Bladeren bron

活体检测功能完善

lideyin 5 jaren geleden
bovenliggende
commit
43820e56d9

+ 1 - 0
examcloud-core-oe-student-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/student/controller/FaceBiopsyController.java

@@ -93,6 +93,7 @@ public class FaceBiopsyController extends ControllerSupport {
         OrgPropertyCacheBean orgProperty = CacheHelper.getOrgProperty(user.getRootOrgId(),
                 Constants.IDENTIFICATION_OF_LIVING_BODY_SCHEME_KEY);
         faceBiopsyBaseInfo.setIdentificationOfLivingBodyScheme(orgProperty.getValue());
+
         Integer faceVerifyMinute = null;
         // 如果是新活体检测方案,则使用新的计算方案计算活检开始时间
         if (NEW_FACE_BIOPSY_SCHEME.equals(orgProperty.getValue())) {

+ 189 - 57
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/FaceBiopsyServiceImpl.java

@@ -60,10 +60,16 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
     @Override
     @Transactional
     public FaceBiopsyInfo getFaceBiopsyInfo(Long rootOrgId, Long examRecordDataId, FaceBiopsyType faceBiopsyType) {
-        //如果在冻结时间外,需要判断是否开启冻结时间外添加人脸活体检测
         boolean isInFreezeTime = calculateIsInFreezeTime(examRecordDataId);
+        /**
+         * case1.冻结时间外的校验逻辑
+         * case1.1.未开启冻结时间外添加人脸活体检测的配置,则抛出异常
+         * case1.2.冻结时间外已完成过1次人脸活体检测,再次调用则抛出异常
+         * case1.3.冻结时间内已经存在2次失败的人脸活体检测记录,冻结时间外,再次调用抛出异常
+         */
         if (!isInFreezeTime) {
-            if (!addFaceVerifyOutFreezeTime(examRecordDataId)) {
+            //case1.1.未开启冻结时间外添加人脸活体检测的配置,则抛出异常
+            if (!isAddFaceVerifyOutFreezeTime(examRecordDataId)) {
                 throw new StatusException("201004", "非冻结时间内不允许人脸活体检测");
             }
         }
@@ -74,6 +80,29 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
             return addFirstFaceBiopsy(rootOrgId, examRecordDataId, faceBiopsyType);
         }
 
+        //case1.2.冻结时间外已完成过1次人脸活体检测,再次调用则抛出异常
+        if (!isInFreezeTime) {
+            List<FaceBiopsyItemEntity> outFreezeTimeCompletedList =
+                    faceBiopsyItemRepo.findByExamRecordDataIdAndCompletedAndInFreezeTime(examRecordDataId,
+                            true, false);
+            if (outFreezeTimeCompletedList != null && outFreezeTimeCompletedList.size() > 0) {
+                throw new StatusException("201005", "冻结时间外不允许进行多次人脸活体检测");
+            }
+
+            //case1.3.冻结时间内已经存在2次失败的人脸活体检测记录,冻结时间外,再次调用抛出异常
+            if (faceBiopsyEntity.getVerifiedTimes() == 2) {
+                List<FaceBiopsyItemEntity> faceBiopsyItemList = faceBiopsyItemRepo.findByFaceBiopsyId(faceBiopsyEntity.getId());
+                FaceBiopsyItemEntity faceBiopsyItem1 = faceBiopsyItemList.get(0);
+                FaceBiopsyItemEntity faceBiopsyItem2 = faceBiopsyItemList.get(1);
+                if (faceBiopsyItem1.getCompleted() && faceBiopsyItem1.getResult() == false &&
+                        faceBiopsyItem2.getCompleted() && faceBiopsyItem2.getResult() == false) {
+                    throw new StatusException("201006", "非法调用,活体检测已结束");
+                }
+            }
+        }
+
+
+
         //如果不是第一次人脸活体检测,判断是否有未检测完的记录,
         FaceBiopsyInfo result = new FaceBiopsyInfo();
         // 未完成的活体检测列表
@@ -92,13 +121,25 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
             return result;
         }
 
-        // 如果不存在未完成的活体检测信息,则判断活检次数是否超过最大活检次数
-        int verifiedTimes = faceBiopsyEntity.getVerifiedTimes();//已活检次数
-        //最大活体检测次数
-        int maxVerifyTimes = PropertyHolder.getInt("oe.faceBiopsy.maxVerifyTimes", 3);
-        //如果超过则提示超过最大活检次数,不允许活检
-        if (verifiedTimes >= maxVerifyTimes) {
-            throw new StatusException("201001", "本次考试已超过最大允许活检次数:" + maxVerifyTimes + ".不允许继续活检");
+        //已活检次数
+        int verifiedTimes = faceBiopsyEntity.getVerifiedTimes();
+        /**
+         * case2.冻结时间内的校验逻辑
+         * case2.1.第一次校验成功,第二次调用则抛出异常(即只有第一次失败才能再调第二次)
+         * case1.2.冻结时间内活检次数不得超过2次(<=2)
+         */
+        if (isInFreezeTime) {
+            if (verifiedTimes == 1) {
+                List<FaceBiopsyItemEntity> faceBiopsyItemList = faceBiopsyItemRepo.findByFaceBiopsyId(faceBiopsyEntity.getId());
+                FaceBiopsyItemEntity faceBiopsyItemEntity = faceBiopsyItemList.get(0);
+                //case2.1.第一次校验成功,第二次调用则抛出异常(即只有第一次失败才能再调第二次)
+                if (faceBiopsyItemEntity.getInFreezeTime() && null != faceBiopsyItemEntity.getResult()
+                        && faceBiopsyItemEntity.getResult()) {
+                    throw new StatusException("201006", "非法请求,冻结时间内无需多次活体检测");
+                }
+            } else {
+                throw new StatusException("201006", "非法请求,冻结时间内最多只能两次活检");
+            }
         }
 
         //没有超过,则追加活检次数
@@ -131,34 +172,90 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
      */
     @Override
     public Integer getFaceBiopsyStartMinute(Long examRecordDataId) {
-
+        //case1.1.第一次调用,返回冻结时间内或冻结时间外下次活检时间
         FaceBiopsyEntity faceBiopsyEntity = faceBiopsyRepo.findByExamRecordDataId(examRecordDataId);
-        //如果是一次活检都没有做过,则认为是第一次,否则需要从库里取次数
+        //如果是一次活检都没有做过,则认为是第一次
         if (faceBiopsyEntity == null) {
-            return calculateFaceBiopsyStartMinute(examRecordDataId, 1);
+            return calculateFaceBiopsyStartMinute(examRecordDataId);
         }
 
-        //判断考试记录id是否有效
-        ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
-                ExamRecordDataEntity.class);
+        boolean isInFreezeTime = calculateIsInFreezeTime(examRecordDataId);
+        /**
+         * case1.冻结时间内的逻辑
+         * case1.1.第一次调用,返回冻结时间内下次活检时间
+         * case1.2.第二次调用,
+         * case1.2.1.如果第一次活检失败,
+         * case1.2.1.1.如果第二次活检未完成,重新计算下次活检时间
+         * case1.2.1.2.如果第二次活检失败,返回null
+         * case1.2.1.3.如果第二次活检成功,返回冻结时间外活检开始的时间
+         * case1.2.2.如果第一次活检成功,
+         * case1.2.2.1.但未开启冻结时间外追加人脸活检的配置,返回null
+         * case1.2.2.2.且开启了冻结时间外追加人脸活检的配置,返回冻结时间外活检开始的时间
+         *
+         */
+        if (isInFreezeTime) {
+            if (faceBiopsyEntity.getVerifiedTimes() <= 2) {
+                List<FaceBiopsyItemEntity> faceBiopsyItemList = faceBiopsyItemRepo.findByFaceBiopsyId(faceBiopsyEntity.getId());
+                FaceBiopsyItemEntity faceBiopsyItemEntity = faceBiopsyItemList.get(0);
+                //第一次活体检测成功,第二次调用时
+                if (faceBiopsyItemEntity.getInFreezeTime() && faceBiopsyItemEntity.getCompleted()
+                        && faceBiopsyItemEntity.getResult()) {
+                    //如果未开启冻结时间外人脸活体检测,则直接返回null
+                    if (!isAddFaceVerifyOutFreezeTime(examRecordDataId)) {
+                        return null;
+                    }
 
-        //如果冻结时间外不添加活体检测
-        if (!addFaceVerifyOutFreezeTime(examRecordData.getExamId(), examRecordData.getOrgId(),
-                examRecordData.getStudentId())) {
-            //如果已活检测次数为>=2次,超过两次,则返回null
-            if (faceBiopsyEntity.getVerifiedTimes() >= 2) {
-                return null;
+                    //如果开启冻结时间外人脸活体检测,则直接返回冻结时间外的活检开始时间
+                    return calculateFaceBiopsyStartMinute(examRecordDataId, true,
+                            FreezeTimeBorder.OUT);
+                }
+
+                //如果进行了两次活检
+                if (faceBiopsyEntity.getVerifiedTimes() == 2) {
+                    faceBiopsyItemEntity = faceBiopsyItemList.get(1);
+                    //如果进行了两次活检,且第二次活检失败,冻结时间内再次调用,返回null
+                    if (faceBiopsyItemEntity.getInFreezeTime() && faceBiopsyItemEntity.getCompleted()
+                            && faceBiopsyItemEntity.getResult() == false) {
+                        return null;
+                    }
+
+                    //如果进行了两次活检,且第二次活检成功,冻结时间内再次调用,返回冻结时间外的值
+                    if (faceBiopsyItemEntity.getInFreezeTime() && faceBiopsyItemEntity.getCompleted()
+                            && faceBiopsyItemEntity.getResult()) {
+                        return calculateFaceBiopsyStartMinute(examRecordDataId, true,
+                                FreezeTimeBorder.OUT);
+                    }
+                }
             }
         }
-        //如果冻结时间外添加新活检
-        else {
-            //如果已最大活检次数>=3次,则返回null
-            if (faceBiopsyEntity.getVerifiedTimes() >= 3) {
+
+        /**
+         * case2.冻结时间外的校验逻辑,
+         * case2.1.冻结时间外已完成过1次人脸活体检测,再次调用则返回null
+         * case2.2.冻结时间内两次活检均失败,冻结时间外再次调用则返回null
+         */
+        if (!isInFreezeTime) {
+            List<FaceBiopsyItemEntity> outFreezeTimeCompletedList =
+                    faceBiopsyItemRepo.findByExamRecordDataIdAndCompletedAndInFreezeTime(examRecordDataId,
+                            true, false);
+            //冻结时间外已完成过1次人脸活体检测,再次调用则返回null
+            if (outFreezeTimeCompletedList != null && outFreezeTimeCompletedList.size() > 0) {
                 return null;
             }
+
+            //冻结时间内两次活检均失败,冻结时间外再次调用则返回null
+            if (faceBiopsyEntity.getVerifiedTimes() == 2) {
+                List<FaceBiopsyItemEntity> faceBiopsyItemList = faceBiopsyItemRepo.findByFaceBiopsyId(faceBiopsyEntity.getId());
+                FaceBiopsyItemEntity faceBiopsyItem1 = faceBiopsyItemList.get(0);
+                FaceBiopsyItemEntity faceBiopsyItem2 = faceBiopsyItemList.get(1);
+                if (faceBiopsyItem1.getCompleted() && faceBiopsyItem1.getResult() == false &&
+                        faceBiopsyItem2.getCompleted() && faceBiopsyItem2.getResult() == false) {
+                    return null;
+                }
+            }
         }
 
-        return calculateFaceBiopsyStartMinute(examRecordDataId, faceBiopsyEntity.getVerifiedTimes());
+        return calculateFaceBiopsyStartMinute(examRecordDataId);
     }
 
     /**
@@ -323,7 +420,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
             //冻结时间内第一次或第二次活检成功,且开启冻结时间外增加一次活检,则需要下次活检,否则不需要
             ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
                     ExamRecordDataEntity.class);
-            return addFaceVerifyOutFreezeTime(examRecordData.getExamId(),
+            return isAddFaceVerifyOutFreezeTime(examRecordData.getExamId(),
                     examRecordData.getOrgId(), examRecordData.getStudentId());
         } else {
             //冻结时间外,无论活检成功或失败,均不可进行下次活检
@@ -532,12 +629,14 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
      * @param faceBiopsyId     人脸活体检测id
      * @return Long 人脸活体检测明细id
      */
-    private Long addFaceBiopsyItemEntity(Long examRecordDataId, FaceBiopsyType faceBiopsyType, Long faceBiopsyId) {
+    private Long addFaceBiopsyItemEntity(Long examRecordDataId, FaceBiopsyType faceBiopsyType,
+                                         Long faceBiopsyId) {
         FaceBiopsyItemEntity faceBiopsyItemEntity = new FaceBiopsyItemEntity();
         faceBiopsyItemEntity.setExamRecordDataId(examRecordDataId);
         faceBiopsyItemEntity.setFaceBiopsyId(faceBiopsyId);
         faceBiopsyItemEntity.setFaceBiopsyType(faceBiopsyType);
         faceBiopsyItemEntity.setCompleted(false);
+        faceBiopsyItemEntity.setInFreezeTime(calculateIsInFreezeTime(examRecordDataId));
         faceBiopsyItemRepo.save(faceBiopsyItemEntity);
         return faceBiopsyItemEntity.getId();
     }
@@ -558,13 +657,24 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         return faceBiopsyEntity.getId();
     }
 
+    /**
+     * @param examRecordDataId 考试记录id
+     * @return
+     */
+    private Integer calculateFaceBiopsyStartMinute(Long examRecordDataId) {
+        return calculateFaceBiopsyStartMinute(examRecordDataId, false, null);
+    }
+
     /**
      * 计算人脸活体检测开始分钟数
      *
-     * @param examRecordDataId 考试记录id
+     * @param examRecordDataId            考试记录id
+     * @param isSpecifiedFreezeTimeBorder 是否指定冻结时间
+     * @param freezeTimeBorder            冻结时间边界
      * @return
      */
-    private Integer calculateFaceBiopsyStartMinute(Long examRecordDataId, Integer verifyTimes) {
+    private Integer calculateFaceBiopsyStartMinute(Long examRecordDataId, Boolean isSpecifiedFreezeTimeBorder,
+                                                   FreezeTimeBorder freezeTimeBorder) {
         ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
                 ExamRecordDataEntity.class);
         Long examId = examRecordData.getExamId();
@@ -586,27 +696,60 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         }
 
         Integer heartbeat = examSessionInfo.getHeartbeat();
-        //如果冻结时间内,使用冻结时间内的计算方式
+        Integer freezeTime = examSessionInfo.getFreezeTime();
+
+        //如果特殊指定了获取冻结时间外或冻结时间内的计算方法,则根据参数分别调用相关方法
+        if (isSpecifiedFreezeTimeBorder) {
+            if (freezeTimeBorder == FreezeTimeBorder.IN) {
+                return generateInFreezeTimeFaceBiopsyStartMinute(examRecordDataId, examId, orgId, studentId, heartbeat);
+            } else {
+                return generateOutFreezeTimeFaceBiopsyStartMinute(examId, orgId, studentId, heartbeat, freezeTime);
+            }
+        }
+
+        //未特殊指定则自动判断,如果冻结时间内,使用冻结时间内的计算方式
         if (calculateIsInFreezeTime(examRecordDataId)) {
-            return generateInFreezeTimeFaceBiopsyStartMinute(examId, orgId, studentId, heartbeat, verifyTimes);
+            return generateInFreezeTimeFaceBiopsyStartMinute(examRecordDataId, examId, orgId, studentId, heartbeat);
         }
         //如果超过冻结时间则使用冻结时间外的计算方式
         else {
-            return generateOutFreezeTimeFaceBiopsyStartMinute(examId, orgId, studentId, heartbeat);
+            return generateOutFreezeTimeFaceBiopsyStartMinute(examId, orgId, studentId, heartbeat, freezeTime);
         }
     }
 
+    /**
+     * 冻结时间边界枚举
+     */
+    enum FreezeTimeBorder {
+        /**
+         * 冻结时间内
+         */
+        IN,
+        /**
+         * 冻结时间外
+         */
+        OUT
+    }
+
     /**
      * 冻结时间内生成人脸活体检测的开始时间
      *
      * @param examId
      * @param orgId
      * @param heartbeat
-     * @param verifyTimes
      * @return
      */
-    private Integer generateInFreezeTimeFaceBiopsyStartMinute(Long examId, Long orgId, Long studentId,
-                                                              Integer heartbeat, Integer verifyTimes) {
+    private Integer generateInFreezeTimeFaceBiopsyStartMinute(Long examRecordDataId, Long examId, Long orgId, Long studentId,
+                                                              Integer heartbeat) {
+        Integer verifyTimes = 0;
+        //第一次调用,返回冻结时间内或冻结时间外下次活检时间
+        FaceBiopsyEntity faceBiopsyEntity = faceBiopsyRepo.findByExamRecordDataId(examRecordDataId);
+        if (faceBiopsyEntity == null) {
+            verifyTimes = 1;
+        } else {
+            verifyTimes = faceBiopsyEntity.getVerifiedTimes();
+        }
+
         //如果没有进行过人脸检测(即第一次活体检测)
         if (verifyTimes == 1) {
             String faceVerifyStartMinuteStr = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
@@ -617,7 +760,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
                     studentId, ExamProperties.FACE_VERIFY_END_MINUTE.name()).getValue();
             Integer faceVerifyEndMinute = Integer.valueOf(faceVerifyEndMinuteStr);
             //	case1.如果考生已使用的考试时间(即心跳时间)还未达到系统设置的活体检测开始时间,
-            //	则实际活体检测时间=random(配置结束时间-配置结束时间)-考试已用时间
+            //	则实际活体检测时间=random(配置结束时间-配置开始时间)-考试已用时间
             if (heartbeat < faceVerifyStartMinute) {
                 return CommonUtil.calculationRandomNumber(faceVerifyStartMinute, faceVerifyEndMinute) - heartbeat;
             }
@@ -646,9 +789,9 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
      * @return
      */
     private Integer generateOutFreezeTimeFaceBiopsyStartMinute(Long examId, Long orgId,
-                                                               Long studentId, Integer heartbeat) {
+                                                               Long studentId, Integer heartbeat, Integer freezeTime) {
         //如果冻结时间外不添加活体检测,则直接返回null
-        if (!addFaceVerifyOutFreezeTime(examId, orgId, studentId)) {
+        if (!isAddFaceVerifyOutFreezeTime(examId, orgId, studentId)) {
             return null;
         }
 
@@ -659,21 +802,10 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
         String strOutFreezeTimeFaceVerifyEndMinute = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
                 studentId, ExamProperties.OUT_FREEZE_TIME_FACE_VERIFY_END_MINUTE.name()).getValue();
         Integer faceVerifyEndMinute = Integer.valueOf(strOutFreezeTimeFaceVerifyEndMinute);
-        //	case1.如果考生已使用的考试时间(即心跳时间)还未达到系统设置的活体检测开始时间,
-        //	则实际活体检测时间=random(配置结束时间-配置结束时间)-考试已用时间
-        if (heartbeat < faceVerifyStartMinute) {
-            return CommonUtil.calculationRandomNumber(faceVerifyStartMinute, faceVerifyEndMinute) - heartbeat;
-        }
-        //	case2如果配置开始时间<考生已使用的考试时间<配置结束时间,
-        //	则实际活体检测时间=random(配置结束时间-考试已用时间)-考试已用时间,如果结果小于1分钟则默认1分钟
-        else if (heartbeat >= faceVerifyStartMinute && heartbeat < faceVerifyEndMinute) {
-            int verifyTime = CommonUtil.calculationRandomNumber(heartbeat, faceVerifyEndMinute) - heartbeat;
-            return verifyTime < 1 ? 1 : verifyTime;
-        }
-        //case3如果考试已用时间>配置结束时间,则默认1分钟后开始人脸检测
-        else {
-            return 1;
-        }
+
+        //活检开始时间 = (冻结时间 + random(配置开始时间,配置结束时间)) -  考试已用时间
+        int result = freezeTime + CommonUtil.calculationRandomNumber(faceVerifyStartMinute, faceVerifyEndMinute) - heartbeat;
+        return result < 1 ? 1 : result;
     }
 
     /**
@@ -683,7 +815,7 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
      * @param orgId
      * @return
      */
-    private boolean addFaceVerifyOutFreezeTime(Long examId, Long orgId, Long studentId) {
+    private boolean isAddFaceVerifyOutFreezeTime(Long examId, Long orgId, Long studentId) {
         String addFaceVerifyOutFreezeTime = ExamCacheTransferHelper.getCachedExamProperty(examId, orgId,
                 studentId, ExamProperties.ADD_FACE_VERIFY_OUT_FREEZE_TIME.name()).getValue();
         return Constants.isTrue.equals(addFaceVerifyOutFreezeTime);
@@ -695,10 +827,10 @@ public class FaceBiopsyServiceImpl implements FaceBiopsyService {
      * @param examRecordDataId
      * @return
      */
-    private boolean addFaceVerifyOutFreezeTime(Long examRecordDataId) {
+    private boolean isAddFaceVerifyOutFreezeTime(Long examRecordDataId) {
         ExamRecordDataEntity examRecordData = GlobalHelper.getEntity(examRecordDataRepo, examRecordDataId,
                 ExamRecordDataEntity.class);
-        return addFaceVerifyOutFreezeTime(examRecordData.getExamId(),
+        return isAddFaceVerifyOutFreezeTime(examRecordData.getExamId(),
                 examRecordData.getOrgId(), examRecordData.getStudentId());
     }