Browse Source

客观题缓存加载

xiatian 4 years ago
parent
commit
3810a2107f
26 changed files with 895 additions and 399 deletions
  1. 23 91
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamActivityController.java
  2. 4 0
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamController.java
  3. 45 0
      themis-business/src/main/java/com/qmth/themis/business/cache/ObjectiveAnswerCacheUtil.java
  4. 28 0
      themis-business/src/main/java/com/qmth/themis/business/cache/RedisKeyHelper.java
  5. 4 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TEExamActivityMapper.java
  6. 2 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TEExamPaperMapper.java
  7. 1 1
      themis-business/src/main/java/com/qmth/themis/business/enums/MqExecTypeEnum.java
  8. 1 1
      themis-business/src/main/java/com/qmth/themis/business/enums/MqTagEnum.java
  9. 8 5
      themis-business/src/main/java/com/qmth/themis/business/service/TEExamActivityService.java
  10. 19 9
      themis-business/src/main/java/com/qmth/themis/business/service/TEExamPaperService.java
  11. 1 1
      themis-business/src/main/java/com/qmth/themis/business/service/TOeExamRecordService.java
  12. 125 12
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamActivityServiceImpl.java
  13. 117 30
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamPaperServiceImpl.java
  14. 232 62
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java
  15. 169 162
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java
  16. 7 2
      themis-business/src/main/java/com/qmth/themis/business/templete/impl/TaskExamPaperImportTemplete.java
  17. 8 0
      themis-business/src/main/java/com/qmth/themis/business/util/RedisUtil.java
  18. 12 0
      themis-business/src/main/resources/mapper/TEExamActivityMapper.xml
  19. 6 0
      themis-business/src/main/resources/mapper/TEExamPaperMapper.xml
  20. 4 0
      themis-common/src/main/java/com/qmth/themis/common/enums/ExceptionResultEnum.java
  21. 1 1
      themis-mq/src/main/java/com/qmth/themis/mq/service/MqLogicService.java
  22. 12 12
      themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java
  23. 7 7
      themis-mq/src/main/java/com/qmth/themis/mq/templete/impl/CalculateObjectiveScoreConcurrentlyImpl.java
  24. 6 1
      themis-task/src/main/java/com/qmth/themis/task/enums/QuartzTaskEnum.java
  25. 42 0
      themis-task/src/main/java/com/qmth/themis/task/quartz/ObjectiveAnswerCacheLoadJob.java
  26. 11 2
      themis-task/src/main/java/com/qmth/themis/task/start/StartRunning.java

+ 23 - 91
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamActivityController.java

@@ -1,31 +1,30 @@
 package com.qmth.themis.admin.api;
 package com.qmth.themis.admin.api;
 
 
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.constant.SystemConstant;
-import com.qmth.themis.business.dto.MqDto;
-import com.qmth.themis.business.entity.TBUser;
-import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.entity.TEExamActivity;
 import com.qmth.themis.business.entity.TEExamActivity;
-import com.qmth.themis.business.enums.FieldUniqueEnum;
-import com.qmth.themis.business.enums.InvigilateMonitorStatusEnum;
-import com.qmth.themis.business.enums.MqTagEnum;
-import com.qmth.themis.business.service.MqDtoService;
 import com.qmth.themis.business.service.TEExamActivityService;
 import com.qmth.themis.business.service.TEExamActivityService;
-import com.qmth.themis.business.service.TEExamService;
-import com.qmth.themis.business.util.*;
-import com.qmth.themis.common.enums.ExceptionResultEnum;
-import com.qmth.themis.common.exception.BusinessException;
+import com.qmth.themis.business.service.TEExamPaperService;
 import com.qmth.themis.common.util.Result;
 import com.qmth.themis.common.util.Result;
 import com.qmth.themis.common.util.ResultUtil;
 import com.qmth.themis.common.util.ResultUtil;
-import io.swagger.annotations.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.dao.DuplicateKeyException;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
 
 
-import javax.annotation.Resource;
-import java.util.*;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
 
 
 /**
 /**
  * @Description: 考试场次 前端控制器
  * @Description: 考试场次 前端控制器
@@ -39,25 +38,11 @@ import java.util.*;
 @RequestMapping("/${prefix.url.admin}/activity")
 @RequestMapping("/${prefix.url.admin}/activity")
 public class TEExamActivityController {
 public class TEExamActivityController {
 
 
-    private final static Logger log = LoggerFactory.getLogger(TEExamActivityController.class);
-
     @Resource
     @Resource
-    TEExamActivityService teExamActivityService;
-
-    @Resource
-    MqDtoService mqDtoService;
-
-    @Resource
-    TEExamService teExamService;
-
-    @Resource
-    RedisUtil redisUtil;
-
-    @Resource
-    UidUtil uidUtil;
-
+    private TEExamActivityService teExamActivityService;
+    
     @Resource
     @Resource
-    MqUtil mqUtil;
+    private  TEExamPaperService examPaperService;
 
 
     @ApiOperation(value = "考试场次修改/新增接口")
     @ApiOperation(value = "考试场次修改/新增接口")
     @RequestMapping(value = "/save", method = RequestMethod.POST)
     @RequestMapping(value = "/save", method = RequestMethod.POST)
@@ -65,61 +50,8 @@ public class TEExamActivityController {
     @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
     @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
     public Result save(
     public Result save(
             @ApiParam(value = "考试场次信息", required = true) @RequestBody List<TEExamActivity> teExamActivityList) {
             @ApiParam(value = "考试场次信息", required = true) @RequestBody List<TEExamActivity> teExamActivityList) {
-        if (Objects.isNull(teExamActivityList) || teExamActivityList.size() == 0) {
-            throw new BusinessException(ExceptionResultEnum.EXAM_INFO_IS_NULL);
-        }
-        Long examId = null;
-        try {
-            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
-            examId = teExamActivityList.get(0).getExamId();
-            TEExam teExam = teExamService.getById(teExamActivityList.get(0).getExamId());
-            if (Objects.nonNull(teExam.getMonitorStatus()) && Objects
-                    .equals(teExam.getMonitorStatus(), InvigilateMonitorStatusEnum.FINISHED)) {
-                throw new BusinessException("监考结束的考试场次不可以修改");
-            }
-            teExamActivityList.forEach(s -> {
-                if (Objects.nonNull(s.getId())) {
-                    s.setUpdateId(tbUser.getId());
-                } else {
-                    s.setId(uidUtil.getId());
-                    s.setCreateId(tbUser.getId());
-                    s.setCode(String.valueOf(redisUtil.getRedisActivityCodeSequence(s.getExamId())));
-                }
-                teExamActivityService.saveOrUpdate(s);
-            });
-            for (TEExamActivity ac : teExamActivityList) {
-                teExamActivityService.updateExamActivityCacheBean(ac.getId());
-            }
-            if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1) {
-                //新增quartz任务,发送mq消息start
-                Map<String, Object> prop = new HashMap<>();
-                prop.put("oper", "insert");
-                prop.put("exam", teExam);
-                MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
-                        JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
-                        String.valueOf(teExam.getId()), prop, tbUser.getName());
-                mqDtoService.assembleSendOneWayMsg(mqDto);
-                //新增quartz任务,发送mq消息end
-            }
-        } catch (Exception e) {
-            log.error("请求出错", e);
-            if (Objects.nonNull(examId) && Objects.nonNull(teExamActivityList) && (Objects.nonNull(teExamActivityList)
-                    && teExamActivityList.size() > 0 && Objects.nonNull(teExamActivityList.get(0)))) {
-                redisUtil.setRedisActivityCodeSequence(examId,
-                        Integer.parseInt(teExamActivityList.get(0).getCode()) - 1);
-            }
-            if (e instanceof DuplicateKeyException) {
-                String errorColumn = e.getCause().toString();
-                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3, errorColumn.length())
-                        .replaceAll("'", "");
-                throw new BusinessException("机构id[" + teExamActivityList.get(0).getExamId() + "]下的" + FieldUniqueEnum
-                        .convertToCode(columnStr) + "数据不允许重复插入");
-            } else if (e instanceof BusinessException) {
-                throw new BusinessException(e.getMessage());
-            } else {
-                throw new RuntimeException(e);
-            }
-        }
+    	teExamActivityService.saveExamActivity(teExamActivityList);
+    	examPaperService.disposeObjectiveAnswer(teExamActivityList.get(0).getExamId());
         return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
         return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
     }
     }
 
 

+ 4 - 0
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamController.java

@@ -77,6 +77,9 @@ public class TEExamController {
 
 
     @Resource
     @Resource
     TOeExamRecordService tOeExamRecordService;
     TOeExamRecordService tOeExamRecordService;
+    
+    @Resource
+    private  TEExamPaperService examPaperService;
 
 
     @ApiOperation(value = "考试批次修改/新增接口")
     @ApiOperation(value = "考试批次修改/新增接口")
     @RequestMapping(value = "/save", method = RequestMethod.POST)
     @RequestMapping(value = "/save", method = RequestMethod.POST)
@@ -237,6 +240,7 @@ public class TEExamController {
             }
             }
         }
         }
         teExamService.updateExamCacheBean(teExam.getId());
         teExamService.updateExamCacheBean(teExam.getId());
+        examPaperService.disposeObjectiveAnswer(teExam.getId());
         return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
         return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
     }
     }
 
 

+ 45 - 0
themis-business/src/main/java/com/qmth/themis/business/cache/ObjectiveAnswerCacheUtil.java

@@ -0,0 +1,45 @@
+package com.qmth.themis.business.cache;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import com.qmth.themis.business.cache.bean.ObjectiveAnswerCacheBean;
+import com.qmth.themis.business.constant.SpringContextHolder;
+import com.qmth.themis.business.util.RedisUtil;
+
+/**客观题缓存
+ * @Description: 
+ * @Author: xiatian
+ * @Date: 2020-12-29
+ */
+public class ObjectiveAnswerCacheUtil {
+
+    private static RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
+    
+    public static void saveObjectiveAnswerCache(Long examId,Long paperId,Map<String, ObjectiveAnswerCacheBean> val) {
+    	redisUtil.set(RedisKeyHelper.objectiveAnswerCacheKey(examId), RedisKeyHelper.objectiveAnswerCacheHashKey(paperId),val);
+    }
+    
+    public static void expireObjectiveAnswerCache(Long examId,Long hours) {
+    	redisUtil.expire(RedisKeyHelper.objectiveAnswerCacheKey(examId), hours, TimeUnit.HOURS);
+    }
+    
+    public static void deleteObjectiveAnswerCache(Long examId,Long paperId) {
+    	redisUtil.delete(RedisKeyHelper.objectiveAnswerCacheKey(examId), RedisKeyHelper.objectiveAnswerCacheHashKey(paperId));
+    }
+    
+    @SuppressWarnings("unchecked")
+	public static Map<String, ObjectiveAnswerCacheBean> getObjectiveAnswerCache(Long examId,Long paperId) {
+    	return (Map<String, ObjectiveAnswerCacheBean>)redisUtil.get(RedisKeyHelper.objectiveAnswerCacheKey(examId), RedisKeyHelper.objectiveAnswerCacheHashKey(paperId));
+    }
+    
+    public static Long getHashCacheSize(Long examId) {
+    	Long ret=redisUtil.getHashSize(RedisKeyHelper.objectiveAnswerCacheKey(examId));
+    	if(ret==null) {
+    		return 0L;
+    	}else {
+    		return ret;
+    	}
+    }
+
+}

+ 28 - 0
themis-business/src/main/java/com/qmth/themis/business/cache/RedisKeyHelper.java

