xiatian 5 жил өмнө
parent
commit
50d1659d0a

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

@@ -103,5 +103,17 @@ public class ExamControlController extends ControllerSupport {
             log.debug("1 [END_EXAM]合计 耗时:" + (System.currentTimeMillis() - st) + " ms");
         }
     }
-
+    
+    
+    /**
+     * 考试心跳
+     *
+     * @return 剩余时间
+     */
+    @ApiOperation(value = "考试心跳")
+    @GetMapping("/examHeartbeat")
+    public Long examHeartbeat() {
+        User user = getAccessUser();
+        return examControlService.examHeartbeat(user);
+    }
 }

+ 6 - 0
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamControlService.java

@@ -37,4 +37,10 @@ public interface ExamControlService {
      */
     public CheckExamInProgressInfo checkExamInProgress(Long studentId);
 
+    /**
+     * 考试心跳
+     *
+     * @param
+     */
+    public long examHeartbeat(User user);
 }

+ 4 - 3
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamRecordQuestionsService.java

@@ -1,5 +1,6 @@
 package cn.com.qmth.examcloud.core.oe.student.service;
 
+import cn.com.qmth.examcloud.core.oe.student.base.bean.ExamQuestion;
 import cn.com.qmth.examcloud.core.oe.student.base.bean.ExamRecordQuestions;
 import cn.com.qmth.examcloud.question.commons.core.paper.DefaultPaper;
 
@@ -13,20 +14,20 @@ public interface ExamRecordQuestionsService {
      * 保存
      * @param timeout   秒
      */
-    public void saveExamRecordQuestions(Long examRecordDataId,ExamRecordQuestions questions);
+    public void saveExamQuestion(Long examRecordDataId,Integer order,ExamQuestion questions);
 
     /**
      * 获取
      * @param examRecordDataId
      * @return
      */
-    public ExamRecordQuestions getExamRecordQuestions(Long examRecordDataId);
+    public ExamQuestion getExamQuestion(Long examRecordDataId,Integer order);
 
     /**
      * 删除
      * @param examRecordDataId
      */
-    public void deleteExamRecordQuestions(Long examRecordDataId);
+    public void deleteExamQuestion(Long examRecordDataId,Integer order);
 
     public ExamRecordQuestions createExamRecordQuestions(Long examRecordDataId, DefaultPaper defaultPaper);
 }

+ 42 - 4
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamControlServiceImpl.java

@@ -30,12 +30,13 @@ import cn.com.qmth.examcloud.core.oe.student.base.utils.CommonUtil;
 import cn.com.qmth.examcloud.core.oe.student.base.utils.QuestionTypeUtil;
 import cn.com.qmth.examcloud.core.oe.student.bean.CheckExamInProgressInfo;
 import cn.com.qmth.examcloud.core.oe.student.bean.StartExamInfo;
-import cn.com.qmth.examcloud.core.oe.student.dao.enums.HandInExamType;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamControlService;
+import cn.com.qmth.examcloud.core.oe.student.service.ExamFaceLivenessVerifyService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordDataService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordPaperStructService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordQuestionsService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamingSessionService;
+import cn.com.qmth.examcloud.core.oe.student.service.FaceBiopsyService;
 import cn.com.qmth.examcloud.core.oe.task.api.ExamCaptureCloudService;
 import cn.com.qmth.examcloud.core.oe.task.api.request.SaveExamCaptureSyncCompareResultReq;
 import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
@@ -59,6 +60,7 @@ import cn.com.qmth.examcloud.support.cache.bean.ExtractConfigPaperCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.SysPropertyCacheBean;
 import cn.com.qmth.examcloud.support.enums.ExamRecordStatus;
 import cn.com.qmth.examcloud.support.enums.FaceBiopsyScheme;
+import cn.com.qmth.examcloud.support.enums.HandInExamType;
 import cn.com.qmth.examcloud.support.examing.ExamRecordData;
 import cn.com.qmth.examcloud.support.examing.ExamingSession;
 import cn.com.qmth.examcloud.support.examing.ExamingStatus;
