소스 검색

断点续考

xiatian 5 년 전
부모
커밋
aae601306f
12개의 변경된 파일332개의 추가작업 그리고 37개의 파일을 삭제
  1. 34 5
      examcloud-core-oe-student-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/student/api/controller/ExamControlController.java
  2. 89 0
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/bean/CheckExamInProgressInfo.java
  3. 36 0
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/bean/ExamProcessResultInfo.java
  4. 8 0
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamControlService.java
  5. 3 3
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamRecordDataService.java
  6. 1 1
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamRecordQuestionsService.java
  7. 1 1
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamingSessionService.java
  8. 149 16
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamControlServiceImpl.java
  9. 5 5
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamRecordDataServiceImpl.java
  10. 1 1
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamRecordPaperStructServiceImpl.java
  11. 3 3
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamRecordQuestionsServiceImpl.java
  12. 2 2
      examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamingSessionServiceImpl.java

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

@@ -1,10 +1,5 @@
 package cn.com.qmth.examcloud.core.oe.student.api.controller;
 
-import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.core.oe.student.base.utils.Check;
-import cn.com.qmth.examcloud.core.oe.student.dao.enums.HandInExamType;
-import cn.com.qmth.examcloud.support.Constants;
-import cn.com.qmth.examcloud.support.examing.ExamingSession;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -12,8 +7,15 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.core.oe.student.base.utils.Check;
+import cn.com.qmth.examcloud.core.oe.student.bean.CheckExamInProgressInfo;
+import cn.com.qmth.examcloud.core.oe.student.bean.ExamProcessResultInfo;
 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.support.Constants;
+import cn.com.qmth.examcloud.support.examing.ExamingSession;
 import cn.com.qmth.examcloud.web.helpers.SequenceLockHelper;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import io.swagger.annotations.Api;
@@ -44,6 +46,33 @@ public class ExamControlController extends ControllerSupport {
         return startExamInfo;
     }
 