@@ -60,6 +60,17 @@ public class RedisKeyHelper {
 	 * 未完成考试记录id
 	 * 未完成考试记录id
 	 */
 	 */
 	private static String unFinishedRecordIdKeyPrefix = "un_finished_record_id::student_id_";
 	private static String unFinishedRecordIdKeyPrefix = "un_finished_record_id::student_id_";
+	
+	/**
+	 * 客观题答案
+	 */
+	private static String objectiveAnswerKeyPrefix = "objective_answer::exam_id_";
+	
+	/**
+	 * 客观题答案
+	 */
+	private static String objectiveAnswerHashKeyPrefix = "paper_id_";
+	
 	/**
 	/**
 	 * 场次
 	 * 场次
 	 * 
 	 * 
@@ -189,4 +200,21 @@ public class RedisKeyHelper {
 		return unFinishedRecordIdKeyPrefix + studentId;
 		return unFinishedRecordIdKeyPrefix + studentId;
 	}
 	}
 	
 	
+	/**客观题答案大key
+	 * @param examId
+	 * @return
+	 */
+	public static String objectiveAnswerCacheKey(Long examId) {
+		return objectiveAnswerKeyPrefix+examId;
+	}
+	
+	/**客观题答案小key
+	 * @param paperId
+	 * @return
+	 */
+	public static String objectiveAnswerCacheHashKey(Long paperId) {
+		return objectiveAnswerHashKeyPrefix+paperId;
+	}
+	
+	
 }
 }

+ 4 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TEExamActivityMapper.java

@@ -95,4 +95,8 @@ public interface TEExamActivityMapper extends BaseMapper<TEExamActivity> {
     public TEExamActivityDto getWaitingExamByExamActivityId(@Param("examActivityId") Long examActivityId);
     public TEExamActivityDto getWaitingExamByExamActivityId(@Param("examActivityId") Long examActivityId);
 
 
     public List<TEExamActivity> findByExamIdAndOrgId(@Param("examId") Long examId, @Param("orgId") Long orgId);
     public List<TEExamActivity> findByExamIdAndOrgId(@Param("examId") Long examId, @Param("orgId") Long orgId);
+    
+    public List<Map<String,Long>> findMinStartTimeAndMaxFinshTimeByExamId(@Param("examId") Long examId);
+    
+    public List<Long> findExamIdToday(@Param("startTime") Long startTime,@Param("endTime") Long endTime);
 }
 }

+ 2 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TEExamPaperMapper.java

@@ -23,6 +23,8 @@ public interface TEExamPaperMapper extends BaseMapper<TEExamPaper> {
 
 
 	public List<TEExamPaper> findListByExamIdAndCourseCode(@Param("examId") Long examId,
 	public List<TEExamPaper> findListByExamIdAndCourseCode(@Param("examId") Long examId,
 			@Param("courseCode") String courseCode);
 			@Param("courseCode") String courseCode);
+	
+	public List<TEExamPaper> findByExamId(@Param("examId") Long examId);
 
 
 	public void updateWeight(@Param("id") Long id, @Param("weight") Double weight);
 	public void updateWeight(@Param("id") Long id, @Param("weight") Double weight);
 }
 }

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/enums/MqExecTypeEnum.java

@@ -35,7 +35,7 @@ public enum MqExecTypeEnum {
 
 
     EXEC_MQ_CALCULATE_SCORE_LOGIC("重新算分逻辑", "execMqCalculateScoreLogic"),
     EXEC_MQ_CALCULATE_SCORE_LOGIC("重新算分逻辑", "execMqCalculateScoreLogic"),
 
 
-    EXEC_MQ_CALCULATE_OBJECTIVE_SCORE_LOGIC("计算客观分逻辑", "execMqCalculateObjectiveScoreLogic"),
+//    EXEC_MQ_CALCULATE_OBJECTIVE_SCORE_LOGIC("计算客观分逻辑", "execMqCalculateObjectiveScoreLogic"),
 
 
     EXEC_MQ_WEBSOCKET_UN_NORMAL_LOGIC("websocket非正常退出,延时消息逻辑", "execMqWebsocketUnNormalLogic"),
     EXEC_MQ_WEBSOCKET_UN_NORMAL_LOGIC("websocket非正常退出,延时消息逻辑", "execMqWebsocketUnNormalLogic"),
 
 

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/enums/MqTagEnum.java

@@ -30,7 +30,7 @@ public enum MqTagEnum {
     OE_UN_NORMAL("websocket超时退出标签", "websocket超时退出", "delay", 18),
     OE_UN_NORMAL("websocket超时退出标签", "websocket超时退出", "delay", 18),
     EXAM_ACTIVITY("考场一次性延时任务标签", "考场一次性延时任务", "normal", 19),
     EXAM_ACTIVITY("考场一次性延时任务标签", "考场一次性延时任务", "normal", 19),
     QUARTZ("quartz标签", "quartz任务", "normal", 20),
     QUARTZ("quartz标签", "quartz任务", "normal", 20),
-    CALCULATE_OBJECTIVE_SCORE("计算客观分标签", "计算客观分", "normal", 21),
+//    CALCULATE_OBJECTIVE_SCORE("计算客观分标签", "计算客观分", "normal", 21),
     FACE_VERIFY_SAVE("人脸验证保存标签", "人脸验证", "normal", 22),
     FACE_VERIFY_SAVE("人脸验证保存标签", "人脸验证", "normal", 22),
     LIVENESS_VERIFY_SAVE("活体验证保存标签", "活体验证", "normal", 23),
     LIVENESS_VERIFY_SAVE("活体验证保存标签", "活体验证", "normal", 23),
     EXAM_RECORD_PERSISTED("考试记录数据持久化标签", "考试", "normal", 24),
     EXAM_RECORD_PERSISTED("考试记录数据持久化标签", "考试", "normal", 24),

+ 8 - 5
themis-business/src/main/java/com/qmth/themis/business/service/TEExamActivityService.java

@@ -1,18 +1,17 @@
 package com.qmth.themis.business.service;
 package com.qmth.themis.business.service;
 
 
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.qmth.themis.business.bean.exam.ExamPrepareBean;
 import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.dto.response.TEExamActivityDto;
 import com.qmth.themis.business.dto.response.TEExamActivityDto;
 import com.qmth.themis.business.dto.response.TEExamActivityQueryDto;
 import com.qmth.themis.business.dto.response.TEExamActivityQueryDto;
 import com.qmth.themis.business.dto.response.TEExamActivityWaitDto;
 import com.qmth.themis.business.dto.response.TEExamActivityWaitDto;
 import com.qmth.themis.business.entity.TEExamActivity;
 import com.qmth.themis.business.entity.TEExamActivity;
 
 
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 /**
 /**
  * @Description: 考试场次 服务类
  * @Description: 考试场次 服务类
  * @Param:
  * @Param:
@@ -119,4 +118,8 @@ public interface TEExamActivityService extends IService<TEExamActivity> {
     void deleteExamActivityCacheBean(Long examActivityId);
     void deleteExamActivityCacheBean(Long examActivityId);
 
 
     public List<TEExamActivity> findByExamIdAndOrgId(Long examId, Long orgId);
     public List<TEExamActivity> findByExamIdAndOrgId(Long examId, Long orgId);
+
+	void saveExamActivity(List<TEExamActivity> teExamActivityList);
+
+	List<Long> findExamIdToday();
 }
 }

+ 19 - 9
themis-business/src/main/java/com/qmth/themis/business/service/TEExamPaperService.java

@@ -40,15 +40,6 @@ public interface TEExamPaperService extends IService<TEExamPaper> {
 
 
     Map<String, ObjectiveAnswerCacheBean> getObjectiveAnswerCacheBean(Long paperId);
     Map<String, ObjectiveAnswerCacheBean> getObjectiveAnswerCacheBean(Long paperId);
 
 
-    void savePaperWeight(Map<Long, Double> map);
-
-	/**
-	 * 删除客观题标答缓存
-	 *
-	 * @param paperId
-	 */
-	void deleteObjectiveAnswerCacheBean(Long paperId);
-
 	/**
 	/**
 	 * 删除试卷结构缓存
 	 * 删除试卷结构缓存
 	 *
 	 *
@@ -58,4 +49,23 @@ public interface TEExamPaperService extends IService<TEExamPaper> {
 
 
 	Map<String, Integer> getPaperStructCacheBean(Long paperId);
 	Map<String, Integer> getPaperStructCacheBean(Long paperId);
 
 
+	void savePaperWeight(Map<Long, Double> map);
+
+	/**处理试卷缓存
+	 * @param examId
+	 * @param paperIds
+	 */
+	void disposePaperCacheOnPaperImport(Long examId,List<Long> paperIds);
+
+	/**加载客观题答案缓存
+	 * @param paperId
+	 * @param timeOutHours
+	 */
+	void reloadObjectiveAnswerCacheBean(Long paperId,Long timeOutHours);
+
+	/**处理考试批次下的客观题答案缓存
+	 * @param examId
+	 */
+	void disposeObjectiveAnswer(Long examId);
+
 }
 }

+ 1 - 1
themis-business/src/main/java/com/qmth/themis/business/service/TOeExamRecordService.java

