|
@@ -15,6 +15,7 @@ import cn.com.qmth.examcloud.core.oe.common.repository.FaceBiopsyItemRepo;
|
|
|
import cn.com.qmth.examcloud.core.oe.common.repository.FaceBiopsyItemStepRepo;
|
|
|
import cn.com.qmth.examcloud.core.oe.common.repository.FaceBiopsyRepo;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.bean.*;
|
|
|
+import cn.com.qmth.examcloud.core.oe.student.service.ExamControlService;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.service.ExamSessionInfoService;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.service.FaceBiopsyService;
|
|
|
import cn.com.qmth.examcloud.support.cache.CacheHelper;
|
|
@@ -47,6 +48,8 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
|
|
|
private ExamRecordDataRepo examRecordDataRepo;
|
|
|
@Autowired
|
|
|
private ExamSessionInfoService examSessionInfoService;
|
|
|
+ @Autowired
|
|
|
+ private ExamControlService examControlService;
|
|
|
|
|
|
@Override
|
|
|
public FaceBiopsyInfo getFaceBiopsyInfo(Long rootOrgId, Long examRecordDataId, FaceBiopsyType faceBiopsyType) {
|
|
@@ -91,11 +94,176 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
|
|
|
|
|
|
@Override
|
|
|
public SaveFaceBiopsyResultResp saveFaceBiopsyResult(SaveFaceBiopsyResultReq req) {
|
|
|
- List<FaceBiopsyStepInfo> verifySteps = req.getVerifySteps();
|
|
|
- for (int i=0;i<verifySteps.size();i++){
|
|
|
+ //构建业务实体
|
|
|
+ SaveFaceBiopsyResultResp resp = buildSaveFaceBiopsyResultResp(req.getExamRecordDataId(), req.getVerifySteps());
|
|
|
+
|
|
|
+ //更新人脸活体检测结果至数据库
|
|
|
+ updateFaceBiopsyResult(req.getExamRecordDataId(), req.getFaceBiopsyItemId(), req.getVerifySteps(),
|
|
|
+ resp.getVerifyResult(), resp.getErrorMessage());
|
|
|
+ return resp;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建保存人脸检测结果的业务实体
|
|
|
+ *
|
|
|
+ * @param examRecordDataId
|
|
|
+ * @param verifySteps
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private SaveFaceBiopsyResultResp buildSaveFaceBiopsyResultResp(Long examRecordDataId,
|
|
|
+ List<FaceBiopsyStepInfo> verifySteps) {
|
|
|
+ //本次检测的最终结果是否成功(检测步骤中只要有一项检测失败,则认为检测失败)
|
|
|
+ boolean finalIsSuccess = true;
|
|
|
+ String errorMsg = null;
|
|
|
+ /**
|
|
|
+ * 是否结束考试
|
|
|
+ * case1:人脸比对失败(即活检第1步,action==FACE_COMPARE)时,结束考试
|
|
|
+ * case2:冻结时间内,第2次人脸活检整体失败,结束考试
|
|
|
+ * case3:冻结时间外,人脸活检失败,结束考试
|
|
|
+ */
|
|
|
+ boolean isEndExam = false;
|
|
|
+ //检测次数
|
|
|
+ int verifyTimes = getVerifyTimes(examRecordDataId);
|
|
|
+ //是否在冻结时间内
|
|
|
+ boolean isInFreezeTime = calculateIsInFreezeTime(examRecordDataId);
|
|
|
+
|
|
|
+ for (FaceBiopsyStepInfo stepInfo : verifySteps) {
|
|
|
+ if (!stepInfo.getResult()) {
|
|
|
+ errorMsg = stepInfo.getErrorMsg();
|
|
|
+ }
|
|
|
+
|
|
|
+ //整个检测步骤中只要有一次失败,则认为整个活检失败
|
|
|
+ if (!stepInfo.getResult()) {
|
|
|
+ finalIsSuccess = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (stepInfo.getAction()) {
|
|
|
+ case FACE_COMPARE:
|
|
|
+ //如果第一步检测(即人脸比对)失败,则结束考试
|
|
|
+ if (!stepInfo.getResult()) {
|
|
|
+ isEndExam = true;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case HAPPY:
|
|
|
+ //如果此前步骤已判断为需要结束考试则不作任何处理
|
|
|
+ if (!isEndExam) {
|
|
|
+ if (isInFreezeTime) {
|
|
|
+ //如果冻结时间内第2次检测失败,则需要结束考试
|
|
|
+ if (verifyTimes > 1 && !stepInfo.getResult()) {
|
|
|
+ isEndExam = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //冻结时间外检测失败,直接结束考试
|
|
|
+ if (!stepInfo.getResult()) {
|
|
|
+ isEndExam = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ //构建业务实体
|
|
|
+ SaveFaceBiopsyResultResp resp = new SaveFaceBiopsyResultResp();
|
|
|
+ resp.setEndExam(isEndExam);
|
|
|
+ resp.setNeedNextVerify(calculateNeedNextVerify(
|
|
|
+ isEndExam, isInFreezeTime, finalIsSuccess, verifyTimes, examRecordDataId));
|
|
|
+ resp.setVerifyResult(finalIsSuccess);
|
|
|
+ resp.setErrorMessage(errorMsg);
|
|
|
+ return resp;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新人脸活体检测结果至数据库
|
|
|
+ *
|
|
|
+ * @param examRecordDataId
|
|
|
+ * @param faceBiopsyItemId
|
|
|
+ * @param verifySteps
|
|
|
+ * @param finalIsSuccess
|
|
|
+ * @param errorMsg
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public void updateFaceBiopsyResult(Long examRecordDataId, Long faceBiopsyItemId, List<FaceBiopsyStepInfo> verifySteps,
|
|
|
+ boolean finalIsSuccess, String errorMsg) {
|
|
|
+ List<FaceBiopsyItemStepEntity> faceBiopsyItemStepEntityList =
|
|
|
+ faceBiopsyItemStepRepo.findByFaceBiopsyItemId(faceBiopsyItemId);
|
|
|
+ for (FaceBiopsyStepInfo stepInfo : verifySteps) {
|
|
|
+ //循环更新新活体检测每步的执行结果
|
|
|
+ FaceBiopsyItemStepEntity faceBiopsyItemStepEntity = faceBiopsyItemStepEntityList.stream().
|
|
|
+ filter(p -> p.getId().equals(stepInfo.getStepId())).findFirst().get();
|
|
|
+ faceBiopsyItemStepEntity.setErrorMsg(stepInfo.getErrorMsg());
|
|
|
+ faceBiopsyItemStepEntity.setResourceType(stepInfo.getResourceType());
|
|
|
+ faceBiopsyItemStepEntity.setResourceRelativePath(getRelativePath(stepInfo.getResourceUrl()));
|
|
|
+ faceBiopsyItemStepEntity.setExt1(stepInfo.getResultJson());//存储动作执行结果
|
|
|
+ faceBiopsyItemStepEntity.setResult(stepInfo.getResult());
|
|
|
+ }
|
|
|
+ //批量更新活检步骤执行结果
|
|
|
+ faceBiopsyItemStepRepo.saveAll(faceBiopsyItemStepEntityList);
|
|
|
+ //更新人脸活体检测最终结果
|
|
|
+ faceBiopsyItemRepo.updateFaceBiopsyItemResult(faceBiopsyItemId, finalIsSuccess, errorMsg, true);
|
|
|
+ faceBiopsyRepo.updateFaceBiopsyResult(examRecordDataId, finalIsSuccess, errorMsg);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算是否需要下次活检
|
|
|
+ *
|
|
|
+ * @param isEndExam
|
|
|
+ * @param isInFreezeTime
|
|
|
+ * @param finalIsSuccess
|
|
|
+ * @param verifyTimes
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean calculateNeedNextVerify(boolean isEndExam, boolean isInFreezeTime, boolean finalIsSuccess,
|
|
|
+ int verifyTimes, Long examRecordDataId) {
|
|
|
+ //考试已结束,不需要继续下次活检
|
|
|
+ if (isEndExam) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ //如果考试未结束的情况
|
|
|
+ if (isInFreezeTime) {
|
|
|
+ if (verifyTimes == 1) {
|
|
|
+ //冻结时间内第一次活检失败,则需要下次活检
|
|
|
+ if (!finalIsSuccess) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //冻结时间内非第一次活检失败,则不需要下次活检
|
|
|
+ if (!finalIsSuccess) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ //冻结时间内第一次或第二次活检成功,且开启冻结时间外增加一次活检,则需要下次活检,否则不需要
|
|
|
+ ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
|
|
|
+ ExamRecordDataEntity.class);
|
|
|
+ return addFaceVerifyOutFreezeTime(examRecordData.getExamId(), examRecordData.getOrgId());
|
|
|
+ } else {
|
|
|
+ //冻结时间外,无论活检成功或失败,均不可进行下次活检
|
|
|
+ return false;
|
|
|
}
|
|
|
- return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取活体检测次数
|
|
|
+ *
|
|
|
+ * @param examRecordDataId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private int getVerifyTimes(Long examRecordDataId) {
|
|
|
+ FaceBiopsyEntity faceBiopsy = faceBiopsyRepo.findByExamRecordDataId(examRecordDataId);
|
|
|
+ return faceBiopsy.getVerifiedTimes();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据完整路径获取相对路径
|
|
|
+ *
|
|
|
+ * @param resourceUrl
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getRelativePath(String resourceUrl) {
|
|
|
+ //TODO 待完善代码
|
|
|
+ return resourceUrl;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -273,7 +441,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
|
|
|
|
|
|
Integer heartbeat = examSessionInfo.getHeartbeat();
|
|
|
//如果冻结时间内,使用冻结时间内的计算方式
|
|
|
- if (heartbeat < examSessionInfo.getFreezeTime()) {
|
|
|
+ if (calculateIsInFreezeTime(examRecordDataId)) {
|
|
|
return generateInFreezeTimeFaceBiopsyStartMinute(examId, orgId, heartbeat, verifyTimes);
|
|
|
}
|
|
|
//如果超过冻结时间则使用冻结时间外的计算方式
|
|
@@ -332,11 +500,8 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
|
|
|
* @return
|
|
|
*/
|
|
|
private Integer generateOutFreezeTimeFaceBiopsyStartMinute(Long examId, Long orgId, Integer heartbeat) {
|
|
|
- //冻结时间外是否添加活体检测
|
|
|
- String addFaceVerifyOutFreezeTime = CacheHelper.getExamOrgProperty(examId, orgId,
|
|
|
- ExamProperties.ADD_FACE_VERIFY_OUT_FREEZE_TIME.name()).getValue();
|
|
|
//如果冻结时间外不添加活体检测,则直接返回null
|
|
|
- if (!Constants.isTrue.equals(addFaceVerifyOutFreezeTime)) {
|
|
|
+ if (!addFaceVerifyOutFreezeTime(examId, orgId)) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
@@ -363,4 +528,29 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ private boolean addFaceVerifyOutFreezeTime(Long examId, Long orgId) {
|
|
|
+ String addFaceVerifyOutFreezeTime = CacheHelper.getExamOrgProperty(examId, orgId,
|
|
|
+ ExamProperties.ADD_FACE_VERIFY_OUT_FREEZE_TIME.name()).getValue();
|
|
|
+ return Constants.isTrue.equals(addFaceVerifyOutFreezeTime);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 当前考试是否在冻结时间内
|
|
|
+ *
|
|
|
+ * @param examRecordDataId 考试记录id
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean calculateIsInFreezeTime(Long examRecordDataId) {
|
|
|
+ ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
|
|
|
+ ExamRecordDataEntity.class);
|
|
|
+
|
|
|
+ ExamSessionInfo examSessionInfo = examSessionInfoService.getExamSessionInfo(examRecordData.getStudentId());
|
|
|
+ if (examSessionInfo == null) {
|
|
|
+ throw new StatusException("201002", "考试会话已过期");
|
|
|
+ }
|
|
|
+ Long usedMilliseconds = examControlService.calculateExamUsedMilliseconds(examSessionInfo);
|
|
|
+
|
|
|
+ return usedMilliseconds < examSessionInfo.getFreezeTime() * 60 * 1000;
|
|
|
+ }
|
|
|
}
|