+    /**
+     * 断点续考:检查正在进行中的考试
+     */
+    @ApiOperation(value = "断点续考:检查正在进行中的考试")
+    @GetMapping("/checkExamInProgress")
+    public ExamProcessResultInfo checkExamInProgress() {
+        User user = getAccessUser();
+        String sequenceLockKey = Constants.START_EXAM_LOCK_PREFIX + user.getUserId();
+        // 系统在请求结束后会,自动释放锁,无需手动解锁
+        SequenceLockHelper.getLock(sequenceLockKey);
+        ExamProcessResultInfo res = new ExamProcessResultInfo();
+        try {
+            CheckExamInProgressInfo info = examControlService.checkExamInProgress(user.getUserId());
+            res.setCode(Constants.COMMON_SUCCESS_CODE);
+            res.setData(info);
+            return res;
+        } catch (StatusException e) {
+            if (e.getCode().equals(Constants.EXAM_RECORD_NOT_END_STATUS_CODE)) {
+                res.setCode(Constants.PROCESSING_EXAM_RECORD_CODE);
+                return res;
+            }
+            throw e;
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+
     /**
      * 结束考试:交卷..
      */

+ 89 - 0
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/bean/CheckExamInProgressInfo.java

@@ -0,0 +1,89 @@
+package cn.com.qmth.examcloud.core.oe.student.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+public class CheckExamInProgressInfo implements JsonSerializable{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 5411680698118472710L;
+
+	//已断点次数
+	private Integer interruptNum;
+	
+	//最大断点次数限制
+	private Integer maxInterruptNum;
+	
+	//是否达到最大断点限制
+	private Boolean isExceed;
+	
+	private Long examRecordDataId;
+	
+	private Long examId;
+	/**
+	 * 使用时间
+	 */
+	private Long usedTime;
+	/**
+	 * 活体检测启动分钟数
+	 */
+	private Integer faceVerifyMinute;
+
+	public Long getExamRecordDataId() {
+		return examRecordDataId;
+	}
+
+	public void setExamRecordDataId(Long examRecordDataId) {
+		this.examRecordDataId = examRecordDataId;
+	}
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public Long getUsedTime() {
+		return usedTime;
+	}
+
+	public void setUsedTime(Long usedTime) {
+		this.usedTime = usedTime;
+	}
+
+	public Integer getFaceVerifyMinute() {
+		return faceVerifyMinute;
+	}
+
+	public void setFaceVerifyMinute(Integer faceVerifyMinute) {
+		this.faceVerifyMinute = faceVerifyMinute;
+	}
+
+	public Integer getInterruptNum() {
+		return interruptNum;
+	}
+
+	public void setInterruptNum(Integer interruptNum) {
+		this.interruptNum = interruptNum;
+	}
+
+	public Integer getMaxInterruptNum() {
+		return maxInterruptNum;
+	}
+
+	public void setMaxInterruptNum(Integer maxInterruptNum) {
+		this.maxInterruptNum = maxInterruptNum;
+	}
+
+	public Boolean getIsExceed() {
+		return isExceed;
+	}
+
+	public void setIsExceed(Boolean isExceed) {
+		this.isExceed = isExceed;
+	}
+
+}

+ 36 - 0
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/bean/ExamProcessResultInfo.java

@@ -0,0 +1,36 @@
+package cn.com.qmth.examcloud.core.oe.student.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+/**
+ * @Description 考试处理结果
+ * @Author lideyin
+ * @Date 2019/8/9 19:49
+ * @Version 1.0
+ */
+public class ExamProcessResultInfo implements JsonSerializable {
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 759446787600457180L;
+
+    private String code;
+
+    private Object data;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+}

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

@@ -2,6 +2,7 @@ package cn.com.qmth.examcloud.core.oe.student.service;
 
 
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
+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;
 
@@ -28,5 +29,12 @@ public interface ExamControlService {
      * @param handInExamType   交卷类型
      */
     void handInExam(Long examRecordDataId, HandInExamType handInExamType);
+    
+    /**
+     * 断点续考:检查正在进行中的考试
+     *
+     * @param studentId
+     */
+    public CheckExamInProgressInfo checkExamInProgress(Long studentId);
 
 }

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

@@ -33,19 +33,19 @@ public interface ExamRecordDataService {
      * 保存
      * @param timeout   秒
      */
-    public void saveExamRecordDataBean(Long examRecordDataId,ExamRecordData data,int timeout);
+    public void saveExamRecordDataCache(Long examRecordDataId,ExamRecordData data);
 
     /**
      * 获取
      * @param examRecordDataId
      * @return
      */
-    public ExamRecordData getExamRecordDataBean(Long examRecordDataId);
+    public ExamRecordData getExamRecordDataCache(Long examRecordDataId);
 
     /**
      * 删除
      * @param examRecordDataId
      */
-    public void deleteExamRecordDataBean(Long examRecordDataId);
+    public void deleteExamRecordDataCache(Long examRecordDataId);
 
 }

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

@@ -13,7 +13,7 @@ public interface ExamRecordQuestionsService {
      * 保存
      * @param timeout   秒
      */
-    public void saveExamRecordQuestions(Long examRecordDataId,ExamRecordQuestions questions,int timeout);
+    public void saveExamRecordQuestions(Long examRecordDataId,ExamRecordQuestions questions);
 
     /**
      * 获取

+ 1 - 1
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamingSessionService.java

@@ -12,7 +12,7 @@ public interface ExamingSessionService {
      * 保存
      * @param timeout   秒
      */
-    public void saveExamingSession(Long studentId,ExamingSession examingSession,int timeout);
+    public void saveExamingSession(Long studentId,ExamingSession examingSession);
 
     /**
      * 获取

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

@@ -9,6 +9,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Random;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -21,11 +22,13 @@ import org.springframework.transaction.annotation.Transactional;
 import cn.com.qmth.examcloud.api.commons.enums.ExamSpecialSettingsType;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.Util;
 import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
 import cn.com.qmth.examcloud.core.oe.student.base.enums.ExamProperties;
 import cn.com.qmth.examcloud.core.oe.student.base.helper.ExamCacheTransferHelper;
 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;
@@ -35,7 +38,10 @@ 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.task.api.ExamCaptureCloudService;
 import cn.com.qmth.examcloud.core.oe.task.api.request.SaveExamCaptureSyncCompareResultReq;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
 import cn.com.qmth.examcloud.examwork.api.bean.ExamBean;
+import cn.com.qmth.examcloud.examwork.api.request.GetExamPropertyReq;
+import cn.com.qmth.examcloud.examwork.api.response.GetExamPropertyResp;
 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;
@@ -51,10 +57,13 @@ import cn.com.qmth.examcloud.support.cache.bean.ExtractConfigCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.ExtractConfigDetailCacheBean;
 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.examing.ExamRecordData;
 import cn.com.qmth.examcloud.support.examing.ExamingSession;
 import cn.com.qmth.examcloud.support.examing.ExamingStatus;
 import cn.com.qmth.examcloud.support.helper.FaceBiopsyHelper;
+import cn.com.qmth.examcloud.web.exception.SequenceLockException;
 
 /**
  * @author chenken
@@ -78,11 +87,13 @@ public class ExamControlServiceImpl implements ExamControlService {
 
     @Autowired
     private ExamRecordQuestionsService examRecordQuestionsService;
-    
+
     @Autowired
     private ExamCaptureCloudService examCaptureCloudService;
-    
-    
+
+    @Autowired
+    private ExamCloudService examCloudService;
+
     @Transactional
     @Override
     public StartExamInfo startExam(Long examStudentId, User user) {
@@ -143,8 +154,8 @@ public class ExamControlServiceImpl implements ExamControlService {
 
         // 生成考试记录
         startTime = System.currentTimeMillis();
-        ExamRecordData examRecordData = examRecordDataService.createExamRecordData(examingSession, examBean,
-                courseBean, paperId);
+        ExamRecordData examRecordData = examRecordDataService.createExamRecordData(examingSession, examBean, courseBean,
+                paperId);
 
         // 如果开启人脸比对,将同步人脸比对结果存储到抓后结果表中
         Long rootOrgId = examRecordData.getRootOrgId();
@@ -211,8 +222,10 @@ public class ExamControlServiceImpl implements ExamControlService {
     /**
      * 交卷
      *
-     * @param examRecordDataId 考试记录id
-     * @param handInExamType   交卷类型
+     * @param examRecordDataId
+     *            考试记录id
+     * @param handInExamType
+     *            交卷类型
      */
     @Override
     public void handInExam(Long examRecordDataId, HandInExamType handInExamType) {
@@ -447,8 +460,7 @@ public class ExamControlServiceImpl implements ExamControlService {
                     .getCachedExamProperty(examId, studentId, ExamProperties.FACE_VERIFY_START_MINUTE.name())
                     .getValue();
             if (CommonUtil.isBlank(startMinuteStr)) {
-                throw new StatusException("5001",
-                        ExamProperties.FACE_VERIFY_START_MINUTE.getDesc() + "未设置");
+                throw new StatusException("5001", ExamProperties.FACE_VERIFY_START_MINUTE.getDesc() + "未设置");
             }
             Integer faceVerifyStartMinute = Integer.valueOf(startMinuteStr);
 
@@ -456,8 +468,7 @@ public class ExamControlServiceImpl implements ExamControlService {
             String endMinuteStr = ExamCacheTransferHelper
                     .getCachedExamProperty(examId, studentId, ExamProperties.FACE_VERIFY_END_MINUTE.name()).getValue();
             if (CommonUtil.isBlank(endMinuteStr)) {
-                throw new StatusException("5002",
-                        ExamProperties.FACE_VERIFY_END_MINUTE.getDesc() + "未设置");
+                throw new StatusException("5002", ExamProperties.FACE_VERIFY_END_MINUTE.getDesc() + "未设置");
             }
             Integer faceVerifyEndMinute = Integer.valueOf(endMinuteStr);
             return CommonUtil.calculationRandomNumber(faceVerifyStartMinute, faceVerifyEndMinute);
@@ -482,8 +493,7 @@ public class ExamControlServiceImpl implements ExamControlService {
                 examSessionInfo.getStudentId(), ExamProperties.EXAM_RECONNECT_TIME.name()).getValue();
         log.debug("11.2 断点时间:" + examReconnectTimeStr);
         if (CommonUtil.isBlank(examReconnectTimeStr)) {
-            throw new StatusException("6001",
-                    ExamProperties.EXAM_RECONNECT_TIME.getDesc() + "未设置");
+            throw new StatusException("6001", ExamProperties.EXAM_RECONNECT_TIME.getDesc() + "未设置");
         }
         examSessionInfo.setExamReconnectTime(Integer.valueOf(examReconnectTimeStr));
         // FREEZE_TIME:冻结时间
@@ -491,13 +501,136 @@ public class ExamControlServiceImpl implements ExamControlService {
                 examSessionInfo.getStudentId(), ExamProperties.FREEZE_TIME.name()).getValue();
         log.debug("11.3 冻结时间:" + freezeTimeStr);
         if (CommonUtil.isBlank(freezeTimeStr)) {
-            throw new StatusException("6002",
-                    ExamProperties.FREEZE_TIME.getDesc() + "未设置");
+            throw new StatusException("6002", ExamProperties.FREEZE_TIME.getDesc() + "未设置");
         }
         examSessionInfo.setFreezeTime(Integer.valueOf(freezeTimeStr));
         examSessionInfo.setExamingStatus(ExamingStatus.FORMAL);
         log.debug("11.4 开始保存考试会话...studentId=" + examSessionInfo.getStudentId());
-        examingSessionService.saveExamingSession(examSessionInfo.getStudentId(), examSessionInfo,-1);
+        examingSessionService.saveExamingSession(examSessionInfo.getStudentId(), examSessionInfo);
         log.debug("11.5 保存考试会话结束 ");
     }
+
+    @Override
+    public CheckExamInProgressInfo checkExamInProgress(Long studentId) {
+        ExamingSession examSessionInfo = examingSessionService.getExamingSession(studentId);
+        if (examSessionInfo == null || ExamingStatus.INFORMAL.equals(examSessionInfo.getExamingStatus())) {
+            return null;
+        }
+        // 检查考试会话是否存在,或者是否失效,如果没有失效,则返回考试中的考试记录实体,否则直接返回null
+        ExamRecordData examingRecord = checkExamSession(examSessionInfo, studentId);
+        if (examingRecord == null) {
+            return null;
+        } else {
+            Integer maxInterruptNum = getMaxInterruptNum(examSessionInfo.getExamId(), examSessionInfo.getRootOrgId(),
+                    examSessionInfo.getOrgId());
+            CheckExamInProgressInfo checkExamInProgressInfo = new CheckExamInProgressInfo();
+
+            if ((examingRecord.getIsExceed() == null || !examingRecord.getIsExceed())
+                    && examingRecord.getContinuedCount().intValue() < maxInterruptNum.intValue()) {// 未达到最大断点次数,可继续断点一次
+                // 断点续考次数自增
+                int continutedCount = examingRecord.getContinuedCount() == null ? 0
+                        : examingRecord.getContinuedCount().intValue();
+                examingRecord.setContinuedCount(continutedCount + 1);
+                examingRecord.setIsContinued(true);
+                examingRecord.setIsExceed(false);
+                checkExamInProgressInfo.setIsExceed(false);
+            } else {
+                examingRecord.setIsExceed(true);
+                checkExamInProgressInfo.setIsExceed(true);
+            }
+            // 更新考试中的断点续考属性
+            examRecordDataService.saveExamRecordDataCache(examingRecord.getId(), examingRecord);
+
+            checkExamInProgressInfo.setExamRecordDataId(examingRecord.getId());
+            checkExamInProgressInfo.setExamId(examSessionInfo.getExamId());
+            checkExamInProgressInfo.setUsedTime(examSessionInfo.getCost());
+            checkExamInProgressInfo.setMaxInterruptNum(maxInterruptNum);
+            checkExamInProgressInfo.setInterruptNum(examingRecord.getContinuedCount());
+
+            // 断点续考时重新计算活体检测的分钟数
+            Integer faceVerifyMinute = null;
+            FaceBiopsyScheme faceBiopsyScheme = FaceBiopsyHelper.getFaceBiopsyScheme(examSessionInfo.getRootOrgId());
+
+            // 如果是新活体检测方案,则使用新的计算方案计算活检开始时间
+            if (faceBiopsyScheme == FaceBiopsyScheme.NEW) {
+                faceVerifyMinute = faceBiopsyService.calculateFaceBiopsyStartMinute(examingRecord.getId());
+            }else {// 非新活检,默认使用旧的活检计算方式
+                faceVerifyMinute = examFaceLivenessVerifyService.getFaceLivenessVerifyMinute(
+                        examSessionInfo.getRootOrgId(), examSessionInfo.getOrgId(), examSessionInfo.getExamId(),
+                        studentId, examSessionInfo.getExamRecordDataId(), examSessionInfo.getHeartbeat());
+            }
+
+            checkExamInProgressInfo.setFaceVerifyMinute(faceVerifyMinute);
+            return checkExamInProgressInfo;
+        }
+    }
+
+    private ExamRecordData checkExamSession(ExamingSession examSessionInfo, Long studentId) {
+        ExamRecordData examingRecord = examRecordDataService
+                .getExamRecordDataCache(examSessionInfo.getExamRecordDataId());
+        if (examingRecord == null) {
+            return null;
+        }
+
+        // 如果考试时间结束,自动交卷
+        if (examSessionInfo.getExamDuration() <= examSessionInfo.getCost()) {
+            delayHandInExamIfLocked(examingRecord.getId());
+            return null;
+        }
+
+        // 如果已经过了断点续考时间,自动交卷
+        long now = System.currentTimeMillis();
+        if (now - examSessionInfo.getActiveTime() >= examSessionInfo.getExamReconnectTime().intValue() * 60 * 1000) {
+            delayHandInExamIfLocked(examingRecord.getId());
+            return null;
+        }
+        return examingRecord;
+    }
+
+    /**
+     * 如果有序列化锁,则延迟交卷
+     *
+     * @param examRecordDataId
+     *            考试记录id
+     * @return
+     */
+    private void delayHandInExamIfLocked(Long examRecordDataId) {
+        try {
+            handInExam(examRecordDataId, HandInExamType.AUTO);
+        } catch (SequenceLockException e) {
+            // 如果发现自动服务正在交卷,则重试1500毫秒获取考试记录状态,判断是否已交卷
+            int loopTimes = 0;
+            while (loopTimes <= 15) {
+                loopTimes++;
+                ExamRecordData examRecordData = examRecordDataService.getExamRecordDataCache(examRecordDataId);
+                if (examRecordData == null) {
+                    throw new StatusException("7001", "考试信息不存在");
+                }
+                // 1500毫秒内如果交卷成功,则退出循环
+                if (examRecordData.getExamRecordStatus() != ExamRecordStatus.EXAM_ING) {
+                    return;
+                }
+                Util.sleep(TimeUnit.MILLISECONDS, 100);
+            }
+            throw e;
+        }
+    }
+
+    private Integer getMaxInterruptNum(Long examId, Long rootOrgId, Long orgId) {
+        GetExamPropertyReq req = new GetExamPropertyReq();
+        req.setExamId(examId);
+        req.setRootOrgId(rootOrgId);
+        req.setOrgId(orgId);
+        req.setKey(ExamProperties.MAX_INTERRUPT_NUM.name());
+        GetExamPropertyResp res = examCloudService.getExamProperty(req);
+        Integer ret = 100;
+        if (StringUtils.isNoneBlank(res.getValue())) {
+            try {
+                ret = Integer.valueOf(res.getValue());
+            } catch (NumberFormatException e) {
+                log.error("MaxInterruptNum is not a number,return default value:100", e);
+            }
+        }
+        return ret;
+    }
 }

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

@@ -67,22 +67,22 @@ public class ExamRecordDataServiceImpl implements ExamRecordDataService {
         ExamRecordData bean = new ExamRecordData();
         BeanUtils.copyProperties(bean, examRecordData);
         //存入redis
-        saveExamRecordDataBean(examRecordData.getId(), bean, -1);
+        saveExamRecordDataCache(examRecordData.getId(), bean);
         return bean;
     }
 
     @Override
-    public void saveExamRecordDataBean(Long examRecordDataId, ExamRecordData data, int timeout) {
-        redisClient.set(examRecordDataKeyPrefix + examRecordDataId, data, timeout);
+    public void saveExamRecordDataCache(Long examRecordDataId, ExamRecordData data) {
+        redisClient.set(examRecordDataKeyPrefix + examRecordDataId, data, -1);
     }
 
     @Override
-    public ExamRecordData getExamRecordDataBean(Long examRecordDataId) {
+    public ExamRecordData getExamRecordDataCache(Long examRecordDataId) {
         return redisClient.get(examRecordDataKeyPrefix + examRecordDataId, ExamRecordData.class);
     }
 
     @Override
-    public void deleteExamRecordDataBean(Long examRecordDataId) {
+    public void deleteExamRecordDataCache(Long examRecordDataId) {
         redisClient.delete(examRecordDataKeyPrefix + examRecordDataId);
     }
 

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

@@ -19,7 +19,7 @@ public class ExamRecordPaperStructServiceImpl implements ExamRecordPaperStructSe
 
     @Override
     public void saveExamRecordPaperStruct(Long examRecordDataId, DefaultPaper paper) {
-        redisClient.set(examPaperStructKeyPrefix + examRecordDataId, paper);
+        redisClient.set(examPaperStructKeyPrefix + examRecordDataId, paper,-1);
     }
 
     @Override

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

@@ -27,8 +27,8 @@ public class ExamRecordQuestionsServiceImpl implements ExamRecordQuestionsServic
     private String examRecordQuestionsKeyPrefix;
 
     @Override
-    public void saveExamRecordQuestions(Long examRecordDataId, ExamRecordQuestions questions,int timeout) {
-        redisClient.set(examRecordQuestionsKeyPrefix + examRecordDataId, questions,timeout);
+    public void saveExamRecordQuestions(Long examRecordDataId, ExamRecordQuestions questions) {
+        redisClient.set(examRecordQuestionsKeyPrefix + examRecordDataId, questions,-1);
     }
 
     @Override
@@ -75,7 +75,7 @@ public class ExamRecordQuestionsServiceImpl implements ExamRecordQuestionsServic
         examRecordQuestions.setExamQuestions(examQuestionEntityList);
         examRecordQuestions.setExamRecordDataId(examRecordDataId);
         examRecordQuestions.setCreationTime(new Date());
-        saveExamRecordQuestions(examRecordDataId, examRecordQuestions,-1);
+        saveExamRecordQuestions(examRecordDataId, examRecordQuestions);
         return examRecordQuestions;
     }
 

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

@@ -24,8 +24,8 @@ public class ExamingSessionServiceImpl implements ExamingSessionService {
     private String examRedisKeyPrefix;
 
     @Override
-    public void saveExamingSession(Long studentId, ExamingSession examingSession,int timeout) {
-        redisClient.set(examRedisKeyPrefix+studentId,examingSession,timeout);
+    public void saveExamingSession(Long studentId, ExamingSession examingSession) {
+        redisClient.set(examRedisKeyPrefix+studentId,examingSession,-1);
     }
 
     @Override