@@ -36,7 +36,7 @@ public interface TOeExamRecordService extends IService<TOeExamRecord> {
      *
      *
      * @param param
      * @param param
      */
      */
-    void calculateObjectiveScore(Map<String, Object> param);
+//    void calculateObjectiveScore(Map<String, Object> param);
 
 
     /**
     /**
      * 考试记录数据持久化
      * 考试记录数据持久化

+ 125 - 12
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamActivityServiceImpl.java

@@ -1,31 +1,57 @@
 package com.qmth.themis.business.service.impl;
 package com.qmth.themis.business.service.impl;
 
 
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import javax.annotation.Resource;
+
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.qmth.themis.business.bean.exam.ExamPrepareBean;
 import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.dao.TEExamActivityMapper;
 import com.qmth.themis.business.dao.TEExamActivityMapper;
+import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.dto.response.TEExamActivityDto;
 import com.qmth.themis.business.dto.response.TEExamActivityDto;
 import com.qmth.themis.business.dto.response.TEExamActivityQueryDto;
 import com.qmth.themis.business.dto.response.TEExamActivityQueryDto;
 import com.qmth.themis.business.dto.response.TEExamActivityWaitDto;
 import com.qmth.themis.business.dto.response.TEExamActivityWaitDto;
+import com.qmth.themis.business.entity.TBUser;
+import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.entity.TEExamActivity;
 import com.qmth.themis.business.entity.TEExamActivity;
 import com.qmth.themis.business.enums.EntryAuthenticationPolicyEnum;
 import com.qmth.themis.business.enums.EntryAuthenticationPolicyEnum;
+import com.qmth.themis.business.enums.FieldUniqueEnum;
 import com.qmth.themis.business.enums.HardwareTestEnum;
 import com.qmth.themis.business.enums.HardwareTestEnum;
+import com.qmth.themis.business.enums.InvigilateMonitorStatusEnum;
 import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
 import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
+import com.qmth.themis.business.enums.MqTagEnum;
+import com.qmth.themis.business.service.MqDtoService;
 import com.qmth.themis.business.service.TEExamActivityService;
 import com.qmth.themis.business.service.TEExamActivityService;
 import com.qmth.themis.business.service.TEExamCourseService;
 import com.qmth.themis.business.service.TEExamCourseService;
 import com.qmth.themis.business.service.TEExamService;
 import com.qmth.themis.business.service.TEExamService;
 import com.qmth.themis.business.service.TEExamStudentService;
 import com.qmth.themis.business.service.TEExamStudentService;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.CachePut;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.util.*;
+import com.qmth.themis.business.util.JacksonUtil;
+import com.qmth.themis.business.util.MqUtil;
+import com.qmth.themis.business.util.RedisUtil;
+import com.qmth.themis.business.util.ServletUtil;
+import com.qmth.themis.business.util.UidUtil;
+import com.qmth.themis.common.enums.ExceptionResultEnum;
+import com.qmth.themis.common.exception.BusinessException;
 
 
 /**
 /**
  * @Description: 考试场次 服务实现类
  * @Description: 考试场次 服务实现类
@@ -38,17 +64,28 @@ import java.util.*;
 public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper, TEExamActivity> implements TEExamActivityService {
 public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper, TEExamActivity> implements TEExamActivityService {
 
 
     @Resource
     @Resource
-    TEExamActivityMapper teExamActivityMapper;
+    private TEExamActivityMapper teExamActivityMapper;
+
+    @Resource
+    private TEExamService teExamService;
+
+    @Resource
+    private TEExamStudentService teExamStudentService;
+
+    @Resource
+    private TEExamCourseService teExamCourseService;
 
 
     @Resource
     @Resource
-    TEExamService teExamService;
+    private MqDtoService mqDtoService;
 
 
     @Resource
     @Resource
-    TEExamStudentService teExamStudentService;
+    private RedisUtil redisUtil;
 
 
     @Resource
     @Resource
-    TEExamCourseService teExamCourseService;
+    private UidUtil uidUtil;
 
 
+    @Resource
+    private MqUtil mqUtil;
     /**
     /**
      * 表是否存在
      * 表是否存在
      *
      *
@@ -259,4 +296,80 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
     public List<TEExamActivity> findByExamIdAndOrgId(Long examId, Long orgId) {
     public List<TEExamActivity> findByExamIdAndOrgId(Long examId, Long orgId) {
         return teExamActivityMapper.findByExamIdAndOrgId(examId, orgId);
         return teExamActivityMapper.findByExamIdAndOrgId(examId, orgId);
     }
     }
+    
+    @Transactional
+    @Override
+    public void saveExamActivity(List<TEExamActivity> teExamActivityList) {
+    	if (Objects.isNull(teExamActivityList) || teExamActivityList.size() == 0) {
+            throw new BusinessException(ExceptionResultEnum.EXAM_INFO_IS_NULL);
+        }
+        Long examId = null;
+        try {
+            TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
+            examId = teExamActivityList.get(0).getExamId();
+            TEExam teExam = teExamService.getById(teExamActivityList.get(0).getExamId());
+            if (Objects.nonNull(teExam.getMonitorStatus()) && Objects
+                    .equals(teExam.getMonitorStatus(), InvigilateMonitorStatusEnum.FINISHED)) {
+                throw new BusinessException("监考结束的考试场次不可以修改");
+            }
+            teExamActivityList.forEach(s -> {
+                if (Objects.nonNull(s.getId())) {
+                    s.setUpdateId(tbUser.getId());
+                } else {
+                    s.setId(uidUtil.getId());
+                    s.setCreateId(tbUser.getId());
+                    s.setCode(String.valueOf(redisUtil.getRedisActivityCodeSequence(s.getExamId())));
+                }
+                this.saveOrUpdate(s);
+            });
+            for (TEExamActivity ac : teExamActivityList) {
+                this.updateExamActivityCacheBean(ac.getId());
+            }
+            if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1) {
+                //新增quartz任务,发送mq消息start
+                Map<String, Object> prop = new HashMap<>();
+                prop.put("oper", "insert");
+                prop.put("exam", teExam);
+                MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
+                        JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
+                        String.valueOf(teExam.getId()), prop, tbUser.getName());
+                mqDtoService.assembleSendOneWayMsg(mqDto);
+                //新增quartz任务,发送mq消息end
+            }
+        } catch (Exception e) {
+            log.error("请求出错", e);
+            if (Objects.nonNull(examId) && Objects.nonNull(teExamActivityList) && (Objects.nonNull(teExamActivityList)
+                    && teExamActivityList.size() > 0 && Objects.nonNull(teExamActivityList.get(0)))) {
+                redisUtil.setRedisActivityCodeSequence(examId,
+                        Integer.parseInt(teExamActivityList.get(0).getCode()) - 1);
+            }
+            if (e instanceof DuplicateKeyException) {
+                String errorColumn = e.getCause().toString();
+                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3, errorColumn.length())
+                        .replaceAll("'", "");
+                throw new BusinessException("机构id[" + teExamActivityList.get(0).getExamId() + "]下的" + FieldUniqueEnum
+                        .convertToCode(columnStr) + "数据不允许重复插入");
+            } else if (e instanceof BusinessException) {
+                throw new BusinessException(e.getMessage());
+            } else {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+    
+    @Override
+    public List<Long> findExamIdToday(){
+    	try {
+			Date now=new Date();
+			SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd");
+			String today=sdf1.format(now);
+			SimpleDateFormat sdf2=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+			Long start=sdf2.parse(today+" 00:00:00").getTime();
+			Long end=sdf2.parse(today+" 23:59:59").getTime();
+			return teExamActivityMapper.findExamIdToday(start, end);
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+    	return null;
+    }
 }
 }

+ 117 - 30
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamPaperServiceImpl.java

@@ -1,29 +1,40 @@
 package com.qmth.themis.business.service.impl;
 package com.qmth.themis.business.service.impl;
 
 
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.aliyun.oss.common.utils.BinaryUtil;
 import com.aliyun.oss.common.utils.BinaryUtil;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.themis.business.cache.ObjectiveAnswerCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
 import com.qmth.themis.business.cache.RedisKeyHelper;
 import com.qmth.themis.business.cache.bean.ExamPaperCacheBean;
 import com.qmth.themis.business.cache.bean.ExamPaperCacheBean;
 import com.qmth.themis.business.cache.bean.ObjectiveAnswerCacheBean;
 import com.qmth.themis.business.cache.bean.ObjectiveAnswerCacheBean;
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.constant.SpringContextHolder;
+import com.qmth.themis.business.dao.TEExamActivityMapper;
 import com.qmth.themis.business.dao.TEExamPaperMapper;
 import com.qmth.themis.business.dao.TEExamPaperMapper;
 import com.qmth.themis.business.entity.TEExamPaper;
 import com.qmth.themis.business.entity.TEExamPaper;
 import com.qmth.themis.business.service.TEExamPaperService;
 import com.qmth.themis.business.service.TEExamPaperService;
+import com.qmth.themis.business.service.TEExamService;
 import com.qmth.themis.business.util.OssUtil;
 import com.qmth.themis.business.util.OssUtil;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.exception.BusinessException;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.CachePut;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.*;
 
 
 /**
 /**
  * @Description: 考试试卷 服务实现类
  * @Description: 考试试卷 服务实现类
@@ -34,12 +45,20 @@ import java.util.*;
  */
  */
 @Service
 @Service
 public class TEExamPaperServiceImpl extends ServiceImpl<TEExamPaperMapper, TEExamPaper> implements TEExamPaperService {
 public class TEExamPaperServiceImpl extends ServiceImpl<TEExamPaperMapper, TEExamPaper> implements TEExamPaperService {
-
+	
+	private final static long objectiveAnswerCacheTimeOutHours=48L;
+	
+	@Resource
+	private TEExamService examService;
+	
     @Resource
     @Resource
     OssUtil ossUtil;
     OssUtil ossUtil;
 
 
     @Resource
     @Resource
     TEExamPaperMapper teExamPaperMapper;
     TEExamPaperMapper teExamPaperMapper;
+    
+    @Resource
+    TEExamActivityMapper  examActivityMapper;
 
 
     @Override
     @Override
     public TEExamPaper findByExamIdAndCourseCodeAndPaperCode(Long examId, String courseCode, String paperCode) {
     public TEExamPaper findByExamIdAndCourseCodeAndPaperCode(Long examId, String courseCode, String paperCode) {
@@ -130,38 +149,56 @@ public class TEExamPaperServiceImpl extends ServiceImpl<TEExamPaperMapper, TEExa
         ret.setPaperViewPath(ep.getPaperViewPath());
         ret.setPaperViewPath(ep.getPaperViewPath());
         return ret;
         return ret;
     }
     }
-
-    /**
-     * 删除客观题标答缓存
-     *
-     * @param paperId
-     */
+    
     @Override
     @Override
-    @CacheEvict(value = "objective_answer", key = "#paperId")
-    public void deleteObjectiveAnswerCacheBean(Long paperId) {
-
+    public void reloadObjectiveAnswerCacheBean(Long paperId,Long timeOutHours) {
+        ExamPaperCacheBean ep = getExamPaperCacheBean(paperId);
+        if (ep == null) {
+            return ;
+        }
+        Long examId=ep.getExamId();
+        if (StringUtils.isBlank(ep.getAnswerPath())) {//没有答案文件
+            return ;
+        }
+        try {
+            String structJson = new String(ossUtil.download(false, ep.getStructPath()), StandardCharsets.UTF_8);
+            String answerjson = new String(ossUtil.download(false, ep.getAnswerPath()), StandardCharsets.UTF_8);
+            Map<String, ObjectiveAnswerCacheBean> map=buildObjectiveAnswerCache(structJson, answerjson);
+            ObjectiveAnswerCacheUtil.saveObjectiveAnswerCache(examId, paperId, map);
+            ObjectiveAnswerCacheUtil.expireObjectiveAnswerCache(examId, timeOutHours);
+        } catch (Exception e) {
+            log.error("get struct/answer json error", e);
+            throw new RuntimeException(e);
+        }
     }
     }
 
 
-    @Cacheable(value = "objective_answer", key = "#paperId", unless = "#result == null")
     @Override
     @Override
     public Map<String, ObjectiveAnswerCacheBean> getObjectiveAnswerCacheBean(Long paperId) {
     public Map<String, ObjectiveAnswerCacheBean> getObjectiveAnswerCacheBean(Long paperId) {
         ExamPaperCacheBean ep = getExamPaperCacheBean(paperId);
         ExamPaperCacheBean ep = getExamPaperCacheBean(paperId);
         if (ep == null) {
         if (ep == null) {
             return null;
             return null;
         }
         }
+        Long examId=ep.getExamId();
         if (StringUtils.isBlank(ep.getAnswerPath())) {//没有答案文件
         if (StringUtils.isBlank(ep.getAnswerPath())) {//没有答案文件
             return null;
             return null;
         }
         }
+        Map<String, ObjectiveAnswerCacheBean> map=ObjectiveAnswerCacheUtil.getObjectiveAnswerCache(examId, paperId);
+        if(map!=null) {
+        	return map;
+        }
         try {
         try {
             String structJson = new String(ossUtil.download(false, ep.getStructPath()), StandardCharsets.UTF_8);
             String structJson = new String(ossUtil.download(false, ep.getStructPath()), StandardCharsets.UTF_8);
             String answerjson = new String(ossUtil.download(false, ep.getAnswerPath()), StandardCharsets.UTF_8);
             String answerjson = new String(ossUtil.download(false, ep.getAnswerPath()), StandardCharsets.UTF_8);
-            return buildObjectiveAnswerCache(structJson, answerjson);
+            map=buildObjectiveAnswerCache(structJson, answerjson);
+            ObjectiveAnswerCacheUtil.saveObjectiveAnswerCache(examId, paperId, map);
+            ObjectiveAnswerCacheUtil.expireObjectiveAnswerCache(examId, objectiveAnswerCacheTimeOutHours);
+            return map;
         } catch (Exception e) {
         } catch (Exception e) {
             log.error("get struct/answer json error", e);
             log.error("get struct/answer json error", e);
             throw new RuntimeException(e);
             throw new RuntimeException(e);
         }
         }
     }
     }
-
+    
     private Map<String, ObjectiveAnswerCacheBean> buildObjectiveAnswerCache(String structStr, String answerStr) {
     private Map<String, ObjectiveAnswerCacheBean> buildObjectiveAnswerCache(String structStr, String answerStr) {
         Map<String, ObjectiveAnswerCacheBean> map = new HashMap<String, ObjectiveAnswerCacheBean>();
         Map<String, ObjectiveAnswerCacheBean> map = new HashMap<String, ObjectiveAnswerCacheBean>();
         JSONObject answerJson = JSONObject.parseObject(answerStr);
         JSONObject answerJson = JSONObject.parseObject(answerStr);
@@ -224,10 +261,6 @@ public class TEExamPaperServiceImpl extends ServiceImpl<TEExamPaperMapper, TEExa
         return map;
         return map;
     }
     }
 
 
-    private String uuid() {
-        return UUID.randomUUID().toString().replaceAll("-", "");
-    }
-
     @Override
     @Override
     public List<TEExamPaper> findByExamIdAndCourseCode(Long examId, String courseCode) {
     public List<TEExamPaper> findByExamIdAndCourseCode(Long examId, String courseCode) {
         return teExamPaperMapper.findListByExamIdAndCourseCode(examId, courseCode);
         return teExamPaperMapper.findListByExamIdAndCourseCode(examId, courseCode);
@@ -236,11 +269,65 @@ public class TEExamPaperServiceImpl extends ServiceImpl<TEExamPaperMapper, TEExa
     @Transactional
     @Transactional
     @Override
     @Override
     public void savePaperWeight(Map<Long, Double> map) {
     public void savePaperWeight(Map<Long, Double> map) {
-        TEExamPaperService examPaperService = SpringContextHolder.getBean(TEExamPaperService.class);
         for (Long id : map.keySet()) {
         for (Long id : map.keySet()) {
             teExamPaperMapper.updateWeight(id, map.get(id));
             teExamPaperMapper.updateWeight(id, map.get(id));
+        }
+    }
+    
+    /**获取缓存过期时间,不满足条件的返回-1.条件:场次最小startTime在当天的,或者当前时间在场次最小startTime和最大finishTime之间的。
+     * @param examId
+     * @return
+     */
+    private Long getObjectiveAnswerCacheTimeOut(Long examId) {
+    	Long objectiveAnswerCacheTimeOut=-1L;
+    	List<Map<String, Long>> list=examActivityMapper.findMinStartTimeAndMaxFinshTimeByExamId(examId);
+    	if(list!=null&&list.size()>0) {
+    		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
+    		Date now=new Date();
+    		Long startTime=list.get(0).get("startTime");
+    		Long finishTime=list.get(0).get("finishTime");
+    		Date start=new Date(startTime);
+    		if(sdf.format(now).equals(sdf.format(start))||(now.getTime()>=startTime&&now.getTime()<=finishTime)) {
+    			objectiveAnswerCacheTimeOut=(finishTime-now.getTime())/(1000*60*60)+24;
+        	}
+    	}
+    	return objectiveAnswerCacheTimeOut;
+    }
+    
+    /**处理考试批次下的客观题答案缓存
+     * @param examId
+     */
+    @Override
+    public void disposeObjectiveAnswer(Long examId) {
+    	Long objectiveAnswerCacheTimeOut=getObjectiveAnswerCacheTimeOut(examId);
+    	if(objectiveAnswerCacheTimeOut>0) {
+    		List<TEExamPaper> list=teExamPaperMapper.findByExamId(examId);
+    		if(list!=null&&list.size()>0) {
+    			for(TEExamPaper paper:list) {
+    				if(ObjectiveAnswerCacheUtil.getObjectiveAnswerCache(examId, paper.getId())==null) {
+    					reloadObjectiveAnswerCacheBean(paper.getId(), objectiveAnswerCacheTimeOut);
+    				}
+    			}
+    		}
+    		Long count=ObjectiveAnswerCacheUtil.getHashCacheSize(examId);
+    		if(count!=null&&count>0) {
+    			ObjectiveAnswerCacheUtil.expireObjectiveAnswerCache(examId, objectiveAnswerCacheTimeOut);
+    		}
+    	}
+    }
+    
+    /**
+     *导入试卷时处理缓存
+     */
+    @Override
+    public void disposePaperCacheOnPaperImport(Long examId,List<Long> paperIds) {
+        TEExamPaperService examPaperService = SpringContextHolder.getBean(TEExamPaperService.class);
+        for (Long id : paperIds) {
             examPaperService.deleteExamPaperCacheBean(id);
             examPaperService.deleteExamPaperCacheBean(id);
-            examPaperService.deleteObjectiveAnswerCacheBean(id);
+            Long objectiveAnswerCacheTimeOut=getObjectiveAnswerCacheTimeOut(examId);
+            if(objectiveAnswerCacheTimeOut>0) {
+            	examPaperService.reloadObjectiveAnswerCacheBean(id,objectiveAnswerCacheTimeOut);
+            }
             examPaperService.deletePaperStructCacheBean(id);
             examPaperService.deletePaperStructCacheBean(id);
         }
         }
     }
     }

+ 232 - 62
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java

@@ -1,14 +1,68 @@
 package com.qmth.themis.business.service.impl;
 package com.qmth.themis.business.service.impl;
 
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.aliyun.oss.common.utils.BinaryUtil;
 import com.aliyun.oss.common.utils.BinaryUtil;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.themis.business.bean.admin.OpenExamBean;
 import com.qmth.themis.business.bean.admin.OpenExamBean;
-import com.qmth.themis.business.bean.exam.*;
-import com.qmth.themis.business.cache.*;
-import com.qmth.themis.business.cache.bean.*;
+import com.qmth.themis.business.bean.exam.AnswerSubmitBean;
+import com.qmth.themis.business.bean.exam.AudioLeftPlayCountSubmitBean;
+import com.qmth.themis.business.bean.exam.ExamFileUploadBean;
+import com.qmth.themis.business.bean.exam.ExamFinishBean;
+import com.qmth.themis.business.bean.exam.ExamPaperDownloadBean;
+import com.qmth.themis.business.bean.exam.ExamPrepareBean;
+import com.qmth.themis.business.bean.exam.ExamResultBean;
+import com.qmth.themis.business.bean.exam.ExamResumeBean;
+import com.qmth.themis.business.bean.exam.ExamStartBean;
+import com.qmth.themis.business.bean.exam.StudentPaperStructBean;
+import com.qmth.themis.business.cache.ExamActivityRecordCacheUtil;
+import com.qmth.themis.business.cache.ExamBreakCacheUtil;
+import com.qmth.themis.business.cache.ExamRecordCacheUtil;
+import com.qmth.themis.business.cache.ExamingDataCacheUtil;
+import com.qmth.themis.business.cache.RedisKeyHelper;
+import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
+import com.qmth.themis.business.cache.bean.ExamCacheBean;
+import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
+import com.qmth.themis.business.cache.bean.ExamPaperCacheBean;
+import com.qmth.themis.business.cache.bean.ExamStudentAnswerCacheBean;
+import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
+import com.qmth.themis.business.cache.bean.ExamStudentPaperStructCacheBean;
+import com.qmth.themis.business.cache.bean.ObjectiveAnswerCacheBean;
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dao.TEExamMapper;
 import com.qmth.themis.business.dao.TEExamMapper;
@@ -22,31 +76,41 @@ import com.qmth.themis.business.entity.TBSession;
 import com.qmth.themis.business.entity.TBTaskHistory;
 import com.qmth.themis.business.entity.TBTaskHistory;
 import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.entity.TOeExamRecord;
 import com.qmth.themis.business.entity.TOeExamRecord;
-import com.qmth.themis.business.enums.*;
-import com.qmth.themis.business.service.*;
-import com.qmth.themis.business.util.*;
+import com.qmth.themis.business.enums.ExamModeEnum;
+import com.qmth.themis.business.enums.ExamRecordStatusEnum;
+import com.qmth.themis.business.enums.FinishExamResultEnum;
+import com.qmth.themis.business.enums.FinishTypeEnum;
+import com.qmth.themis.business.enums.InvigilateMonitorStatusEnum;
+import com.qmth.themis.business.enums.InvigilateVerifyEnum;
+import com.qmth.themis.business.enums.MonitorStatusSourceEnum;
+import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
+import com.qmth.themis.business.enums.MqTagEnum;
+import com.qmth.themis.business.enums.ObjectiveScorePolicyEnum;
+import com.qmth.themis.business.enums.ReviewResultEnum;
+import com.qmth.themis.business.enums.ScoreStatusEnum;
+import com.qmth.themis.business.enums.SystemOperationEnum;
+import com.qmth.themis.business.enums.TaskStatusEnum;
+import com.qmth.themis.business.enums.WebsocketStatusEnum;
+import com.qmth.themis.business.service.MqDtoService;
+import com.qmth.themis.business.service.TBTaskHistoryService;
+import com.qmth.themis.business.service.TEExamActivityService;
+import com.qmth.themis.business.service.TEExamCourseService;
+import com.qmth.themis.business.service.TEExamPaperService;
+import com.qmth.themis.business.service.TEExamService;
+import com.qmth.themis.business.service.TEExamStudentService;
+import com.qmth.themis.business.service.TGErrorService;
+import com.qmth.themis.business.service.TOeExamBreakHistoryService;
+import com.qmth.themis.business.service.TOeExamRecordService;
+import com.qmth.themis.business.util.JacksonUtil;
+import com.qmth.themis.business.util.MqUtil;
+import com.qmth.themis.business.util.OssUtil;
+import com.qmth.themis.business.util.RedisUtil;
+import com.qmth.themis.business.util.ServletUtil;
+import com.qmth.themis.business.util.TencentYunUtil;
 import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.util.HexUtils;
 import com.qmth.themis.common.util.HexUtils;
 import com.qmth.themis.common.util.IpUtil;
 import com.qmth.themis.common.util.IpUtil;
-import org.springframework.beans.BeanUtils;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.CachePut;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.annotation.Resource;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigDecimal;
-import java.text.SimpleDateFormat;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 
 
 /**
 /**
  * @Description: 考试批次 服务实现类
  * @Description: 考试批次 服务实现类
@@ -119,7 +183,8 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
      * @param type
      * @param type
      * @return
      * @return
      */
      */
-    @Override
+    @SuppressWarnings("rawtypes")
+	@Override
     public IPage<TEExamQueryDto> examQuery(IPage<Map> iPage, Long userId, Long id, String code, String name,
     public IPage<TEExamQueryDto> examQuery(IPage<Map> iPage, Long userId, Long id, String code, String name,
                                            String mode, Integer enable, Long orgId, String type) {
                                            String mode, Integer enable, Long orgId, String type) {
         return teExamMapper.examQuery(iPage, userId, id, code, name, mode, enable, orgId, type);
         return teExamMapper.examQuery(iPage, userId, id, code, name, mode, enable, orgId, type);
@@ -616,28 +681,124 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
                 ExamRecordCacheUtil.getHasAnswerFile(recordId) :
                 ExamRecordCacheUtil.getHasAnswerFile(recordId) :
                 0;
                 0;
         if (hasAnswerFile.intValue() == 1) {
         if (hasAnswerFile.intValue() == 1) {
-            // 每次提交,清空得分
-            answerCache.setScore(null);
+        	calculateObjectiveScore(answerCache, recordId);
         }
         }
         // 更新考生作答
         // 更新考生作答
         redisUtil.set(RedisKeyHelper.examAnswerKey(recordId),
         redisUtil.set(RedisKeyHelper.examAnswerKey(recordId),
                 RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex), answerCache);
                 RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex), answerCache);
-        if (hasAnswerFile.intValue() == 1) {
-            // 如果是客观题,重置考试记录客观题得分
-            if (answerCache.getObjective()) {
-                ExamRecordCacheUtil.setObjectiveScore(recordId, null);
-                toeExamRecordService.sendExamRecordDataSaveMq(recordId, System.currentTimeMillis());
-                // 发消息计算客观分
-                calculateObjectiveScoreMsg(recordId, mainNumber, subNumber, subIndex);
-            }
-        }
 
 
         AnswerSubmitBean ret = new AnswerSubmitBean();
         AnswerSubmitBean ret = new AnswerSubmitBean();
         ret.setVersion(version);
         ret.setVersion(version);
 
 
         return ret;
         return ret;
     }
     }
+    
+    private void calculateObjectiveScore(ExamStudentAnswerCacheBean answer,Long recordId) {
+    	if(answer.getObjective()==null||!answer.getObjective()) {
+    		return;
+    	}
+    	answer.setScore(0.0);
+        Integer mainNumber = answer.getMainNumber();
+        Integer subNumber = answer.getSubNumber();
+        Integer subIndex = answer.getSubIndex();
+        Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
+        String key = RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex);
 
 
+        //整卷客观题标答缓存集合
+        Map<String, ObjectiveAnswerCacheBean> map = examPaperService.getObjectiveAnswerCacheBean(paperId);
+        if (map == null || map.size() == 0) {
+        	throw new BusinessException(ExceptionResultEnum.NOT_FOUND_PAPER_OBJECTIVE_ANSWER);
+        }
+        //客观题标答缓存
+        ObjectiveAnswerCacheBean cb = map.get(key);
+        if (cb == null) {
+        	throw new BusinessException(ExceptionResultEnum.NOT_FOUND_QUESTION_OBJECTIVE_ANSWER);
+        }
+
+        if (cb.getStructType().intValue() == 1) {
+            if (checkSingleChoice(answer.getAnswer(), cb.getChoiceAnswer())) {
+                answer.setScore(cb.getScore());
+            } else {
+                answer.setScore(0.0);
+            }
+        }
+        if (cb.getStructType().intValue() == 2) {
+            ExamCacheBean ec = getExamCacheBeanNative(ExamRecordCacheUtil.getExamId(recordId));
+            int r = checkMultipleChoice(answer.getAnswer(), cb.getChoiceAnswer());
+            if (ec.getObjectiveScorePolicy().equals(ObjectiveScorePolicyEnum.EQUAL)) {// 全对给分
+                if (r == 1) {
+                    answer.setScore(cb.getScore());
+                } else {
+                    answer.setScore(0.0);
+                }
+            }
+            if (ec.getObjectiveScorePolicy().equals(ObjectiveScorePolicyEnum.PARTIAL)) {// 漏选半分
+                if (r == 1) {
+                    answer.setScore(cb.getScore());
+                } else if (r == 0) {
+                    BigDecimal b = new BigDecimal(cb.getScore()).divide(new BigDecimal("2"), 1, BigDecimal.ROUND_UP);
+                    answer.setScore(b.doubleValue());
+                } else {
+                    answer.setScore(0.0);
+                }
+            }
+        }
+        if (cb.getStructType().intValue() == 3) {
+            if (StringUtils.isNotBlank(answer.getAnswer())) {
+                String answerStr = answer.getAnswer().replaceAll("\n", "");
+                if (StringUtils.isNotBlank(answerStr)) {
+                    if (Boolean.parseBoolean(answerStr) == cb.getBoolAnswer().booleanValue()) {
+                        answer.setScore(cb.getScore());
+                    } else {
+                        answer.setScore(0.0);
+                    }
+                }
+            }
+        }
+    }
+    private boolean checkSingleChoice(String answerArray, JSONArray ar) {
+        JSONArray an = JSONArray.parseArray(answerArray);
+        if (an.size() == 0) {
+            return false;
+        }
+        int a = an.getIntValue(0);
+        return checkSingleChoice(a, ar);
+    }
+
+    private boolean checkSingleChoice(int answer, JSONArray ar) {
+        for (int i = 0; i < ar.size(); i++) {
+            if (answer == ar.getIntValue(i)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param answer
+     * @param ar
+     * @return -1 有错选项,0-无措选项 未答全 1-全对
+     */
+    private int checkMultipleChoice(String answer, JSONArray ar) {
+        int yes = 0;
+        int no = 0;
+        JSONArray an = JSONArray.parseArray(answer);
+        for (int i = 0; i < an.size(); i++) {
+            if (checkSingleChoice(an.getIntValue(i), ar)) {
+                yes++;
+                continue;
+            } else {
+                no++;
+            }
+        }
+        if (yes == ar.size()) {
+            return 1;
+        }
+        if (yes != 0 && no == 0) {
+            return 0;
+        }
+        return -1;
+    }
     private boolean checkIsObjective(Long paperId, Integer mainNumber, Integer subNumber, Integer subIndex) {
     private boolean checkIsObjective(Long paperId, Integer mainNumber, Integer subNumber, Integer subIndex) {
         Map<String, ObjectiveAnswerCacheBean> map = examPaperService.getObjectiveAnswerCacheBean(paperId);
         Map<String, ObjectiveAnswerCacheBean> map = examPaperService.getObjectiveAnswerCacheBean(paperId);
         if (map == null || map.size() == 0) {
         if (map == null || map.size() == 0) {
@@ -651,19 +812,6 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         return true;
         return true;
     }
     }
 
 
-    //考试中计算客观分消息
-    private void calculateObjectiveScoreMsg(Long recordId, Integer mainNumber, Integer subNumber, Integer subIndex) {
-        Map<String, Object> transMap = new HashMap<String, Object>();
-        transMap.put("recordId", recordId);
-        transMap.put("mainNumber", mainNumber);
-        transMap.put("subNumber", subNumber);
-        transMap.put("subIndex", subIndex);
-        // mq发送消息start
-        MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.CALCULATE_OBJECTIVE_SCORE.name(),
-                transMap, MqTagEnum.CALCULATE_OBJECTIVE_SCORE, recordId.toString(), recordId.toString());
-        mqDtoService.assembleSendOneWayMsg(mqDto);
-    }
-
     /**
     /**
      * 更新音频剩余播放次数
      * 更新音频剩余播放次数
      */
      */
@@ -926,18 +1074,30 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
             redisUtil.releaseLock(lockKey);
             redisUtil.releaseLock(lockKey);
         }
         }
     }
     }
+    
+    @SuppressWarnings("unchecked")
+	private Double calculateTotalObjectiveScore(Long recordId) {
+    	Double total = 0.0;
+    	Map<String, ExamStudentAnswerCacheBean> as = redisUtil.getHashEntries(RedisKeyHelper.examAnswerKey(recordId));
+        if (as != null && as.size() > 0) {
+            for (ExamStudentAnswerCacheBean sa : as.values()) {
+                if (sa.getObjective() != null && sa.getObjective()) {//是客观题
+                    if (sa.getScore() != null) {//有分值
+                        total = total + sa.getScore();
+                    } 
+                }
+            }
+        }
+        ExamRecordCacheUtil.setObjectiveScore(recordId, total);
+        return total;
+    }
 
 
     private ExamFinishBean diposeFinish(Long studentId, Long recordId, String type, Integer durationSeconds) {
     private ExamFinishBean diposeFinish(Long studentId, Long recordId, String type, Integer durationSeconds) {
-        Date now = new Date();
-        ExamFinishBean ret = new ExamFinishBean();
-        ret.setFinishTime(now.getTime());
-        ret.setObjectiveScore(ExamRecordCacheUtil.getObjectiveScore(recordId));
-        Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
-        if (ExamRecordCacheUtil.getId(recordId) == null || examStudentId == null) {
-            ret.setStatus(FinishExamResultEnum.NORMAL);
-            return ret;
-        }
+    	Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
         // 校验当前登录用户和参数一致性
         // 校验当前登录用户和参数一致性
+    	if(examStudentId==null) {
+    		throw new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD);
+    	}
         ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
         ExamStudentCacheBean es = (ExamStudentCacheBean) redisUtil
                 .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
                 .get(RedisKeyHelper.examStudentCacheKey(examStudentId));
         if (es == null) {
         if (es == null) {
@@ -946,6 +1106,17 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         if (!studentId.equals(es.getStudentId())) {
         if (!studentId.equals(es.getStudentId())) {
             throw new BusinessException(ExceptionResultEnum.EXAM_ID_NOT_EQUALY);
             throw new BusinessException(ExceptionResultEnum.EXAM_ID_NOT_EQUALY);
         }
         }
+        
+        Date now = new Date();
+        ExamFinishBean ret = new ExamFinishBean();
+        ret.setFinishTime(now.getTime());
+        ret.setObjectiveScore(calculateTotalObjectiveScore(recordId));
+        
+        if (ExamRecordCacheUtil.getId(recordId) == null || examStudentId == null) {
+            ret.setStatus(FinishExamResultEnum.NORMAL);
+            return ret;
+        }
+
 
 
         ExamCacheBean exam = getExamCacheBeanNative(es.getExamId());
         ExamCacheBean exam = getExamCacheBeanNative(es.getExamId());
         ret.setPostNotice(exam.getPostNotice());
         ret.setPostNotice(exam.getPostNotice());
@@ -967,9 +1138,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
                             1 :
                             1 :
                             ExamRecordCacheUtil.getBreachStatus(recordId);
                             ExamRecordCacheUtil.getBreachStatus(recordId);
                     if (warningCount != null && warningCount.intValue() > 0) {//有预警
                     if (warningCount != null && warningCount.intValue() > 0) {//有预警
-                        if (breachStatus == null) {//无违纪结果
-                            ret.setStatus(FinishExamResultEnum.AUDITING);
-                        } else if (breachStatus.intValue() == 0) {//违纪结果是false
+                        if (breachStatus.intValue() == 0) {//违纪结果是false
                             ret.setReviewResult(ReviewResultEnum.PASS);
                             ret.setReviewResult(ReviewResultEnum.PASS);
                             if (ret.getObjectiveScore() == null) {
                             if (ret.getObjectiveScore() == null) {
                                 ret.setStatus(FinishExamResultEnum.SCORE_CALCULATE);
                                 ret.setStatus(FinishExamResultEnum.SCORE_CALCULATE);
@@ -1206,7 +1375,8 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
      * @param orgId
      * @param orgId
      * @return
      * @return
      */
      */
-    @Override
+    @SuppressWarnings("rawtypes")
+	@Override
     public List<Map> examList(Long userId, Long orgId) {
     public List<Map> examList(Long userId, Long orgId) {
         return teExamMapper.examList(userId, orgId);
         return teExamMapper.examList(userId, orgId);
     }
     }

+ 169 - 162
themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java

@@ -99,7 +99,8 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
      * @param orgId
      * @param orgId
      * @return
      * @return
      */
      */
-    @Override
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+	@Override
     public Map getUnFinishExam(Long studentId, Long examId, Long orgId) {
     public Map getUnFinishExam(Long studentId, Long examId, Long orgId) {
         TEExamUnFinishDto teExamUnFinishDto = tOeExamRecordMapper.getUnFinishExam(studentId, examId, orgId);
         TEExamUnFinishDto teExamUnFinishDto = tOeExamRecordMapper.getUnFinishExam(studentId, examId, orgId);
         if (Objects.nonNull(teExamUnFinishDto)) {
         if (Objects.nonNull(teExamUnFinishDto)) {
@@ -192,163 +193,163 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
     /**
     /**
      * 计算客观分
      * 计算客观分
      */
      */
-    @Override
-    public void calculateObjectiveScore(Map<String, Object> param) {
-        Long recordId = (Long) param.get("recordId");
-        Integer mainNumber = (Integer) param.get("mainNumber");
-        Integer subNumber = (Integer) param.get("subNumber");
-        Integer subIndex = (Integer) param.get("subIndex");
-        Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
-        String key = RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex);
-
-        //考生作答缓存
-        ExamStudentAnswerCacheBean answer = (ExamStudentAnswerCacheBean) redisUtil
-                .get(RedisKeyHelper.examAnswerKey(recordId), key);
-        if (answer == null) {
-            log.error("no ExamStudentAnswerCacheBean for calculateObjectiveScore recordId:" + recordId + " key:" + key);
-
-            // 计算客观分总分
-            calculateTotalObjectiveScore(param);
-            return;
-        }
-        //整卷客观题标答缓存集合
-        Map<String, ObjectiveAnswerCacheBean> map = examPaperService.getObjectiveAnswerCacheBean(paperId);
-        if (map == null || map.size() == 0) {
-            log.info("no ObjectiveAnswerCacheBean map for calculateObjectiveScore recordId:" + recordId + " paperId:"
-                    + paperId);
-            // 更新分数
-            answer.setScore(0.0);
-            redisUtil.set(RedisKeyHelper.examAnswerKey(recordId), key, answer);
-
-            // 计算客观分总分
-            calculateTotalObjectiveScore(param);
-            return;
-        }
-        //客观题标答缓存
-        ObjectiveAnswerCacheBean cb = map.get(key);
-        if (cb == null) {
-            log.info("no ObjectiveAnswerCacheBean for calculateObjectiveScore recordId:" + recordId + " key:" + key);
-            // 更新分数
-            answer.setScore(0.0);
-            redisUtil.set(RedisKeyHelper.examAnswerKey(recordId), key, answer);
-
-            // 计算客观分总分
-            calculateTotalObjectiveScore(param);
-            return;
-        }
-
-        if (cb.getStructType().intValue() == 1) {
-            if (checkSingleChoice(answer.getAnswer(), cb.getChoiceAnswer())) {
-                answer.setScore(cb.getScore());
-            } else {
-                answer.setScore(0.0);
-            }
-        }
-        if (cb.getStructType().intValue() == 2) {
-            ExamCacheBean ec = examService.getExamCacheBean(ExamRecordCacheUtil.getExamId(recordId));
-            int r = checkMultipleChoice(answer.getAnswer(), cb.getChoiceAnswer());
-            if (ec.getObjectiveScorePolicy().equals(ObjectiveScorePolicyEnum.EQUAL)) {// 全对给分
-                if (r == 1) {
-                    answer.setScore(cb.getScore());
-                } else {
-                    answer.setScore(0.0);
-                }
-            }
-            if (ec.getObjectiveScorePolicy().equals(ObjectiveScorePolicyEnum.PARTIAL)) {// 漏选半分
-                if (r == 1) {
-                    answer.setScore(cb.getScore());
-                } else if (r == 0) {
-                    BigDecimal b = new BigDecimal(cb.getScore()).divide(new BigDecimal("2"), 1, BigDecimal.ROUND_UP);
-                    answer.setScore(b.doubleValue());
-                } else {
-                    answer.setScore(0.0);
-                }
-            }
-        }
-        if (cb.getStructType().intValue() == 3) {
-            if (StringUtils.isNotBlank(answer.getAnswer())) {
-                String answerStr = answer.getAnswer().replaceAll("\n", "");
-                if (StringUtils.isNotBlank(answerStr)) {
-                    if (Boolean.parseBoolean(answerStr) == cb.getBoolAnswer().booleanValue()) {
-                        answer.setScore(cb.getScore());
-                    } else {
-                        answer.setScore(0.0);
-                    }
-                }
-            }
-        }
-
-        if (answer.getScore() == null) {
-            log.info("小题分数为空,得分置为0," + "recordId:" + recordId + " questionKey:" + key);
-            answer.setScore(0.0);
-        }
-        // 更新分数
-        redisUtil.set(RedisKeyHelper.examAnswerKey(recordId), key, answer);
-
-        // 计算客观分总分
-        calculateTotalObjectiveScore(param);
-    }
-
-    @SuppressWarnings("unchecked")
-    private void calculateTotalObjectiveScore(Map<String, Object> param) {
-        Long recordId = (Long) param.get("recordId");
-        Integer mainNumber = (Integer) param.get("mainNumber");
-        Integer subNumber = (Integer) param.get("subNumber");
-        Integer subIndex = (Integer) param.get("subIndex");
-        String lockKey = SystemConstant.REDIS_LOCK_TOTAL_OBJECTIVE_SCORE_PREFIX + recordId;
-        try {
-            String key = RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex);
-            Boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_CACHE_TIME_OUT);
-            if (lock) {
-                log.info("calculateTotalObjectiveScore get lock sucss recordId:" + recordId + " key:" + key);
-                Map<String, ExamStudentAnswerCacheBean> as = redisUtil
-                        .getHashEntries(RedisKeyHelper.examAnswerKey(recordId));
-                if (as != null && as.size() > 0) {
-                    Double total = 0.0;
-                    for (ExamStudentAnswerCacheBean sa : as.values()) {
-                        if (sa.getObjective() != null && sa.getObjective()) {//是客观题
-                            if (sa.getScore() != null) {//有分值
-                                total = total + sa.getScore();
-                            } else {
-                                log.info(
-                                        "calculateTotalObjectiveScore ExamStudentAnswerCacheBean Score is null recordId:"
-                                                + recordId + " key:" + RedisKeyHelper
-                                                .examAnswerHashKey(sa.getMainNumber(), sa.getSubNumber(),
-                                                        sa.getSubIndex()));
-                                total = null;
-                                break;
-                            }
-                        }
-                    }
-                    if (total != null) {
-                        ExamRecordCacheUtil.setObjectiveScore(recordId, total);
-                        this.sendExamRecordDataSaveMq(recordId, System.currentTimeMillis());
-                    } else {
-                        log.info("calculateTotalObjectiveScore total Score is null recordId:" + recordId + " key:"
-                                + key);
-                    }
-                }
-            } else {
-                log.info("calculateTotalObjectiveScore get lock faild recordId:" + recordId + " key:" + key);
-                calculateObjectiveScoreMsg(recordId, mainNumber, subNumber, subIndex);
-            }
-        } finally {
-            redisUtil.releaseLock(lockKey);
-        }
-    }
+//    @Override
+//    public void calculateObjectiveScore(Map<String, Object> param) {
+//        Long recordId = (Long) param.get("recordId");
+//        Integer mainNumber = (Integer) param.get("mainNumber");
+//        Integer subNumber = (Integer) param.get("subNumber");
+//        Integer subIndex = (Integer) param.get("subIndex");
+//        Long paperId = ExamRecordCacheUtil.getPaperId(recordId);
+//        String key = RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex);
+//
+//        //考生作答缓存
+//        ExamStudentAnswerCacheBean answer = (ExamStudentAnswerCacheBean) redisUtil
+//                .get(RedisKeyHelper.examAnswerKey(recordId), key);
+//        if (answer == null) {
+//            log.error("no ExamStudentAnswerCacheBean for calculateObjectiveScore recordId:" + recordId + " key:" + key);
+//
+//            // 计算客观分总分
+//            calculateTotalObjectiveScore(param);
+//            return;
+//        }
+//        //整卷客观题标答缓存集合
+//        Map<String, ObjectiveAnswerCacheBean> map = examPaperService.getObjectiveAnswerCacheBean(paperId);
+//        if (map == null || map.size() == 0) {
+//            log.info("no ObjectiveAnswerCacheBean map for calculateObjectiveScore recordId:" + recordId + " paperId:"
+//                    + paperId);
+//            // 更新分数
+//            answer.setScore(0.0);
+//            redisUtil.set(RedisKeyHelper.examAnswerKey(recordId), key, answer);
+//
+//            // 计算客观分总分
+//            calculateTotalObjectiveScore(param);
+//            return;
+//        }
+//        //客观题标答缓存
+//        ObjectiveAnswerCacheBean cb = map.get(key);
+//        if (cb == null) {
+//            log.info("no ObjectiveAnswerCacheBean for calculateObjectiveScore recordId:" + recordId + " key:" + key);
+//            // 更新分数
+//            answer.setScore(0.0);
+//            redisUtil.set(RedisKeyHelper.examAnswerKey(recordId), key, answer);
+//
+//            // 计算客观分总分
+//            calculateTotalObjectiveScore(param);
+//            return;
+//        }
+//
+//        if (cb.getStructType().intValue() == 1) {
+//            if (checkSingleChoice(answer.getAnswer(), cb.getChoiceAnswer())) {
+//                answer.setScore(cb.getScore());
+//            } else {
+//                answer.setScore(0.0);
+//            }
+//        }
+//        if (cb.getStructType().intValue() == 2) {
+//            ExamCacheBean ec = examService.getExamCacheBean(ExamRecordCacheUtil.getExamId(recordId));
+//            int r = checkMultipleChoice(answer.getAnswer(), cb.getChoiceAnswer());
+//            if (ec.getObjectiveScorePolicy().equals(ObjectiveScorePolicyEnum.EQUAL)) {// 全对给分
+//                if (r == 1) {
+//                    answer.setScore(cb.getScore());
+//                } else {
+//                    answer.setScore(0.0);
+//                }
+//            }
+//            if (ec.getObjectiveScorePolicy().equals(ObjectiveScorePolicyEnum.PARTIAL)) {// 漏选半分
+//                if (r == 1) {
+//                    answer.setScore(cb.getScore());
+//                } else if (r == 0) {
+//                    BigDecimal b = new BigDecimal(cb.getScore()).divide(new BigDecimal("2"), 1, BigDecimal.ROUND_UP);
+//                    answer.setScore(b.doubleValue());
+//                } else {
+//                    answer.setScore(0.0);
+//                }
+//            }
+//        }
+//        if (cb.getStructType().intValue() == 3) {
+//            if (StringUtils.isNotBlank(answer.getAnswer())) {
+//                String answerStr = answer.getAnswer().replaceAll("\n", "");
+//                if (StringUtils.isNotBlank(answerStr)) {
+//                    if (Boolean.parseBoolean(answerStr) == cb.getBoolAnswer().booleanValue()) {
+//                        answer.setScore(cb.getScore());
+//                    } else {
+//                        answer.setScore(0.0);
+//                    }
+//                }
+//            }
+//        }
+//
+//        if (answer.getScore() == null) {
+//            log.info("小题分数为空,得分置为0," + "recordId:" + recordId + " questionKey:" + key);
+//            answer.setScore(0.0);
+//        }
+//        // 更新分数
+//        redisUtil.set(RedisKeyHelper.examAnswerKey(recordId), key, answer);
+//
+//        // 计算客观分总分
+//        calculateTotalObjectiveScore(param);
+//    }
+
+//    @SuppressWarnings("unchecked")
+//    private void calculateTotalObjectiveScore(Map<String, Object> param) {
+//        Long recordId = (Long) param.get("recordId");
+//        Integer mainNumber = (Integer) param.get("mainNumber");
+//        Integer subNumber = (Integer) param.get("subNumber");
+//        Integer subIndex = (Integer) param.get("subIndex");
+//        String lockKey = SystemConstant.REDIS_LOCK_TOTAL_OBJECTIVE_SCORE_PREFIX + recordId;
+//        try {
+//            String key = RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex);
+//            Boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_CACHE_TIME_OUT);
+//            if (lock) {
+//                log.info("calculateTotalObjectiveScore get lock sucss recordId:" + recordId + " key:" + key);
+//                Map<String, ExamStudentAnswerCacheBean> as = redisUtil
+//                        .getHashEntries(RedisKeyHelper.examAnswerKey(recordId));
+//                if (as != null && as.size() > 0) {
+//                    Double total = 0.0;
+//                    for (ExamStudentAnswerCacheBean sa : as.values()) {
+//                        if (sa.getObjective() != null && sa.getObjective()) {//是客观题
+//                            if (sa.getScore() != null) {//有分值
+//                                total = total + sa.getScore();
+//                            } else {
+//                                log.info(
+//                                        "calculateTotalObjectiveScore ExamStudentAnswerCacheBean Score is null recordId:"
+//                                                + recordId + " key:" + RedisKeyHelper
+//                                                .examAnswerHashKey(sa.getMainNumber(), sa.getSubNumber(),
+//                                                        sa.getSubIndex()));
+//                                total = null;
+//                                break;
+//                            }
+//                        }
+//                    }
+//                    if (total != null) {
+//                        ExamRecordCacheUtil.setObjectiveScore(recordId, total);
+//                        this.sendExamRecordDataSaveMq(recordId, System.currentTimeMillis());
+//                    } else {
+//                        log.info("calculateTotalObjectiveScore total Score is null recordId:" + recordId + " key:"
+//                                + key);
+//                    }
+//                }
+//            } else {
+//                log.info("calculateTotalObjectiveScore get lock faild recordId:" + recordId + " key:" + key);
+//                calculateObjectiveScoreMsg(recordId, mainNumber, subNumber, subIndex);
+//            }
+//        } finally {
+//            redisUtil.releaseLock(lockKey);
+//        }
+//    }
 
 
     //考试中计算客观分消息
     //考试中计算客观分消息
-    private void calculateObjectiveScoreMsg(Long recordId, Integer mainNumber, Integer subNumber, Integer subIndex) {
-        Map<String, Object> transMap = new HashMap<String, Object>();
-        transMap.put("recordId", recordId);
-        transMap.put("mainNumber", mainNumber);
-        transMap.put("subNumber", subNumber);
-        transMap.put("subIndex", subIndex);
-        Map<String, Object> propMap = mqDtoService.buildMqDelayMsg("1s");
-        MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.CALCULATE_OBJECTIVE_SCORE.name(),
-                transMap, MqTagEnum.CALCULATE_OBJECTIVE_SCORE, recordId.toString(), propMap, recordId.toString());
-        mqDtoService.assembleSendAsyncDelayMsg(mqDto);
-    }
+//    private void calculateObjectiveScoreMsg(Long recordId, Integer mainNumber, Integer subNumber, Integer subIndex) {
+//        Map<String, Object> transMap = new HashMap<String, Object>();
+//        transMap.put("recordId", recordId);
+//        transMap.put("mainNumber", mainNumber);
+//        transMap.put("subNumber", subNumber);
+//        transMap.put("subIndex", subIndex);
+//        Map<String, Object> propMap = mqDtoService.buildMqDelayMsg("1s");
+//        MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.CALCULATE_OBJECTIVE_SCORE.name(),
+//                transMap, MqTagEnum.CALCULATE_OBJECTIVE_SCORE, recordId.toString(), propMap, recordId.toString());
+//        mqDtoService.assembleSendAsyncDelayMsg(mqDto);
+//    }
 
 
     private boolean checkSingleChoice(String answerArray, JSONArray ar) {
     private boolean checkSingleChoice(String answerArray, JSONArray ar) {
         JSONArray an = JSONArray.parseArray(answerArray);
         JSONArray an = JSONArray.parseArray(answerArray);
@@ -614,7 +615,8 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
      * @param userId
      * @param userId
      * @return
      * @return
      */
      */
-    @Override
+    @SuppressWarnings("rawtypes")
+	@Override
     public IPage<InvigilateListBean> invigilatePageList(IPage<Map> iPage, Long examId, Long examActivityId,
     public IPage<InvigilateListBean> invigilatePageList(IPage<Map> iPage, Long examId, Long examActivityId,
                                                         String roomCode, Integer paperDownload, String status, String name, String identity,
                                                         String roomCode, Integer paperDownload, String status, String name, String identity,
                                                         Integer minWarningCount, Integer maxWarningCount, String clientWebsocketStatus, String monitorStatusSource,
                                                         Integer minWarningCount, Integer maxWarningCount, String clientWebsocketStatus, String monitorStatusSource,
@@ -642,7 +644,8 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
      * @param orgId
      * @param orgId
      * @return
      * @return
      */
      */
-    @Override
+    @SuppressWarnings("rawtypes")
+	@Override
     public IPage<InvigilateListVideoBean> invigilatePageListVideo(IPage<Map> iPage, Long examId, Long examActivityId,
     public IPage<InvigilateListVideoBean> invigilatePageListVideo(IPage<Map> iPage, Long examId, Long examActivityId,
                                                                   String roomCode, Integer paperDownload, String status, String name, String identity,
                                                                   String roomCode, Integer paperDownload, String status, String name, String identity,
                                                                   Integer minWarningCount, Integer maxWarningCount, String clientWebsocketStatus, Long userId, Long orgId) {
                                                                   Integer minWarningCount, Integer maxWarningCount, String clientWebsocketStatus, Long userId, Long orgId) {
@@ -687,7 +690,8 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
      * @param orgId
      * @param orgId
      * @return
      * @return
      */
      */
-    @Override
+    @SuppressWarnings("rawtypes")
+	@Override
     public IPage<InvigilateListPatrolBean> invigilatePagePatrolList(IPage<Map> iPage, Long examId, Long examActivityId,
     public IPage<InvigilateListPatrolBean> invigilatePagePatrolList(IPage<Map> iPage, Long examId, Long examActivityId,
                                                                     String roomCode, String status, String name, String identity, Integer minMultipleFaceCount,
                                                                     String roomCode, String status, String name, String identity, Integer minMultipleFaceCount,
                                                                     Integer maxMultipleFaceCount, Integer minExceptionCount, Integer maxExceptionCount, Integer minWarningCount,
                                                                     Integer maxMultipleFaceCount, Integer minExceptionCount, Integer maxExceptionCount, Integer minWarningCount,
@@ -718,7 +722,8 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
      * @param orgId
      * @param orgId
      * @return
      * @return
      */
      */
-    @Override
+    @SuppressWarnings("rawtypes")
+	@Override
     public IPage<InvigilateListWarningBean> invigilatePageWarningList(IPage<Map> iPage, Long examId,
     public IPage<InvigilateListWarningBean> invigilatePageWarningList(IPage<Map> iPage, Long examId,
                                                                       Long examActivityId, String roomCode, Integer approveStatus, String name, String identity,
                                                                       Long examActivityId, String roomCode, Integer approveStatus, String name, String identity,
                                                                       Integer minMultipleFaceCount, Integer maxMultipleFaceCount, Integer minExceptionCount,
                                                                       Integer minMultipleFaceCount, Integer maxMultipleFaceCount, Integer minExceptionCount,
@@ -772,7 +777,8 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
      * @param userId
      * @param userId
      * @return
      * @return
      */
      */
-    @Override
+    @SuppressWarnings("rawtypes")
+	@Override
     public IPage<InvigilateListProgressBean> invigilatePageProgressList(IPage<Map> iPage, Long examId,
     public IPage<InvigilateListProgressBean> invigilatePageProgressList(IPage<Map> iPage, Long examId,
                                                                         Long examActivityId, String roomCode, String courseCode, String name, String identity, Long userId,
                                                                         Long examActivityId, String roomCode, String courseCode, String name, String identity, Long userId,
                                                                         Long orgId) {
                                                                         Long orgId) {
@@ -825,7 +831,8 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
      * @param orgId
      * @param orgId
      * @return
      * @return
      */
      */
-    @Override
+    @SuppressWarnings("rawtypes")
+	@Override
     public IPage<InvigilateListHistoryBean> invigilatePageListHistory(IPage<Map> iPage, Long examId,
     public IPage<InvigilateListHistoryBean> invigilatePageListHistory(IPage<Map> iPage, Long examId,
                                                                       Long examActivityId, String roomCode, String courseCode, String status, Integer breachStatus,
                                                                       Long examActivityId, String roomCode, String courseCode, String status, Integer breachStatus,
                                                                       String finishType, String name, String identity, Integer minMultipleFaceCount, Integer maxMultipleFaceCount,
                                                                       String finishType, String name, String identity, Integer minMultipleFaceCount, Integer maxMultipleFaceCount,

+ 7 - 2
themis-business/src/main/java/com/qmth/themis/business/templete/impl/TaskExamPaperImportTemplete.java

@@ -168,10 +168,11 @@ public class TaskExamPaperImportTemplete implements TaskImportTemplete {
         if (course == null) {
         if (course == null) {
             throw new BusinessException("科目编码不存在 " + courseCode);
             throw new BusinessException("科目编码不存在 " + courseCode);
         }
         }
+        List<Long> paperIds=new ArrayList<Long>();
         File[] childs = courseDir.listFiles();
         File[] childs = courseDir.listFiles();
         for (File paperDir : childs) {
         for (File paperDir : childs) {
             if (paperDir.isDirectory()) {
             if (paperDir.isDirectory()) {
-                disposePaperDir(rootDir, teExam, course, paperDir, map);
+                disposePaperDir(rootDir, teExam, course, paperDir, map,paperIds);
             }
             }
         }
         }
         Boolean objectiveShuffle = (Boolean) map.get("objectiveShuffle");
         Boolean objectiveShuffle = (Boolean) map.get("objectiveShuffle");
@@ -207,6 +208,9 @@ public class TaskExamPaperImportTemplete implements TaskImportTemplete {
         teExamCourseService.saveOrUpdate(course);
         teExamCourseService.saveOrUpdate(course);
         // 设置调卷比例
         // 设置调卷比例
         teExamPaperService.savePaperWeight(paperWeight(list));
         teExamPaperService.savePaperWeight(paperWeight(list));
+        
+        //处理试卷缓存
+        teExamPaperService.disposePaperCacheOnPaperImport(teExam.getId(),paperIds);
 
 
         //清除考试科目缓存
         //清除考试科目缓存
         teExamCourseService.deleteExamCourseCacheBean(teExam.getId(), courseCode);
         teExamCourseService.deleteExamCourseCacheBean(teExam.getId(), courseCode);
@@ -230,7 +234,7 @@ public class TaskExamPaperImportTemplete implements TaskImportTemplete {
     }
     }
 
 
     private void disposePaperDir(String rootDir, TEExam teExam, TEExamCourse course, File paperDir,
     private void disposePaperDir(String rootDir, TEExam teExam, TEExamCourse course, File paperDir,
-                                 Map<String, Object> map) throws IOException {
+                                 Map<String, Object> map,List<Long> paperIds) throws IOException {
         String paperCode = paperDir.getName();
         String paperCode = paperDir.getName();
         File[] childs = paperDir.listFiles();
         File[] childs = paperDir.listFiles();
 
 
@@ -289,6 +293,7 @@ public class TaskExamPaperImportTemplete implements TaskImportTemplete {
         Integer audioPlayCount = (Integer) map.get("audioPlayCount");
         Integer audioPlayCount = (Integer) map.get("audioPlayCount");
         paper.setAudioPlayCount(audioPlayCount);
         paper.setAudioPlayCount(audioPlayCount);
         teExamPaperService.saveOrUpdate(paper);
         teExamPaperService.saveOrUpdate(paper);
+        paperIds.add(paper.getId());
     }
     }
 
 
     private void disposeViewPaper(String rootDir, TEExamPaper paper, File paperFile, File attachmentDir)
     private void disposeViewPaper(String rootDir, TEExamPaper paper, File paperFile, File attachmentDir)

+ 8 - 0
themis-business/src/main/java/com/qmth/themis/business/util/RedisUtil.java

@@ -372,6 +372,14 @@ public class RedisUtil {
     public void expire(String key, int timeOutSecond) {
     public void expire(String key, int timeOutSecond) {
         redisTemplate.expire(key, timeOutSecond, TimeUnit.SECONDS);
         redisTemplate.expire(key, timeOutSecond, TimeUnit.SECONDS);
     }
     }
+    
+    /**设置过期时间
+     * @param key
+     * @param timeOut
+     */
+    public void expire(String key, long timeOut,TimeUnit timeUnit) {
+        redisTemplate.expire(key, timeOut, timeUnit);
+    }
 
 
     /**
     /**
      * 获取redis序列
      * 获取redis序列

+ 12 - 0
themis-business/src/main/resources/mapper/TEExamActivityMapper.xml

@@ -197,4 +197,16 @@
             and f.org_id=#{orgId}
             and f.org_id=#{orgId}
         </if>
         </if>
     </select>
     </select>
+    
+    <select id="findMinStartTimeAndMaxFinshTimeByExamId" resultType="java.util.Map" >
+        select min(t.start_time) startTime,max(t.finish_time) finishTime from t_e_exam_activity t
+        where t.exam_id=#{examId} and t.enable=1
+    </select>
+    
+    <select id="findExamIdToday" resultType="java.lang.Long" >
+        select distinct t.exam_id  from t_e_exam_activity t
+        left join t_e_exam f on t.exam_id=f.id
+        where t.start_time&gt;=#{startTime} and t.start_time&lt;=#{endTime} and t.enable=1 and f.enable=1
+    </select>
+    
 </mapper>
 </mapper>

+ 6 - 0
themis-business/src/main/resources/mapper/TEExamPaperMapper.xml

@@ -21,4 +21,10 @@
 		update t_e_exam_paper t set t.weight=#{weight} where t.id=#{id}
 		update t_e_exam_paper t set t.weight=#{weight} where t.id=#{id}
 	</update>
 	</update>
 	
 	
+	<select id="findByExamId"
+		resultType="com.qmth.themis.business.entity.TEExamPaper">
+		select * from t_e_exam_paper t
+		where t.exam_id=#{examId}
+	</select>
+	
 </mapper>
 </mapper>

+ 4 - 0
themis-common/src/main/java/com/qmth/themis/common/enums/ExceptionResultEnum.java

@@ -52,6 +52,10 @@ public enum ExceptionResultEnum {
     MOBILE_FIRST_OFFLINE(500,500039,"移动端第一机位离线"),
     MOBILE_FIRST_OFFLINE(500,500039,"移动端第一机位离线"),
 
 
     MOBILE_SECOND_OFFLINE(500,500040,"移动端第二机位离线"),
     MOBILE_SECOND_OFFLINE(500,500040,"移动端第二机位离线"),
+    
+    NOT_FOUND_PAPER_OBJECTIVE_ANSWER(500,500041,"未找到试卷客观题答案"),
+    
+    NOT_FOUND_QUESTION_OBJECTIVE_ANSWER(500,500042,"未找到小题客观题答案"),
 
 
     /**
     /**
      * 系统预置
      * 系统预置

+ 1 - 1
themis-mq/src/main/java/com/qmth/themis/mq/service/MqLogicService.java

@@ -63,7 +63,7 @@ public interface MqLogicService {
      * @param mqDto
      * @param mqDto
      * @param key
      * @param key
      */
      */
-    public void execMqCalculateObjectiveScoreLogic(MqDto mqDto, String key);
+//    public void execMqCalculateObjectiveScoreLogic(MqDto mqDto, String key);
 
 
     /**
     /**
      * 人脸验证保存
      * 人脸验证保存

+ 12 - 12
themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java

@@ -306,18 +306,18 @@ public class MqLogicServiceImpl implements MqLogicService {
      * @param mqDto
      * @param mqDto
      * @param key
      * @param key
      */
      */
-    @Override
-    @Transactional
-    public void execMqCalculateObjectiveScoreLogic(MqDto mqDto, String key) {
-        Gson gson = new Gson();
-        Map<String, Object> param = (Map<String, Object>) mqDto.getBody();
-        examRecordService.calculateObjectiveScore(param);
-        mqDto.setAck(SystemConstant.STANDARD_ACK_TYPE);
-        TMRocketMessage tmRocketMessage = gson.fromJson(gson.toJson(mqDto), TMRocketMessage.class);
-        tmRocketMessage.setBody(JacksonUtil.parseJson(tmRocketMessage.getBody()));
-        tmRocketMessageService.saveOrUpdate(tmRocketMessage);
-        redisUtil.delete(key, mqDto.getId());
-    }
+//    @Override
+//    @Transactional
+//    public void execMqCalculateObjectiveScoreLogic(MqDto mqDto, String key) {
+//        Gson gson = new Gson();
+//        Map<String, Object> param = (Map<String, Object>) mqDto.getBody();
+//        examRecordService.calculateObjectiveScore(param);
+//        mqDto.setAck(SystemConstant.STANDARD_ACK_TYPE);
+//        TMRocketMessage tmRocketMessage = gson.fromJson(gson.toJson(mqDto), TMRocketMessage.class);
+//        tmRocketMessage.setBody(JacksonUtil.parseJson(tmRocketMessage.getBody()));
+//        tmRocketMessageService.saveOrUpdate(tmRocketMessage);
+//        redisUtil.delete(key, mqDto.getId());
+//    }
 
 
     /**
     /**
      * 人脸验证保存
      * 人脸验证保存

+ 7 - 7
themis-mq/src/main/java/com/qmth/themis/mq/templete/impl/CalculateObjectiveScoreConcurrentlyImpl.java

@@ -1,15 +1,13 @@
 package com.qmth.themis.mq.templete.impl;
 package com.qmth.themis.mq.templete.impl;
 
 
-import com.qmth.themis.business.constant.SpringContextHolder;
-import com.qmth.themis.business.enums.MqExecTypeEnum;
-import com.qmth.themis.mq.service.MqLogicService;
-import com.qmth.themis.mq.templete.Concurrently;
+import java.util.List;
+
 import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
 import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
 import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
 import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
 import org.apache.rocketmq.common.message.MessageExt;
 import org.apache.rocketmq.common.message.MessageExt;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
-import java.util.List;
+import com.qmth.themis.mq.templete.Concurrently;
 
 
 /**
 /**
  * 计算客观分
  * 计算客观分
@@ -18,12 +16,14 @@ import java.util.List;
  * @Author: xiatian
  * @Author: xiatian
  * @Date: 2020-07-30
  * @Date: 2020-07-30
  */
  */
+@Deprecated
 @Service
 @Service
 public class CalculateObjectiveScoreConcurrentlyImpl implements Concurrently {
 public class CalculateObjectiveScoreConcurrentlyImpl implements Concurrently {
 
 
     @Override
     @Override
     public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
     public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
-        MqLogicService mqLogicService = SpringContextHolder.getBean(MqLogicService.class);
-        return mqLogicService.consumeMessage(msgs, consumeConcurrentlyContext, MqExecTypeEnum.EXEC_MQ_CALCULATE_OBJECTIVE_SCORE_LOGIC);
+//        MqLogicService mqLogicService = SpringContextHolder.getBean(MqLogicService.class);
+//        return mqLogicService.consumeMessage(msgs, consumeConcurrentlyContext, MqExecTypeEnum.EXEC_MQ_CALCULATE_OBJECTIVE_SCORE_LOGIC);
+    	return null;
     }
     }
 }
 }

+ 6 - 1
themis-task/src/main/java/com/qmth/themis/task/enums/QuartzTaskEnum.java

@@ -19,7 +19,12 @@ public enum QuartzTaskEnum {
 
 
     MQ_ACTIVITY_JOB_NAME("mq_activity_job"),
     MQ_ACTIVITY_JOB_NAME("mq_activity_job"),
 
 
-    MQ_ACTIVITY_JOB_GROUP_NAME("mq_activity_job group"),;
+    MQ_ACTIVITY_JOB_GROUP_NAME("mq_activity_job group"),
+    
+    OBJECTIVE_ANSWER_CACHE_LOAD_JOB_NAME("客观题缓存加载"),
+    
+    OBJECTIVE_ANSWER_CACHE_LOAD_JOB_GROUP_NAME("客观题缓存加载")
+    ;
 
 
     private QuartzTaskEnum(String code) {
     private QuartzTaskEnum(String code) {
         this.code = code;
         this.code = code;

+ 42 - 0
themis-task/src/main/java/com/qmth/themis/task/quartz/ObjectiveAnswerCacheLoadJob.java

@@ -0,0 +1,42 @@
+package com.qmth.themis.task.quartz;
+
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+import org.springframework.stereotype.Component;
+
+import com.qmth.themis.business.service.TEExamActivityService;
+import com.qmth.themis.business.service.TEExamPaperService;
+
+/**
+ * @Description: 客观题缓存加载
+ * @Author: xiatian
+ * @Date: 2020-12-30
+ */
+@Component
+public class ObjectiveAnswerCacheLoadJob extends QuartzJobBean {
+    private final static Logger log = LoggerFactory.getLogger(ObjectiveAnswerCacheLoadJob.class);
+
+    @Resource
+    TEExamActivityService examActivityService;
+    
+    @Resource
+    TEExamPaperService examPaperService;
+
+    @Override
+    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
+        log.info("ObjectiveAnswerCacheLoadJob进来了,context:{}", context);
+        List<Long> examids=examActivityService.findExamIdToday();
+        if(examids!=null&&examids.size()>0) {
+        	for(Long examId:examids) {
+        		examPaperService.disposeObjectiveAnswer(examId);
+        	}
+        }
+    }
+}

+ 11 - 2
themis-task/src/main/java/com/qmth/themis/task/start/StartRunning.java

@@ -11,6 +11,7 @@ import com.qmth.themis.task.enums.QuartzTaskEnum;
 import com.qmth.themis.task.listener.QuartzOrderlyImpl;
 import com.qmth.themis.task.listener.QuartzOrderlyImpl;
 import com.qmth.themis.task.quartz.MqActivityJob;
 import com.qmth.themis.task.quartz.MqActivityJob;
 import com.qmth.themis.task.quartz.MqJob;
 import com.qmth.themis.task.quartz.MqJob;
+import com.qmth.themis.task.quartz.ObjectiveAnswerCacheLoadJob;
 import com.qmth.themis.task.service.QuartzService;
 import com.qmth.themis.task.service.QuartzService;
 import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
 import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
@@ -46,7 +47,8 @@ public class StartRunning implements CommandLineRunner {
     @Resource
     @Resource
     DictionaryConfig dictionaryConfig;
     DictionaryConfig dictionaryConfig;
 
 
-    @Override
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+	@Override
     public void run(String... args) throws Exception {
     public void run(String... args) throws Exception {
         log.info("服务器启动时执行 start");
         log.info("服务器启动时执行 start");
         log.info("增加mqjob start");
         log.info("增加mqjob start");
@@ -62,6 +64,13 @@ public class StartRunning implements CommandLineRunner {
         quartzService.deleteJob(QuartzTaskEnum.MQ_ACTIVITY_JOB_NAME.name(), QuartzTaskEnum.MQ_ACTIVITY_JOB_GROUP_NAME.name());
         quartzService.deleteJob(QuartzTaskEnum.MQ_ACTIVITY_JOB_NAME.name(), QuartzTaskEnum.MQ_ACTIVITY_JOB_GROUP_NAME.name());
         quartzService.addJob(MqActivityJob.class, QuartzTaskEnum.MQ_ACTIVITY_JOB_NAME.name(), QuartzTaskEnum.MQ_ACTIVITY_JOB_GROUP_NAME.name(), "0 0 0 * * ?", mqMap);
         quartzService.addJob(MqActivityJob.class, QuartzTaskEnum.MQ_ACTIVITY_JOB_NAME.name(), QuartzTaskEnum.MQ_ACTIVITY_JOB_GROUP_NAME.name(), "0 0 0 * * ?", mqMap);
         log.info("增加mqActivityjob end");
         log.info("增加mqActivityjob end");
+        
+        log.info("增加客观题答案缓存加载job start");
+        Map objectiveAnswerCacheMap = new HashMap();
+        objectiveAnswerCacheMap.put("name", ObjectiveAnswerCacheLoadJob.class.getName());
+        quartzService.deleteJob(QuartzTaskEnum.OBJECTIVE_ANSWER_CACHE_LOAD_JOB_NAME.name(), QuartzTaskEnum.OBJECTIVE_ANSWER_CACHE_LOAD_JOB_GROUP_NAME.name());
+        quartzService.addJob(ObjectiveAnswerCacheLoadJob.class, QuartzTaskEnum.OBJECTIVE_ANSWER_CACHE_LOAD_JOB_NAME.name(), QuartzTaskEnum.OBJECTIVE_ANSWER_CACHE_LOAD_JOB_GROUP_NAME.name(), "0 0 1 * * ?", objectiveAnswerCacheMap);
+        log.info("增加客观题答案缓存加载job end");
 
 
         /**
         /**
          * session
          * session
@@ -88,7 +97,7 @@ public class StartRunning implements CommandLineRunner {
          */
          */
         rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.QUARTZ_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name() + "||" + MqTagEnum.EXAM_STUDENT.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(QuartzOrderlyImpl.class));
         rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.QUARTZ_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name() + "||" + MqTagEnum.EXAM_STUDENT.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(QuartzOrderlyImpl.class));
         //计算客观分
         //计算客观分
-        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.CALCULATE_OBJECTIVE_SCORE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.CALCULATE_OBJECTIVE_SCORE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(CalculateObjectiveScoreConcurrentlyImpl.class));
+//        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.CALCULATE_OBJECTIVE_SCORE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.CALCULATE_OBJECTIVE_SCORE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(CalculateObjectiveScoreConcurrentlyImpl.class));
         //重新算分
         //重新算分
         rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.SCORE_CALCULATE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_SCORE_CALCULATE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(CalculateScoreConcurrentlyImpl.class));
         rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.SCORE_CALCULATE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_SCORE_CALCULATE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(CalculateScoreConcurrentlyImpl.class));
         //人脸验证保存
         //人脸验证保存