@@ -93,7 +95,13 @@ public class ExamControlServiceImpl implements ExamControlService {
 
     @Autowired
     private ExamCloudService examCloudService;
-
+    
+    @Autowired
+    private FaceBiopsyService faceBiopsyService;
+    
+    @Autowired
+    private ExamFaceLivenessVerifyService examFaceLivenessVerifyService;
+    
     @Transactional
     @Override
     public StartExamInfo startExam(Long examStudentId, User user) {
@@ -554,7 +562,7 @@ public class ExamControlServiceImpl implements ExamControlService {
             // 如果是新活体检测方案,则使用新的计算方案计算活检开始时间
             if (faceBiopsyScheme == FaceBiopsyScheme.NEW) {
                 faceVerifyMinute = faceBiopsyService.calculateFaceBiopsyStartMinute(examingRecord.getId());
-            }else {// 非新活检,默认使用旧的活检计算方式
+            } else {// 非新活检,默认使用旧的活检计算方式
                 faceVerifyMinute = examFaceLivenessVerifyService.getFaceLivenessVerifyMinute(
                         examSessionInfo.getRootOrgId(), examSessionInfo.getOrgId(), examSessionInfo.getExamId(),
                         studentId, examSessionInfo.getExamRecordDataId(), examSessionInfo.getHeartbeat());
@@ -573,7 +581,7 @@ public class ExamControlServiceImpl implements ExamControlService {
         }
 
         // 如果考试时间结束,自动交卷
-        if (examSessionInfo.getExamDuration() <= examSessionInfo.getCost()) {
+        if (examSessionInfo.getExamDuration() <= examSessionInfo.getCost()*1000) {
             delayHandInExamIfLocked(examingRecord.getId());
             return null;
         }
@@ -633,4 +641,34 @@ public class ExamControlServiceImpl implements ExamControlService {
         }
         return ret;
     }
+
+    /**
+     * 考试心跳每分钟调用一次
+     *
+     * @param user
+     *            学生
+     */
+    @Override
+    public long examHeartbeat(User user) {
+        Long studentId = user.getUserId();
+        ExamingSession examSessionInfo = examingSessionService.getExamingSession(studentId);
+        if (examSessionInfo == null || examSessionInfo.getExamingStatus().equals(ExamingStatus.INFORMAL)
+                || examSessionInfo.getCost() >= examSessionInfo.getExamDuration()) {
+            throw new StatusException("8001", "无效的会话,请离开考试");
+        }
+        //考试耗时加60秒
+        examSessionInfo.setCost(examSessionInfo.getCost()+60);
+        long now = System.currentTimeMillis();
+        if (now - examSessionInfo.getActiveTime() >= examSessionInfo.getExamReconnectTime().intValue() * 60 * 1000) {
+            delayHandInExamIfLocked(examSessionInfo.getExamRecordDataId());
+            return 0L;
+        }
+        // 更新考试会话过期时间
+        examingSessionService.saveExamingSession(examSessionInfo.getStudentId(), examSessionInfo);
+        // 在线考生心跳打点
+        ReportsUtil.report(new OnlineExamStudentReport(user.getRootOrgId(), user.getUserId(),
+                examSessionInfo.getExamId(), examSessionInfo.getExamStudentId()));
+        // 返回考试剩余时间 
+        return examSessionInfo.getExamDuration() - (examSessionInfo.getCost() * 1000);
+    }
 }

+ 7 - 7
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamRecordDataServiceImpl.java

@@ -4,7 +4,6 @@ import java.util.Date;
 
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -17,6 +16,7 @@ import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
 import cn.com.qmth.examcloud.support.enums.ExamRecordStatus;
 import cn.com.qmth.examcloud.support.examing.ExamRecordData;
 import cn.com.qmth.examcloud.support.examing.ExamingSession;
+import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 
 /**
@@ -31,9 +31,6 @@ public class ExamRecordDataServiceImpl implements ExamRecordDataService {
     @Autowired
     private RedisClient redisClient;
 
-    @Value("${exam_record_data_key_prefix}")
-    private String examRecordDataKeyPrefix;
-
     @Autowired
     private ExamRecordDataRepo examRecordDataRepo;
 
@@ -73,17 +70,20 @@ public class ExamRecordDataServiceImpl implements ExamRecordDataService {
 
     @Override
     public void saveExamRecordDataCache(Long examRecordDataId, ExamRecordData data) {
-        redisClient.set(examRecordDataKeyPrefix + examRecordDataId, data, -1);
+        String key = RedisKeyHelper.getBuilder().examRecordDataKey(examRecordDataId);
+        redisClient.set(key + examRecordDataId, data, -1);
     }
 
     @Override
     public ExamRecordData getExamRecordDataCache(Long examRecordDataId) {
-        return redisClient.get(examRecordDataKeyPrefix + examRecordDataId, ExamRecordData.class);
+        String key = RedisKeyHelper.getBuilder().examRecordDataKey(examRecordDataId);
+        return redisClient.get(key + examRecordDataId, ExamRecordData.class);
     }
 
     @Override
     public void deleteExamRecordDataCache(Long examRecordDataId) {
-        redisClient.delete(examRecordDataKeyPrefix + examRecordDataId);
+        String key = RedisKeyHelper.getBuilder().examRecordDataKey(examRecordDataId);
+        redisClient.delete(key + examRecordDataId);
     }
 
 }

+ 7 - 6
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamRecordPaperStructServiceImpl.java

@@ -1,11 +1,11 @@
 package cn.com.qmth.examcloud.core.oe.student.service.impl;
 
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordPaperStructService;
 import cn.com.qmth.examcloud.question.commons.core.paper.DefaultPaper;
+import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 
 @Service("examRecordPaperStructService")
@@ -14,22 +14,23 @@ public class ExamRecordPaperStructServiceImpl implements ExamRecordPaperStructSe
     @Autowired
     private RedisClient redisClient;
 
-    @Value("${exam_paper_struct_key_prefix}")
-    private String examPaperStructKeyPrefix;
 
     @Override
     public void saveExamRecordPaperStruct(Long examRecordDataId, DefaultPaper paper) {
-        redisClient.set(examPaperStructKeyPrefix + examRecordDataId, paper,-1);
+        String key = RedisKeyHelper.getBuilder().studentPaperKey(examRecordDataId);
+        redisClient.set(key + examRecordDataId, paper,-1);
     }
 
     @Override
     public DefaultPaper getExamRecordPaperStruct(Long examRecordDataId) {
-        return redisClient.get(examPaperStructKeyPrefix + examRecordDataId, DefaultPaper.class);
+        String key = RedisKeyHelper.getBuilder().studentPaperKey(examRecordDataId);
+        return redisClient.get(key + examRecordDataId, DefaultPaper.class);
     }
 
     @Override
     public void deleteExamRecordPaperStruct(Long examRecordDataId) {
-        redisClient.delete(examPaperStructKeyPrefix + examRecordDataId);
+        String key = RedisKeyHelper.getBuilder().studentPaperKey(examRecordDataId);
+        redisClient.delete(key + examRecordDataId);
     }
 
 }

+ 13 - 11
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamRecordQuestionsServiceImpl.java

@@ -5,7 +5,6 @@ import java.util.Date;
 import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import cn.com.qmth.examcloud.core.oe.student.base.bean.ExamQuestion;
@@ -15,6 +14,7 @@ import cn.com.qmth.examcloud.question.commons.core.paper.DefaultPaper;
 import cn.com.qmth.examcloud.question.commons.core.paper.DefaultQuestionGroup;
 import cn.com.qmth.examcloud.question.commons.core.paper.DefaultQuestionStructureWrapper;
 import cn.com.qmth.examcloud.question.commons.core.paper.DefaultQuestionUnitWrapper;
+import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 
 @Service("examRecordQuestionsService")
@@ -23,22 +23,22 @@ public class ExamRecordQuestionsServiceImpl implements ExamRecordQuestionsServic
     @Autowired
     private RedisClient redisClient;
 
-    @Value("${exam_record_questions_key_prefix}")
-    private String examRecordQuestionsKeyPrefix;
-
     @Override
-    public void saveExamRecordQuestions(Long examRecordDataId, ExamRecordQuestions questions) {
-        redisClient.set(examRecordQuestionsKeyPrefix + examRecordDataId, questions,-1);
+    public void saveExamQuestion(Long examRecordDataId,Integer order, ExamQuestion question) {
+        String key = RedisKeyHelper.getBuilder().studentAnswerKey(examRecordDataId, order);
+        redisClient.set(key + examRecordDataId, question,-1);
     }
 
     @Override
-    public ExamRecordQuestions getExamRecordQuestions(Long examRecordDataId) {
-        return redisClient.get(examRecordQuestionsKeyPrefix + examRecordDataId, ExamRecordQuestions.class);
+    public ExamQuestion getExamQuestion(Long examRecordDataId,Integer order) {
+        String key = RedisKeyHelper.getBuilder().studentAnswerKey(examRecordDataId, order);
+        return redisClient.get(key + examRecordDataId, ExamQuestion.class);
     }
 
     @Override
-    public void deleteExamRecordQuestions(Long examRecordDataId) {
-        redisClient.delete(examRecordQuestionsKeyPrefix + examRecordDataId);
+    public void deleteExamQuestion(Long examRecordDataId,Integer order) {
+        String key = RedisKeyHelper.getBuilder().studentAnswerKey(examRecordDataId, order);
+        redisClient.delete(key + examRecordDataId);
     }
 
     @Override
@@ -75,7 +75,9 @@ public class ExamRecordQuestionsServiceImpl implements ExamRecordQuestionsServic
         examRecordQuestions.setExamQuestions(examQuestionEntityList);
         examRecordQuestions.setExamRecordDataId(examRecordDataId);
         examRecordQuestions.setCreationTime(new Date());
-        saveExamRecordQuestions(examRecordDataId, examRecordQuestions);
+        for(ExamQuestion eq:examRecordQuestions.getExamQuestions()) {
+            saveExamQuestion(eq.getExamRecordDataId(), eq.getOrder(), eq);
+        }
         return examRecordQuestions;
     }
 

+ 7 - 7
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamingSessionServiceImpl.java

@@ -1,11 +1,11 @@
 package cn.com.qmth.examcloud.core.oe.student.service.impl;
 
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import cn.com.qmth.examcloud.core.oe.student.service.ExamingSessionService;
 import cn.com.qmth.examcloud.support.examing.ExamingSession;
+import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 
 /**
@@ -19,22 +19,22 @@ public class ExamingSessionServiceImpl implements ExamingSessionService {
 
     @Autowired
     private RedisClient redisClient;
-    
-    @Value("${exam_redis_key_prefix}")
-    private String examRedisKeyPrefix;
 
     @Override
     public void saveExamingSession(Long studentId, ExamingSession examingSession) {
-        redisClient.set(examRedisKeyPrefix+studentId,examingSession,-1);
+        String key = RedisKeyHelper.getBuilder().examingSessionKey(studentId);
+        redisClient.set(key,examingSession,-1);
     }
 
     @Override
     public ExamingSession getExamingSession(Long studentId) {
-        return redisClient.get(examRedisKeyPrefix+studentId,ExamingSession.class);
+        String key = RedisKeyHelper.getBuilder().examingSessionKey(studentId);
+        return redisClient.get(key+studentId,ExamingSession.class);
     }
 
     @Override
     public void deleteExamingSession(Long studentId) {
-        redisClient.delete(examRedisKeyPrefix+studentId);
+        String key = RedisKeyHelper.getBuilder().examingSessionKey(studentId);
+        redisClient.delete(key+studentId);
     }
 }