wangliang пре 4 година
родитељ
комит
812a5b1dd5
19 измењених фајлова са 491 додато и 248 уклоњено
  1. 2 2
      themis-backend/src/main/java/com/qmth/themis/backend/start/StartRunning.java
  2. 176 119
      themis-business/src/main/java/com/qmth/themis/business/cache/ExamRecordCacheUtil.java
  3. 12 33
      themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java
  4. 109 0
      themis-business/src/main/java/com/qmth/themis/business/enums/ExamRecordFieldEnum.java
  5. 7 6
      themis-business/src/main/java/com/qmth/themis/business/enums/MqTagEnum.java
  6. 9 0
      themis-business/src/main/java/com/qmth/themis/business/service/TOeExamRecordService.java
  7. 19 11
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java
  8. 32 6
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java
  9. 2 2
      themis-business/src/main/java/com/qmth/themis/business/service/impl/WarningServiceImpl.java
  10. 23 11
      themis-exam/src/main/java/com/qmth/themis/exam/api/TEStudentController.java
  11. 2 2
      themis-exam/src/main/java/com/qmth/themis/exam/api/TIeInvigilateCallMobileController.java
  12. 9 6
      themis-exam/src/main/java/com/qmth/themis/exam/api/TIeInvigilateCallOeController.java
  13. 7 7
      themis-exam/src/main/java/com/qmth/themis/exam/listener/service/impl/MqOeLogicServiceImpl.java
  14. 1 1
      themis-exam/src/main/java/com/qmth/themis/exam/start/StartRunning.java
  15. 1 1
      themis-exam/src/main/java/com/qmth/themis/exam/websocket/WebSocketMobileServer.java
  16. 17 10
      themis-exam/src/main/java/com/qmth/themis/exam/websocket/WebSocketOeServer.java
  17. 13 4
      themis-exam/src/main/java/com/qmth/themis/exam/websocketTemplete/WebSocketOeMessageTemplete.java
  18. 49 26
      themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java
  19. 1 1
      themis-task/src/main/java/com/qmth/themis/task/start/StartRunning.java

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

@@ -68,10 +68,10 @@ public class StartRunning implements CommandLineRunner {
         //考试记录数据持久化
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_PERSISTED_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_PERSISTED.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordPersistedConcurrentlyImpl.class));
         //考试记录数据更新
-        rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_UPDATE_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_UPDATE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordUpdateConcurrentlyImpl.class));
+        rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_UPDATE_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_UPDATE.name() + "||" + MqTagEnum.EXAM_RECORD_UPDATE_COLUMNS.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordUpdateConcurrentlyImpl.class));
         //考试记录数据初始化
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_INIT_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_INIT.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordInitConcurrentlyImpl.class));
-        
+
         //考试重新算分
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.SCORE_CALCULATE_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_SCORE_CALCULATE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(CalculateScoreConcurrentlyImpl.class));
 

+ 176 - 119
themis-business/src/main/java/com/qmth/themis/business/cache/ExamRecordCacheUtil.java

@@ -22,143 +22,169 @@ public class ExamRecordCacheUtil {
     private static RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
 
     public static Long getId(Long recordId) {
-        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "id");
+        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.id.getCode());
     }
 
     public static Long getExamStudentId(Long recordId) {
-        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "examStudentId");
+        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.exam_student_id.getCode());
     }
 
     public static Long getPaperId(Long recordId) {
-        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "paperId");
+        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.paper_id.getCode());
     }
 
-    public static void setFirstStartTime(Long recordId, Date date) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "firstStartTime", date);
-        examRecordService.dataUpdateMq(recordId, "first_start_time", date, 1);
+    public static void setFirstStartTime(Long recordId, Date date, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.first_start_time.getCode(), date);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.first_start_time.name(), date, 1);
+        }
     }
 
-    public static void setStatus(Long recordId, ExamRecordStatusEnum status) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "status", status);
-        examRecordService.dataUpdateMq(recordId, "status", status);
+    public static void setStatus(Long recordId, ExamRecordStatusEnum status, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.status.getCode(), status);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.status.name(), status);
+        }
     }
 
     public static Integer getDurationSeconds(Long recordId) {
-        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "durationSeconds");
+        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.duration_seconds.getCode());
     }
 
     public static Double getObjectiveScore(Long recordId) {
-        return (Double) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "objectiveScore");
+        return (Double) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.objective_score.getCode());
     }
 
     public static Long getExamId(Long recordId) {
-        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "examId");
+        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.exam_id.getCode());
     }
 
-    public static void setObjectiveScore(Long recordId, Double objectiveScore) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "objectiveScore", objectiveScore);
-        examRecordService.dataUpdateMq(recordId, "objective_score", objectiveScore);
+    public static void setObjectiveScore(Long recordId, Double objectiveScore, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.objective_score.getCode(), objectiveScore);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.objective_score.name(), objectiveScore);
+        }
     }
 
-    public static void setFinishTime(Long recordId, Date finishTime) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "finishTime", finishTime);
-        examRecordService.dataUpdateMq(recordId, "finish_time", finishTime, 1);
+    public static void setFinishTime(Long recordId, Date finishTime, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.finish_time.getCode(), finishTime);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.finish_time.name(), finishTime, 1);
+        }
     }
 
     public static Date getFinishTime(Long recordId) {
-        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "finishTime");
+        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.finish_time.getCode());
     }
 
-    public static void setDurationSeconds(Long recordId, Integer durationSeconds) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "durationSeconds", durationSeconds);
-        examRecordService.dataUpdateMq(recordId, "duration_seconds", durationSeconds);
+    public static void setDurationSeconds(Long recordId, Integer durationSeconds, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.duration_seconds.getCode(), durationSeconds);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.duration_seconds.name(), durationSeconds);
+        }
     }
 
-    public static void setFinishType(Long recordId, FinishTypeEnum finishType) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "finishType", finishType);
-        examRecordService.dataUpdateMq(recordId, "finish_type", finishType);
+    public static void setFinishType(Long recordId, FinishTypeEnum finishType, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.finish_type.getCode(), finishType);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.finish_type.name(), finishType);
+        }
     }
 
     public static FinishTypeEnum getFinishType(Long recordId) {
-        return (FinishTypeEnum) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "finishType");
+        return (FinishTypeEnum) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.finish_type.getCode());
     }
 
     public static Date getClientLastSyncTime(Long recordId) {
-        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "clientLastSyncTime");
+        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.client_last_sync_time.getCode());
     }
 
     public static Integer getAlreadyBreakCount(Long recordId) {
-        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "alreadyBreakCount");
+        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.already_break_count.getCode());
     }
 
-    public static void setAlreadyBreakCount(Long recordId, Integer alreadyBreakCount) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "alreadyBreakCount", alreadyBreakCount);
-        examRecordService.dataUpdateMq(recordId, "already_break_count", alreadyBreakCount);
+    public static void setAlreadyBreakCount(Long recordId, Integer alreadyBreakCount, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.already_break_count.getCode(), alreadyBreakCount);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.already_break_count.name(), alreadyBreakCount);
+        }
     }
 
     public static ExamRecordStatusEnum getStatus(Long recordId) {
-        return (ExamRecordStatusEnum) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "status");
+        return (ExamRecordStatusEnum) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.status.getCode());
     }
 
     public static Long getLastBreakId(Long recordId) {
-        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "lastBreakId");
+        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.last_break_id.getCode());
     }
 
     public static Date getLastBreakTime(Long recordId) {
-        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "lastBreakTime");
+        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.last_break_time.getCode());
     }
 
-    public static void setEntryAuthenticationResult(Long recordId, VerifyExceptionEnum entryAuthenticationResult) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "entryAuthenticationResult", entryAuthenticationResult);
-        examRecordService.dataUpdateMq(recordId, "entry_authentication_result", entryAuthenticationResult);
+    public static void setEntryAuthenticationResult(Long recordId, VerifyExceptionEnum entryAuthenticationResult, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.entry_authentication_result.getCode(), entryAuthenticationResult);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.entry_authentication_result.name(), entryAuthenticationResult);
+        }
     }
 
-    public static void setEntryAuthenticationId(Long recordId, Long entryAuthenticationId) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "entryAuthenticationId", entryAuthenticationId);
-        examRecordService.dataUpdateMq(recordId, "entry_authentication_id", entryAuthenticationId);
+    public static void setEntryAuthenticationId(Long recordId, Long entryAuthenticationId, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.entry_authentication_id.getCode(), entryAuthenticationId);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.entry_authentication_id.name(), entryAuthenticationId);
+        }
     }
 
     public static Long getExamActivityId(Long recordId) {
-        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "examActivityId");
+        return (Long) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.exam_activity_id.getCode());
     }
 
-    public static void setWarningCount(Long recordId, Integer warningCount) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "warningCount", warningCount);
-        examRecordService.dataUpdateMq(recordId, "warning_count", warningCount);
+    public static void setWarningCount(Long recordId, Integer warningCount, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.warning_count.getCode(), warningCount);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.warning_count.name(), warningCount);
+        }
     }
 
     public static Integer getWarningCount(Long recordId) {
-        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "warningCount");
+        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.warning_count.getCode());
     }
 
-    public static void setBreachStatus(Long recordId, Integer breachStatus) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "breachStatus", breachStatus);
-        examRecordService.dataUpdateMq(recordId, "breach_status", breachStatus);
+    public static void setBreachStatus(Long recordId, Integer breachStatus, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.breach_status.getCode(), breachStatus);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.breach_status.name(), breachStatus);
+        }
     }
 
     public static Integer getBreachStatus(Long recordId) {
-        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "breachStatus");
+        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.breach_status.getCode());
     }
 
-    public static void setInProcessLivenessVerifyCount(Long recordId, Integer inProcessLivenessVerifyCount) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "inProcessLivenessVerifyCount", inProcessLivenessVerifyCount);
-        examRecordService.dataUpdateMq(recordId, "in_process_liveness_verify_count", inProcessLivenessVerifyCount);
+    public static void setInProcessLivenessVerifyCount(Long recordId, Integer inProcessLivenessVerifyCount, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.in_process_liveness_verify_count.getCode(), inProcessLivenessVerifyCount);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.in_process_liveness_verify_count.name(), inProcessLivenessVerifyCount);
+        }
     }
 
     public static Integer getInProcessLivenessVerifyCount(Long recordId) {
-        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "inProcessLivenessVerifyCount");
+        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.in_process_liveness_verify_count.getCode());
     }
 
-    public static void setMonitorKey(Long recordId, String monitorKey) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "monitorKey", monitorKey);
-        examRecordService.dataUpdateMq(recordId, "monitor_key", monitorKey);
+    public static void setMonitorKey(Long recordId, String monitorKey, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.monitor_key.getCode(), monitorKey);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.monitor_key.name(), monitorKey);
+        }
     }
 
     public static String getMonitorKey(Long recordId) {
-        if (Objects.isNull(redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "monitorKey"))) {
-            setMonitorKey(recordId, String.valueOf(redisUtil.getRedisSequence()));
+        if (Objects.isNull(redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.monitor_key.getCode()))) {
+            setMonitorKey(recordId, String.valueOf(redisUtil.getRedisSequence()), true);
         }
-        return (String) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "monitorKey");
+        return (String) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.monitor_key.getCode());
     }
 
     public static String getMonitorLiveUrl(Long recordId, String source) {
@@ -181,18 +207,22 @@ public class ExamRecordCacheUtil {
         return (String) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), SystemConstant.MONITOR_LIVE_URL_ + MonitorVideoSourceEnum.CLIENT_SCREEN.name());
     }
 
-    public static void setMonitorLiveUrl(Long recordId, String source, String liveUrl) {
+    public static void setMonitorLiveUrl(Long recordId, String source, String liveUrl, boolean update) {
         redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), SystemConstant.MONITOR_LIVE_URL_ + source, liveUrl);
-        examRecordService.dataUpdateMq(recordId, "monitor_live_url", liveUrl);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.monitor_live_url.name(), liveUrl);
+        }
     }
 
     public static MonitorStatusSourceEnum getMonitorStatus(Long recordId, String source) {
         return (MonitorStatusSourceEnum) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), SystemConstant.MONITOR_STATUS_ + source);
     }
 
-    public static void setMonitorStatus(Long recordId, String source, MonitorStatusSourceEnum statusSourceEnum) {
+    public static void setMonitorStatus(Long recordId, String source, MonitorStatusSourceEnum statusSourceEnum, boolean update) {
         redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), SystemConstant.MONITOR_STATUS_ + source, statusSourceEnum);
-        examRecordService.dataUpdateMq(recordId, "monitor_status_source", statusSourceEnum);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.monitor_status_source.name(), statusSourceEnum);
+        }
     }
 
     public static MonitorCallStatusSourceEnum getMonitorCallStatus(Long recordId, String source) {
@@ -204,112 +234,139 @@ public class ExamRecordCacheUtil {
     }
 
     public static WebsocketStatusEnum getClientWebsocketStatus(Long recordId) {
-        return (WebsocketStatusEnum) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "clientWebsocketStatus");
+        return (WebsocketStatusEnum) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.client_websocket_status.getCode());
     }
 
-    public static void setClientWebsocketStatus(Long recordId, WebsocketStatusEnum websocketStatusEnum) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "clientWebsocketStatus", websocketStatusEnum);
-        examRecordService.dataUpdateMq(recordId, "client_websocket_status", websocketStatusEnum);
+    public static void setClientWebsocketStatus(Long recordId, WebsocketStatusEnum websocketStatusEnum, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.client_websocket_status.getCode(), websocketStatusEnum);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.client_websocket_status.name(), websocketStatusEnum);
+        }
     }
 
-    public static void setClientCurrentIp(Long recordId, String ip) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "clientCurrentIp", ip);
-        examRecordService.dataUpdateMq(recordId, "client_current_ip", ip);
+    public static void setClientCurrentIp(Long recordId, String ip, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.client_current_ip.getCode(), ip);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.client_current_ip.name(), ip);
+        }
     }
 
-    public static void setClientWebsocketId(Long recordId, String id) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "clientWebsocketId", id);
-        examRecordService.dataUpdateMq(recordId, "client_websocket_id", id);
+    public static void setClientWebsocketId(Long recordId, String id, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.client_websocket_id.getCode(), id);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.client_websocket_id.name(), id);
+        }
     }
 
-    public static void setClientLastSyncTime(Long recordId) {
-        Date now = new Date();
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "clientLastSyncTime", now);
-        examRecordService.dataUpdateMq(recordId, "client_last_sync_time", now);
+    public static void setClientLastSyncTime(Long recordId, Date date, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.client_last_sync_time.getCode(), date);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.client_last_sync_time.name(), date, 1);
+        }
     }
 
-    public static void setPaperDownload(Long recordId, Integer paperDownload) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "paperDownload", paperDownload);
-        examRecordService.dataUpdateMq(recordId, "paper_download", paperDownload);
+    public static void setPaperDownload(Long recordId, Integer paperDownload, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.paper_download.getCode(), paperDownload);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.paper_download.name(), paperDownload);
+        }
     }
 
-    public static void setAnswerProgress(Long recordId, Double progress) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "answerProgress", progress);
-        examRecordService.dataUpdateMq(recordId, "answer_progress", progress);
+    public static void setAnswerProgress(Long recordId, Double progress, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.answer_progress.getCode(), progress);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.answer_progress.name(), progress);
+        }
     }
 
-    public static void setLastBreakId(Long recordId, Long breakId) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "lastBreakId", breakId);
-        examRecordService.dataUpdateMq(recordId, "last_break_id", breakId);
+    public static void setLastBreakId(Long recordId, Long breakId, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.last_break_id.getCode(), breakId);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.last_break_id.name(), breakId);
+        }
     }
 
-    public static void setLastBreakTime(Long recordId) {
-        Date now = new Date();
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "lastBreakTime", now);
-        examRecordService.dataUpdateMq(recordId, "last_break_time", now);
+    public static void setLastBreakTime(Long recordId, Date date, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.last_break_time.getCode(), date);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.last_break_time.name(), date, 1);
+        }
     }
 
-    public static void setLastStartTime(Long recordId) {
-        Date now = new Date();
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "lastStartTime", now);
-        examRecordService.dataUpdateMq(recordId, "last_start_time", now);
+    public static void setLastStartTime(Long recordId, Date date, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.last_start_time.getCode(), date);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.last_start_time.name(), date, 1);
+        }
     }
 
     public static Date getLastStartTime(Long recordId) {
-        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "lastStartTime");
+        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.last_start_time.getCode());
     }
 
     public static Date getStartTime(Long recordId) {
-        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "startTime");
+        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.start_time.getCode());
     }
 
     public static Date getEndTime(Long recordId) {
-        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "endTime");
+        return (Date) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.end_time.getCode());
     }
 
     public static Integer getOpeningSeconds(Long recordId) {
-        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "openingSeconds");
+        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.opening_seconds.getCode());
     }
 
     public static Integer getMinDurationSeconds(Long recordId) {
-        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "minDurationSeconds");
+        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.min_duration_seconds.getCode());
     }
 
     public static Integer getMaxDurationSeconds(Long recordId) {
-        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "maxDurationSeconds");
+        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.max_duration_seconds.getCode());
     }
 
     public static Integer getForceFinish(Long recordId) {
-        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), "forceFinish");
+        return (Integer) redisUtil.get(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.force_finish.getCode());
     }
 
-    public static void setStartTime(Long recordId, Date startTime) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "startTime", startTime);
-        examRecordService.dataUpdateMq(recordId, "start_time", startTime);
+    public static void setStartTime(Long recordId, Date startTime, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.start_time.getCode(), startTime);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.start_time.name(), startTime, 1);
+        }
     }
 
-    public static void setEndTime(Long recordId, Date endTime) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "endTime", endTime);
-        examRecordService.dataUpdateMq(recordId, "end_time", endTime);
+    public static void setEndTime(Long recordId, Date endTime, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.end_time.getCode(), endTime);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.end_time.name(), endTime, 1);
+        }
     }
 
-    public static void setOpeningSeconds(Long recordId, Integer openingSeconds) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), "openingSeconds", openingSeconds);
-        examRecordService.dataUpdateMq(recordId, "opening_seconds", openingSeconds);
+    public static void setOpeningSeconds(Long recordId, Integer openingSeconds, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.opening_seconds.getCode(), openingSeconds);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.opening_seconds.name(), openingSeconds);
+        }
     }
 
-    public static void setMinDurationSeconds(Long recordId, Integer minDurationSeconds) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), minDurationSeconds, minDurationSeconds);
-        examRecordService.dataUpdateMq(recordId, "min_duration_seconds", minDurationSeconds);
+    public static void setMinDurationSeconds(Long recordId, Integer minDurationSeconds, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.min_duration_seconds.getCode(), minDurationSeconds);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.min_duration_seconds.name(), minDurationSeconds);
+        }
     }
 
-    public static void setMaxDurationSeconds(Long recordId, Integer maxDurationSeconds) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), maxDurationSeconds, maxDurationSeconds);
-        examRecordService.dataUpdateMq(recordId, "max_duration_seconds", maxDurationSeconds);
+    public static void setMaxDurationSeconds(Long recordId, Integer maxDurationSeconds, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.max_duration_seconds.getCode(), maxDurationSeconds);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.max_duration_seconds.name(), maxDurationSeconds);
+        }
     }
 
-    public static void setForceFinish(Long recordId, Integer forceFinish) {
-        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), forceFinish, forceFinish);
-        examRecordService.dataUpdateMq(recordId, "force_finish", forceFinish);
+    public static void setForceFinish(Long recordId, Integer forceFinish, boolean update) {
+        redisUtil.set(RedisKeyHelper.examRecordCacheKey(recordId), ExamRecordFieldEnum.force_finish.getCode(), forceFinish);
+        if (update) {
+            examRecordService.dataUpdateMq(recordId, ExamRecordFieldEnum.force_finish.name(), forceFinish);
+        }
     }
 }

+ 12 - 33
themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java

@@ -1,22 +1,11 @@
 package com.qmth.themis.business.constant;
 
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qmth.themis.business.dto.AuthDto;
-import com.qmth.themis.business.entity.TBExamInvigilateUser;
-import com.qmth.themis.business.entity.TBSession;
-import com.qmth.themis.business.entity.TBUser;
-import com.qmth.themis.business.entity.TEExamStudent;
-import com.qmth.themis.business.enums.RoleEnum;
-import com.qmth.themis.business.util.ServletUtil;
 import com.qmth.themis.common.contanst.Constants;
-import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.enums.Platform;
 import com.qmth.themis.common.enums.Source;
-import com.qmth.themis.common.exception.BusinessException;
 
 import java.io.File;
 import java.util.*;
-import java.util.stream.Collectors;
 
 /**
  * @Description: 系统常量
@@ -120,7 +109,7 @@ public class SystemConstant {
 
     //考试记录数据持久化锁
     public static final String REDIS_LOCK_EXAM_RECORD_PERSISTED_PREFIX = "lock:exam_record_persisted:record_id_";
-    
+
     //重新算分锁
     public static final String REDIS_LOCK_CALCULATE_SCORE_PREFIX = "lock:calculate_score:exam_id_";
     /**
@@ -242,27 +231,17 @@ public class SystemConstant {
      * @return
      */
     public static Map timeTransform(Map map) {
-        if (Objects.nonNull(map)) {
-            if (Objects.nonNull(map.get("createTime")) && map.get("createTime") instanceof Long) {
-                Date date = new Date();
-                date.setTime(Long.parseLong(String.valueOf(map.get("createTime"))));
-                map.put("createTime", date);
-            }
-            if (Objects.nonNull(map.get("startTime")) && map.get("startTime") instanceof Long) {
-                Date date = new Date();
-                date.setTime(Long.parseLong(String.valueOf(map.get("startTime"))));
-                map.put("startTime", date);
-            }
-            if (Objects.nonNull(map.get("finishTime")) && map.get("finishTime") instanceof Long) {
-                Date date = new Date();
-                date.setTime(Long.parseLong(String.valueOf(map.get("finishTime"))));
-                map.put("finishTime", date);
-            }
-            if (Objects.nonNull(map.get("updateTime")) && map.get("updateTime") instanceof Long) {
-                Date date = new Date();
-                date.setTime(Long.parseLong(String.valueOf(map.get("updateTime"))));
-                map.put("updateTime", date);
-            }
+        if (Objects.nonNull(map) && Objects.nonNull(map.get("createTime")) && map.get("createTime") instanceof Long) {
+            map.put("createTime", new Date((Long) map.get("createTime")));
+        }
+        if (Objects.nonNull(map) && Objects.nonNull(map.get("startTime")) && map.get("startTime") instanceof Long) {
+            map.put("startTime", new Date((Long) map.get("startTime")));
+        }
+        if (Objects.nonNull(map) && Objects.nonNull(map.get("finishTime")) && map.get("finishTime") instanceof Long) {
+            map.put("finishTime", new Date((Long) map.get("finishTime")));
+        }
+        if (Objects.nonNull(map) && Objects.nonNull(map.get("updateTime")) && map.get("updateTime") instanceof Long) {
+            map.put("updateTime", new Date((Long) map.get("updateTime")));
         }
         return map;
     }

+ 109 - 0
themis-business/src/main/java/com/qmth/themis/business/enums/ExamRecordFieldEnum.java

@@ -0,0 +1,109 @@
+package com.qmth.themis.business.enums;
+
+/**
+* @Description: 考试记录字段
+* @Param:
+* @return:
+* @Author: wangliang
+* @Date: 2020/9/18
+*/
+public enum ExamRecordFieldEnum {
+
+    id("id"),
+
+    exam_id("examId"),
+
+    exam_activity_id("examActivityId"),
+
+    exam_student_id("examStudentId"),
+
+    paper_id("paperId"),
+
+    status("status"),
+
+    first_prepare_time("firstPrepareTime"),
+
+    first_start_time("firstStartTime"),
+
+    last_break_time("lastBreakTime"),
+
+    last_prepare_time("lastPrepareTime"),
+
+    last_start_time("lastStartTime"),
+
+    already_break_count("alreadyBreakCount"),
+
+    client_current_ip("clientCurrentIp"),
+
+    client_websocket_status("clientWebsocketStatus"),
+
+    client_websocket_id("clientWebsocketId"),
+
+    client_last_sync_time("clientLastSyncTime"),
+
+    answer_progress("answerProgress"),
+
+    duration_seconds("durationSeconds"),
+
+    finish_time("finishTime"),
+
+    finish_type("finishType"),
+
+    warning_count("warningCount"),
+
+    review_result("reviewResult"),
+
+    objective_score("objectiveScore"),
+
+    paper_download("paperDownload"),
+
+    breach_status("breachStatus"),
+
+    paper_struct_path("paperStructPath"),
+
+    paper_struct_upload("paperStructUpload"),
+
+    serial_number("serialNumber"),
+
+    last_break_id("lastBreakId"),
+
+    entry_authentication_id("entryAuthenticationId"),
+
+    entry_authentication_result("entryAuthenticationResult"),
+
+    in_process_face_verify_status("inProcessFaceVerifyStatus"),
+
+    in_process_liveness_verify_status("inProcessLivenessVerifyStatus"),
+
+    in_process_liveness_verify_count("inProcessLivenessVerifyCount"),
+
+    monitor_key("monitorKey"),
+
+    monitor_status_source("monitorStatusSource"),
+
+    monitor_live_url("monitorLiveUrl"),
+
+    score_status("scoreStatus"),
+
+    start_time("startTime"),
+
+    end_time("endTime"),
+
+    opening_seconds("openingSeconds"),
+
+    min_duration_seconds("minDurationSeconds"),
+
+    max_duration_seconds("maxDurationSeconds"),
+
+    force_finish("forceFinish");
+
+    private String code;
+
+    private ExamRecordFieldEnum(String code) {
+        this.code = code;
+    }
+
+    public String getCode() {
+        return code;
+    }
+}

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

@@ -31,18 +31,19 @@ public enum MqTagEnum {
     EXAM_ACTIVITY("考场一次性延时任务标签", "考场一次性延时任务", "normal", 19),
     QUARTZ("quartz标签", "quartz任务", "normal", 20),
     CALCULATE_OBJECTIVE_SCORE("计算客观分标签", "计算客观分", "normal", 21),
-    FACE_VERIFY_SAVE("人脸验证保存", "人脸验证", "normal", 22),
-    LIVENESS_VERIFY_SAVE("活体验证保存", "活体验证", "normal", 23),
-    EXAM_RECORD_PERSISTED("考试记录数据持久化", "考试", "normal", 24),
-    EXAM_RECORD_UPDATE("考试记录数据更新", "考试", "normal", 25),
-    EXAM_RECORD_INIT("考试记录数据初始化", "考试", "normal", 26),
+    FACE_VERIFY_SAVE("人脸验证保存标签", "人脸验证", "normal", 22),
+    LIVENESS_VERIFY_SAVE("活体验证保存标签", "活体验证", "normal", 23),
+    EXAM_RECORD_PERSISTED("考试记录数据持久化标签", "考试", "normal", 24),
+    EXAM_RECORD_UPDATE("考试记录数据更新标签", "考试记录数据更新", "normal", 25),
+    EXAM_RECORD_INIT("考试记录数据初始化标签", "考试", "normal", 26),
     WARNING_LOG("预警标签", "预警", "normal", 27),
     EXCEPTION_LOG("异常标签", "异常", "normal", 28),
     MONITOR_LOG("监考监控标签", "监考监控", "normal", 29),
     EXAM_SCORE_CALCULATE("重新算分标签", "重新算分", "normal", 30),
     EXAM_STUDNET_UPDATE("考生数据更新标签", "考生数据更新", "normal", 31),
     EXAM_BREAK("考试断点标签", "考试断点", "normal", 32),
-    EXAM_STOP("考试移动端监控退出标签", "考试移动端退出暂停", "normal", 33);
+    EXAM_STOP("考试移动端监控退出标签", "考试移动端退出暂停", "normal", 33),
+    EXAM_RECORD_UPDATE_COLUMNS("考试记录多字段数据更新标签", "考试记录多字段数据更新", "normal", 34);
 
     private MqTagEnum(String desc, String code, String type, int id) {
         this.desc = desc;

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

@@ -70,6 +70,15 @@ public interface TOeExamRecordService extends IService<TOeExamRecord> {
      */
     void dataUpdate(Long recordId, String colName, Object colValue, Integer isDate);
 
+    /**
+     * 考试记录字段同步消息发送
+     *
+     * @param recordId
+     * @param colNames
+     * @param colValues
+     */
+    void dataUpdatesMq(Long recordId, String[] colNames, Object[] colValues);
+
     /**
      * 考试记录初始化消息发送
      *

+ 19 - 11
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java

@@ -260,7 +260,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         }
 
         // 写入次数
-        Integer alreadyExamCount = es.getAlreadyExamCount()+1;
+        Integer alreadyExamCount = es.getAlreadyExamCount() + 1;
 
         Long recordId = toeExamRecordService.saveByPrepare(es.getExamId(), es.getExamActivityId(), examStudentId,
                 paperId, alreadyExamCount);
@@ -299,9 +299,9 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         //mq发送消息end
         return prepare;
     }
-    
-    private void updateExamStudent(Long examStudentId,Integer alreadyExamCount,Long currentRecordId) {
-    	Map<String, Object> transMap = new HashMap<String, Object>();
+
+    private void updateExamStudent(Long examStudentId, Integer alreadyExamCount, Long currentRecordId) {
+        Map<String, Object> transMap = new HashMap<String, Object>();
         transMap.put("examStudentId", examStudentId);
         transMap.put("alreadyExamCount", alreadyExamCount);
         transMap.put("currentRecordId", currentRecordId);
@@ -386,8 +386,12 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         ret.setPaperDecryptVector(ep.getDecryptVector());
 
         // 更新考试记录缓存
-        ExamRecordCacheUtil.setFirstStartTime(recordId, new Date());
-        ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.ANSWERING);
+        Date firstStartTime = new Date();
+        ExamRecordCacheUtil.setFirstStartTime(recordId, firstStartTime, false);
+        ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.ANSWERING, false);
+        String[] columns = new String[]{ExamRecordFieldEnum.first_start_time.name(), ExamRecordFieldEnum.status.name()};
+        Object[] values = new Object[]{firstStartTime, ExamRecordStatusEnum.ANSWERING};
+        toeExamRecordService.dataUpdatesMq(recordId, columns, values);
         //更新场次-考试记录缓存
         ExamActivityRecordCacheUtil.setExamRecordStatus(activityId, recordId, ExamRecordCacheUtil.getStatus(recordId));
         return ret;
@@ -474,7 +478,7 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         redisUtil.set(RedisKeyHelper.examAnswerKey(recordId),
                 RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex), answerCache);
         // 重置考试记录客观题得分
-        ExamRecordCacheUtil.setObjectiveScore(recordId, null);
+        ExamRecordCacheUtil.setObjectiveScore(recordId, null, true);
         AnswerSubmitBean ret = new AnswerSubmitBean();
         ret.setVersion(version);
         // 发消息计算客观分
@@ -743,10 +747,14 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
         } else {//非实时出分
             ret.setStatus(FinishExamResultEnum.NORMAL);
         }
-        ExamRecordCacheUtil.setFinishTime(recordId, now);
-        ExamRecordCacheUtil.setDurationSeconds(recordId, durationSeconds);
-        ExamRecordCacheUtil.setFinishType(recordId, FinishTypeEnum.valueOf(type));
-        ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.FINISHED);
+        Date finishTime = new Date();
+        ExamRecordCacheUtil.setFinishTime(recordId, finishTime, false);
+        ExamRecordCacheUtil.setDurationSeconds(recordId, durationSeconds, false);
+        ExamRecordCacheUtil.setFinishType(recordId, FinishTypeEnum.valueOf(type), false);
+        ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.FINISHED, false);
+        String[] columns = new String[]{ExamRecordFieldEnum.finish_time.name(), ExamRecordFieldEnum.duration_seconds.name(), ExamRecordFieldEnum.finish_type.name(), ExamRecordFieldEnum.status.name()};
+        Object[] values = new Object[]{finishTime, durationSeconds, FinishTypeEnum.valueOf(type), ExamRecordStatusEnum.FINISHED};
+        toeExamRecordService.dataUpdatesMq(recordId, columns, values);
         //更新场次-考试记录缓存
         ExamActivityRecordCacheUtil.setExamRecordStatus(es.getExamActivityId(), recordId, ExamRecordCacheUtil.getStatus(recordId));
         //更新未完成考试记录id

+ 32 - 6
themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java

@@ -244,7 +244,7 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
                         }
                     }
                     if (total != null) {
-                        ExamRecordCacheUtil.setObjectiveScore(recordId, total);
+                        ExamRecordCacheUtil.setObjectiveScore(recordId, total, true);
                     }
                 }
             }
@@ -352,8 +352,11 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
     @Override
     public void saveFaceVerify(ExamTypeEnum type, Long recordId, Long entryAuthenticationId, VerifyExceptionEnum entryAuthenticationResult) {
         if (ExamTypeEnum.FIRST_START.equals(type)) {
-            ExamRecordCacheUtil.setEntryAuthenticationId(recordId, entryAuthenticationId);
-            ExamRecordCacheUtil.setEntryAuthenticationResult(recordId, entryAuthenticationResult);
+            ExamRecordCacheUtil.setEntryAuthenticationId(recordId, entryAuthenticationId, false);
+            ExamRecordCacheUtil.setEntryAuthenticationResult(recordId, entryAuthenticationResult, false);
+            String[] columns = new String[]{ExamRecordFieldEnum.entry_authentication_id.name(), ExamRecordFieldEnum.entry_authentication_result.name()};
+            Object[] values = new Object[]{entryAuthenticationId, entryAuthenticationResult};
+            this.dataUpdatesMq(recordId, columns, values);
         } else if (ExamTypeEnum.IN_PROCESS.equals(type)) {
 
         }
@@ -362,11 +365,14 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
     @Override
     public void saveLivenessVerify(LivenessTypeEnum type, Long recordId, Long entryAuthenticationId, VerifyExceptionEnum entryAuthenticationResult) {
         if (LivenessTypeEnum.FIRST_START.equals(type)) {
-            ExamRecordCacheUtil.setEntryAuthenticationId(recordId, entryAuthenticationId);
-            ExamRecordCacheUtil.setEntryAuthenticationResult(recordId, entryAuthenticationResult);
+            ExamRecordCacheUtil.setEntryAuthenticationId(recordId, entryAuthenticationId, false);
+            ExamRecordCacheUtil.setEntryAuthenticationResult(recordId, entryAuthenticationResult, false);
+            String[] columns = new String[]{ExamRecordFieldEnum.entry_authentication_id.name(), ExamRecordFieldEnum.entry_authentication_result.name()};
+            Object[] values = new Object[]{entryAuthenticationId, entryAuthenticationResult};
+            this.dataUpdatesMq(recordId, columns, values);
         } else if (LivenessTypeEnum.IN_PROCESS.equals(type)) {
             Integer count = ExamRecordCacheUtil.getInProcessLivenessVerifyCount(recordId);
-            ExamRecordCacheUtil.setInProcessLivenessVerifyCount(recordId, (count == null ? 0 : count + 1));
+            ExamRecordCacheUtil.setInProcessLivenessVerifyCount(recordId, (count == null ? 0 : count + 1), true);
         }
     }
 
@@ -376,6 +382,7 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
     }
 
     @Override
+    @Transactional
     public void dataUpdateMq(Long recordId, String colName, Object colValue, Integer isDate) {
         Map<String, Object> transMap = new HashMap<String, Object>();
         transMap.put("recordId", recordId);
@@ -399,7 +406,26 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
         }
     }
 
+    /**
+     * 多字段更新
+     * @param recordId
+     * @param colNames
+     * @param colValues
+     */
+    @Override
+    @Transactional
+    public void dataUpdatesMq(Long recordId, String[] colNames, Object[] colValues) {
+        Map<String, Object> transMap = new HashMap<String, Object>();
+        transMap.put("recordId", recordId);
+        transMap.put("colNames", colNames);
+        transMap.put("colValues", colValues);
+        //mq发送消息start
+        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_UPDATE_COLUMNS.name(), transMap, MqTagEnum.EXAM_RECORD_UPDATE_COLUMNS, recordId.toString(), recordId.toString());
+        mqDtoService.assembleSendOneWayMsg(mqDto);
+    }
+
     @Override
+    @Transactional
     public void dataInitMq(Map<String, Object> param) {
         Long id = (Long) param.get("id");
         //mq发送消息start

+ 2 - 2
themis-business/src/main/java/com/qmth/themis/business/service/impl/WarningServiceImpl.java

@@ -187,9 +187,9 @@ public class WarningServiceImpl implements WarningService {
         if (Objects.nonNull(objectMap.get("warningCount"))) {
             Integer warningCount = ExamRecordCacheUtil.getWarningCount(recordId);
             warningCount++;
-            ExamRecordCacheUtil.setWarningCount(recordId, warningCount);
+            ExamRecordCacheUtil.setWarningCount(recordId, warningCount, true);
         } else {
-            ExamRecordCacheUtil.setWarningCount(recordId, 1);
+            ExamRecordCacheUtil.setWarningCount(recordId, 1, true);
         }
     }
 

+ 23 - 11
themis-exam/src/main/java/com/qmth/themis/exam/api/TEStudentController.java

@@ -93,6 +93,9 @@ public class TEStudentController {
     @Resource
     SystemConfig systemConfig;
 
+    @Resource
+    TOeExamRecordService tOeExamRecordService;
+
     @ApiOperation(value = "学生登录接口")
     @RequestMapping(value = "/login", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "学生信息", response = TEExamResultDto.class)})
@@ -244,11 +247,17 @@ public class TEStudentController {
                         //只有ANSWERING状态才生成断点
                         if (Objects.equals(status, ExamRecordStatusEnum.ANSWERING)) {
                             alreadyBreakCount++;
-                            ExamRecordCacheUtil.setLastBreakId(recordId, Constants.idGen.next());
-                            ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.RESUME_PREPARE);
-                            ExamRecordCacheUtil.setLastBreakTime(recordId);
-                            ExamRecordCacheUtil.setAlreadyBreakCount(recordId, alreadyBreakCount);
-                            ExamRecordCacheUtil.setLastStartTime(recordId);
+                            Long breakId = Constants.idGen.next();
+                            ExamRecordCacheUtil.setLastBreakId(recordId, breakId, false);
+                            ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.RESUME_PREPARE, false);
+                            Date lastBreakTimeNow = new Date();
+                            ExamRecordCacheUtil.setLastBreakTime(recordId, lastBreakTimeNow, false);
+                            ExamRecordCacheUtil.setAlreadyBreakCount(recordId, alreadyBreakCount, false);
+                            Date lastStartTime = new Date();
+                            ExamRecordCacheUtil.setLastStartTime(recordId, lastStartTime, false);
+                            String[] columns = new String[]{ExamRecordFieldEnum.last_break_id.name(), ExamRecordFieldEnum.status.name(), ExamRecordFieldEnum.last_break_time.name(), ExamRecordFieldEnum.already_break_count.name(), ExamRecordFieldEnum.last_start_time.name()};
+                            Object[] values = new Object[]{breakId, ExamRecordStatusEnum.RESUME_PREPARE, lastBreakTimeNow, alreadyBreakCount, lastStartTime};
+                            tOeExamRecordService.dataUpdatesMq(recordId, columns, values);
                             //考试断点异常原因 发送mq start
                             MqDto mqDtoBreak = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_BREAK.name(), ExceptionEnum.NET_TIME_OUT, MqTagEnum.EXAM_BREAK, String.valueOf(recordId), String.valueOf(recordId));
                             mqDtoService.assembleSendOneWayMsg(mqDtoBreak);
@@ -322,12 +331,15 @@ public class TEStudentController {
         Gson gson = new Gson();
         ExamActivityUnFinishBean examActivityUnFinishBean = gson.fromJson(gson.toJson(teExamActivityDto), ExamActivityUnFinishBean.class);
         examActivityUnFinishBean.setRecordId(recordId);
-        ExamRecordCacheUtil.setStartTime(recordId, examActivityUnFinishBean.getStartTime());
-        ExamRecordCacheUtil.setEndTime(recordId, examActivityCacheBean.getFinishTime());
-        ExamRecordCacheUtil.setOpeningSeconds(recordId, examActivityCacheBean.getOpeningSeconds());
-        ExamRecordCacheUtil.setMinDurationSeconds(recordId, ec.getMinDurationSeconds());
-        ExamRecordCacheUtil.setMaxDurationSeconds(recordId, examActivityCacheBean.getMaxDurationSeconds());
-        ExamRecordCacheUtil.setForceFinish(recordId, ec.getForceFinish());
+        ExamRecordCacheUtil.setStartTime(recordId, examActivityUnFinishBean.getStartTime(), false);
+        ExamRecordCacheUtil.setEndTime(recordId, examActivityCacheBean.getFinishTime(), false);
+        ExamRecordCacheUtil.setOpeningSeconds(recordId, examActivityCacheBean.getOpeningSeconds(), false);
+        ExamRecordCacheUtil.setMinDurationSeconds(recordId, ec.getMinDurationSeconds(), false);
+        ExamRecordCacheUtil.setMaxDurationSeconds(recordId, examActivityCacheBean.getMaxDurationSeconds(), false);
+        ExamRecordCacheUtil.setForceFinish(recordId, ec.getForceFinish(), false);
+        String[] columns = new String[]{ExamRecordFieldEnum.start_time.name(), ExamRecordFieldEnum.end_time.name(), ExamRecordFieldEnum.opening_seconds.name(), ExamRecordFieldEnum.min_duration_seconds.name(), ExamRecordFieldEnum.max_duration_seconds.name(), ExamRecordFieldEnum.force_finish.name()};
+        Object[] values = new Object[]{examActivityUnFinishBean.getStartTime(), examActivityCacheBean.getFinishTime(), examActivityCacheBean.getOpeningSeconds(), ec.getMinDurationSeconds(), examActivityCacheBean.getMaxDurationSeconds(), ec.getForceFinish()};
+        tOeExamRecordService.dataUpdatesMq(recordId, columns, values);
         return new ExamUnFinishBean(ec.getId(), ec.getName(), ec.getPreNotice(), ec.getPreNoticeStaySeconds(), ec.getPostNotice(), examActivityUnFinishBean);
     }
 }

+ 2 - 2
themis-exam/src/main/java/com/qmth/themis/exam/api/TIeInvigilateCallMobileController.java

@@ -82,7 +82,7 @@ public class TIeInvigilateCallMobileController {
             String monitorKey = ExamRecordCacheUtil.getMonitorKey(recordId);
             TIeExamInvigilateCallLog tIeExamInvigilateCallLog = new TIeExamInvigilateCallLog(recordId, source, liveUrl, MonitorStatusSourceEnum.INIT, monitorKey);
             //获取考试记录缓存
-            ExamRecordCacheUtil.setMonitorLiveUrl(recordId, source.name(), liveUrl);
+            ExamRecordCacheUtil.setMonitorLiveUrl(recordId, source.name(), liveUrl, true);
 
             //监考监控通话信息 发送mq start
             MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.MONITOR_LOG.name(), tIeExamInvigilateCallLog, MqTagEnum.MONITOR_LOG, String.valueOf(tIeExamInvigilateCallLog.getId()), source.name());
@@ -182,7 +182,7 @@ public class TIeInvigilateCallMobileController {
         } else {
             callStatus = MonitorCallStatusSourceEnum.STOP;
         }
-        ExamRecordCacheUtil.setMonitorStatus(recordId, source.name(), status);
+        ExamRecordCacheUtil.setMonitorStatus(recordId, source.name(), status, true);
         ExamRecordCacheUtil.setMonitorCallStatus(recordId, source.name(), callStatus);
         String monitorKey = ExamRecordCacheUtil.getMonitorKey(recordId);
         TIeExamInvigilateCallLog tIeExamInvigilateCallLog = new TIeExamInvigilateCallLog(recordId, source, liveUrl, MonitorStatusSourceEnum.START, monitorKey, callStatus);

+ 9 - 6
themis-exam/src/main/java/com/qmth/themis/exam/api/TIeInvigilateCallOeController.java

@@ -7,7 +7,7 @@ import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.entity.TIeExamInvigilateCallLog;
 import com.qmth.themis.business.enums.*;
 import com.qmth.themis.business.service.MqDtoService;
-import com.qmth.themis.business.util.RedisUtil;
+import com.qmth.themis.business.service.TOeExamRecordService;
 import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.util.Result;
@@ -42,10 +42,10 @@ public class TIeInvigilateCallOeController {
     private final static Logger log = LoggerFactory.getLogger(TIeInvigilateCallOeController.class);
 
     @Resource
-    RedisUtil redisUtil;
+    MqDtoService mqDtoService;
 
     @Resource
-    MqDtoService mqDtoService;
+    TOeExamRecordService tOeExamRecordService;
 
     @ApiOperation(value = "监控观看地址更新接口")
     @RequestMapping(value = "/live_url", method = RequestMethod.POST)
@@ -73,8 +73,11 @@ public class TIeInvigilateCallOeController {
             String monitorKey = ExamRecordCacheUtil.getMonitorKey(recordId);
             TIeExamInvigilateCallLog tIeExamInvigilateCallLog = new TIeExamInvigilateCallLog(recordId, source, liveUrl, MonitorStatusSourceEnum.INIT, monitorKey);
             //获取考试记录缓存
-            ExamRecordCacheUtil.setMonitorLiveUrl(recordId, source.name(), liveUrl);
-            ExamRecordCacheUtil.setMonitorStatus(recordId, source.name(), tIeExamInvigilateCallLog.getStatus());
+            ExamRecordCacheUtil.setMonitorLiveUrl(recordId, source.name(), liveUrl, false);
+            ExamRecordCacheUtil.setMonitorStatus(recordId, source.name(), tIeExamInvigilateCallLog.getStatus(), false);
+            String[] columns = new String[]{ExamRecordFieldEnum.monitor_live_url.name(), ExamRecordFieldEnum.monitor_status_source.name()};
+            Object[] values = new Object[]{liveUrl, tIeExamInvigilateCallLog.getStatus()};
+            tOeExamRecordService.dataUpdatesMq(recordId, columns, values);
 
             //监考监控通话信息 发送mq start
             MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.MONITOR_LOG.name(), tIeExamInvigilateCallLog, MqTagEnum.MONITOR_LOG, String.valueOf(tIeExamInvigilateCallLog.getId()), source.name());
@@ -123,7 +126,7 @@ public class TIeInvigilateCallOeController {
         //获取考试记录缓存
         String liveUrl = Objects.nonNull(ExamRecordCacheUtil.getMonitorLiveUrl(recordId, source.name())) ? ExamRecordCacheUtil.getMonitorLiveUrl(recordId, source.name()) : null;
         MonitorCallStatusSourceEnum callStatus = Objects.nonNull(ExamRecordCacheUtil.getMonitorCallStatus(recordId, source.name())) ? ExamRecordCacheUtil.getMonitorCallStatus(recordId, source.name()) : MonitorCallStatusSourceEnum.STOP;
-        ExamRecordCacheUtil.setMonitorStatus(recordId, source.name(), status);
+        ExamRecordCacheUtil.setMonitorStatus(recordId, source.name(), status,true);
         ExamRecordCacheUtil.setMonitorCallStatus(recordId, source.name(), callStatus);
         String monitorKey = ExamRecordCacheUtil.getMonitorKey(recordId);
         TIeExamInvigilateCallLog tIeExamInvigilateCallLog = new TIeExamInvigilateCallLog(recordId, source, liveUrl, MonitorStatusSourceEnum.START, monitorKey, callStatus);

+ 7 - 7
themis-exam/src/main/java/com/qmth/themis/exam/listener/service/impl/MqOeLogicServiceImpl.java

@@ -97,7 +97,7 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
         Gson gson = new Gson();
         ConcurrentHashMap<Long, WebSocketOeServer> webSocketMap = WebSocketOeServer.getWebSocketMap();
         String tag = mqDto.getTag();
-        if (tag.contains(MqTagEnum.OE_MONITOR_FINISH.name())) {//强制离线交卷
+        if (Objects.equals(MqTagEnum.OE_MONITOR_FINISH.name(), tag)) {//强制离线交卷
             Set examRecordId = JacksonUtil.readJson(String.valueOf(mqDto.getBody()), Set.class);
             examRecordId.forEach(s -> {
                 Long recordId = Long.parseLong(String.valueOf(s));
@@ -115,7 +115,7 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
                     teExamStudentLogService.save(teExamStudentLog);
                 }
             });
-        } else if (tag.contains(MqTagEnum.OE_HARD_FINISH.name())) {//手动交卷
+        } else if (Objects.equals(MqTagEnum.OE_HARD_FINISH.name(), tag)) {//手动交卷
             Set examRecordId = JacksonUtil.readJson(String.valueOf(mqDto.getBody()), Set.class);
             examRecordId.forEach(s -> {
                 Long recordId = Long.parseLong(String.valueOf(s));
@@ -132,7 +132,7 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
                     teExamStudentLogService.save(teExamStudentLog);
                 }
             });
-        } else if (tag.contains(MqTagEnum.OE_WARNING_FINISH.name())) {//预警交卷
+        } else if (Objects.equals(MqTagEnum.OE_WARNING_FINISH.name(), tag)) {//预警交卷
             Set examRecordId = JacksonUtil.readJson(String.valueOf(mqDto.getBody()), Set.class);
             examRecordId.forEach(s -> {
                 Long recordId = Long.parseLong(String.valueOf(s));
@@ -149,7 +149,7 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
                     teExamStudentLogService.save(teExamStudentLog);
                 }
             });
-        } else if (tag.contains(MqTagEnum.OE_IM_CLUSTERING.name())) {//点对点消息
+        } else if (Objects.equals(MqTagEnum.OE_IM_CLUSTERING.name(), tag)) {//点对点消息
             Long recordId = Long.parseLong(String.valueOf(mqDto.getBody()));
             if (Objects.nonNull(webSocketMap.get(recordId))) {
                 Long examId = ExamRecordCacheUtil.getExamId(recordId);
@@ -167,11 +167,11 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
                 TIeExamInvigilateNotice tIeExamInvigilateNotice = new TIeExamInvigilateNotice(examId, examActivityId, recordId, Long.parseLong(mqDto.getObjId()), examStudentId, MessageTypeEnum.valueOf(String.valueOf(prop.get("type"))), String.valueOf(prop.get("content")));
                 tIeExamInvigilateNoticeService.saveOrUpdate(tIeExamInvigilateNotice);
             }
-        } else if (tag.contains(MqTagEnum.OE_IM_BROADCASTING.name())) {//广播消息
+        } else if (Objects.equals(MqTagEnum.OE_IM_BROADCASTING.name(), tag)) {//广播消息
             JSONArray jsonArray = JSONArray.parseArray(String.valueOf(mqDto.getBody()));
             Set<String> examStudentIdentitySet = jsonArray.toJavaObject(Set.class);
             log.info("examStudentIdentitySet:{}", JacksonUtil.parseJson(examStudentIdentitySet));
-        } else if (tag.contains(MqTagEnum.OE_LIVENESS_VERIFY.name())) {//监考强制活体验证
+        } else if (Objects.equals(MqTagEnum.OE_LIVENESS_VERIFY.name(), tag)) {//监考强制活体验证
             Long recordId = Long.parseLong(String.valueOf(mqDto.getBody()));
             if (Objects.nonNull(webSocketMap.get(recordId))) {
                 Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
@@ -208,7 +208,7 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
         Gson gson = new Gson();
         ConcurrentHashMap<Long, WebSocketMobileServer> webSocketMap = WebSocketMobileServer.getWebSocketMap();
         String tag = mqDto.getTag();
-        if (tag.contains(MqTagEnum.EXAM_STOP.name())) {//考试暂停
+        if (Objects.equals(MqTagEnum.EXAM_STOP.name(), tag)) {//考试暂停
             Long recordId = Long.parseLong(String.valueOf(mqDto.getBody()));
             if (Objects.nonNull(webSocketMap.get(recordId))) {
                 WebSocketMobileServer webSocketMobileServer = webSocketMap.get(recordId);

+ 1 - 1
themis-exam/src/main/java/com/qmth/themis/exam/start/StartRunning.java

@@ -76,7 +76,7 @@ public class StartRunning implements CommandLineRunner {
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_PERSISTED_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_PERSISTED.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordPersistedConcurrentlyImpl.class));
 
         //考试记录数据更新
-        rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_UPDATE_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_UPDATE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordUpdateConcurrentlyImpl.class));
+        rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_UPDATE_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_UPDATE.name() + "||" + MqTagEnum.EXAM_RECORD_UPDATE_COLUMNS.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordUpdateConcurrentlyImpl.class));
         //考试记录数据初始化
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_INIT_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_INIT.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordInitConcurrentlyImpl.class));
 

+ 1 - 1
themis-exam/src/main/java/com/qmth/themis/exam/websocket/WebSocketMobileServer.java

@@ -144,7 +144,7 @@ public class WebSocketMobileServer implements Concurrently {
             //从set中删除
             subOnlineCount();
             //判断是否是正常退出
-            ExamRecordCacheUtil.setMonitorStatus(recordId, this.source.name(), MonitorStatusSourceEnum.STOP);
+            ExamRecordCacheUtil.setMonitorStatus(recordId, this.source.name(), MonitorStatusSourceEnum.STOP, true);
             ConcurrentHashMap<Long, WebSocketOeServer> webSocketMap = WebSocketOeServer.getWebSocketMap();
             if (Objects.nonNull(webSocketMap.get(recordId))) {
                 WebSocketOeServer webSocketOeServer = webSocketMap.get(recordId);

+ 17 - 10
themis-exam/src/main/java/com/qmth/themis/exam/websocket/WebSocketOeServer.java

@@ -8,11 +8,9 @@ import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.dto.WebsocketDto;
 import com.qmth.themis.business.entity.TBSession;
-import com.qmth.themis.business.enums.MqTagEnum;
-import com.qmth.themis.business.enums.MqTopicEnum;
-import com.qmth.themis.business.enums.WebsocketStatusEnum;
-import com.qmth.themis.business.enums.WebsocketTypeEnum;
+import com.qmth.themis.business.enums.*;
 import com.qmth.themis.business.service.MqDtoService;
+import com.qmth.themis.business.service.TOeExamRecordService;
 import com.qmth.themis.business.util.JacksonUtil;
 import com.qmth.themis.business.util.RedisUtil;
 import com.qmth.themis.business.util.WebsocketUtil;
@@ -117,10 +115,18 @@ public class WebSocketOeServer implements Concurrently {
                     this.ip = addr.toString().replace("/", "").split(":")[0];
 //                    this.sendMessage("ip[" + this.ip + "]连接成功");
                     log.info("ip[:{}]连接成功", this.ip);
-                    ExamRecordCacheUtil.setClientWebsocketStatus(recordId, WebsocketStatusEnum.ON_LINE);
-                    ExamRecordCacheUtil.setClientCurrentIp(recordId, this.ip);
-                    ExamRecordCacheUtil.setClientWebsocketId(recordId, this.session.getId());
-                    ExamRecordCacheUtil.setClientLastSyncTime(recordId);
+                    ExamRecordStatusEnum status = ExamRecordCacheUtil.getStatus(recordId);
+                    if (!Objects.equals(ExamRecordStatusEnum.PERSISTED, status) || !Objects.equals(ExamRecordStatusEnum.FINISHED, status)) {
+                        ExamRecordCacheUtil.setClientWebsocketStatus(recordId, WebsocketStatusEnum.ON_LINE, false);
+                        ExamRecordCacheUtil.setClientCurrentIp(recordId, this.ip, false);
+                        ExamRecordCacheUtil.setClientWebsocketId(recordId, this.session.getId(), false);
+                        Date clientLastSyncTime = new Date();
+                        ExamRecordCacheUtil.setClientLastSyncTime(recordId, clientLastSyncTime, false);
+                        String[] columns = new String[]{ExamRecordFieldEnum.client_websocket_status.name(), ExamRecordFieldEnum.client_current_ip.name(), ExamRecordFieldEnum.client_websocket_id.name(), ExamRecordFieldEnum.client_last_sync_time.name()};
+                        Object[] values = new Object[]{WebsocketStatusEnum.ON_LINE, this.ip, this.session.getId(), clientLastSyncTime};
+                        TOeExamRecordService tOeExamRecordService = SpringContextHolder.getBean(TOeExamRecordService.class);
+                        tOeExamRecordService.dataUpdatesMq(recordId, columns, values);
+                    }
                     tranMap = new HashMap<>();
                     tranMap.put("recordId", this.recordId);
                     tranMap.put("deviceId", this.deviceId);
@@ -148,7 +154,7 @@ public class WebSocketOeServer implements Concurrently {
             subOnlineCount();
             //判断是否是正常退出
             Date now = new Date();
-            ExamRecordCacheUtil.setClientWebsocketStatus(recordId, WebsocketStatusEnum.OFF_LINE);
+            ExamRecordCacheUtil.setClientWebsocketStatus(recordId, WebsocketStatusEnum.OFF_LINE, true);
             //大于等于超时时间,说明规定时间内都没有通信,非正常退出,因为期间会有心跳更新updateTime
             if ((now.getTime() - this.updateTime) / 1000 >= SystemConstant.WEBSOCKET_MAX_TIME_OUT / 1000) {
                 log.info("超时退出");
@@ -266,7 +272,8 @@ public class WebSocketOeServer implements Concurrently {
     }
 
     @Override
-    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
+    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext
+            consumeConcurrentlyContext) {
         RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
         MqOeLogicService mqOeLogicService = SpringContextHolder.getBean(MqOeLogicService.class);
         MqDto mqDto = null;

+ 13 - 4
themis-exam/src/main/java/com/qmth/themis/exam/websocketTemplete/WebSocketOeMessageTemplete.java

@@ -5,7 +5,9 @@ import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.WebsocketDto;
+import com.qmth.themis.business.enums.ExamRecordFieldEnum;
 import com.qmth.themis.business.enums.WebsocketTypeEnum;
+import com.qmth.themis.business.service.TOeExamRecordService;
 import com.qmth.themis.business.util.RedisUtil;
 import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.exception.BusinessException;
@@ -33,6 +35,9 @@ public class WebSocketOeMessageTemplete {
     @Resource
     RedisUtil redisUtil;
 
+    @Resource
+    TOeExamRecordService tOeExamRecordService;
+
     /**
      * 客户端已下载试卷
      *
@@ -50,7 +55,7 @@ public class WebSocketOeMessageTemplete {
         if (Objects.isNull(objectMap)) {
             throw new BusinessException(ExceptionResultEnum.RECORD_NO);
         }
-        ExamRecordCacheUtil.setPaperDownload(recordId, 0);
+        ExamRecordCacheUtil.setPaperDownload(recordId, 0, true);
         return new WebsocketDto(Collections.singletonMap("success", true));
     }
 
@@ -79,9 +84,13 @@ public class WebSocketOeMessageTemplete {
         if (Objects.isNull(objectMap)) {
             throw new BusinessException(ExceptionResultEnum.RECORD_NO);
         }
-        ExamRecordCacheUtil.setAnswerProgress(recordId, progress);
-        ExamRecordCacheUtil.setDurationSeconds(recordId, durationSeconds);
-        ExamRecordCacheUtil.setClientLastSyncTime(recordId);
+        ExamRecordCacheUtil.setAnswerProgress(recordId, progress, false);
+        ExamRecordCacheUtil.setDurationSeconds(recordId, durationSeconds, false);
+        Date clientLastSyncTime = new Date();
+        ExamRecordCacheUtil.setClientLastSyncTime(recordId, clientLastSyncTime, false);
+        String[] columns = new String[]{ExamRecordFieldEnum.answer_progress.name(), ExamRecordFieldEnum.duration_seconds.name(), ExamRecordFieldEnum.client_last_sync_time.name()};
+        Object[] values = new Object[]{progress, durationSeconds, clientLastSyncTime};
+        tOeExamRecordService.dataUpdatesMq(recordId, columns, values);
         return this.syncAck(body);
     }
 

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

@@ -34,7 +34,10 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.io.IOException;
-import java.util.*;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 /**
  * @Description: mq执行逻辑 impl
@@ -130,10 +133,10 @@ public class MqLogicServiceImpl implements MqLogicService {
     public void execMqUserLogLogic(MqDto mqDto, String key) {
         Gson gson = new Gson();
         String tag = mqDto.getTag();
-        if (tag.contains(MqTagEnum.USER.name())) {
+        if (Objects.equals(MqTagEnum.USER.name(), tag)) {
             TEUserLog teUserLog = new TEUserLog(String.valueOf(mqDto.getBody()), SystemOperationEnum.valueOf(String.valueOf(mqDto.getBody())).getCode(), SystemOperationEnum.valueOf(String.valueOf(mqDto.getBody())).getCode(), Long.parseLong(String.valueOf(mqDto.getObjId())));
             teUserLogService.save(teUserLog);
-        } else if (tag.contains(MqTagEnum.STUDENT.name())) {
+        } else if (Objects.equals(MqTagEnum.STUDENT.name(), tag)) {
             TEExamStudentLog teExamStudentLog = null;
             if (Objects.nonNull(mqDto.getProperties())) {
                 teExamStudentLog = new TEExamStudentLog(String.valueOf(mqDto.getBody()), SystemOperationEnum.valueOf(String.valueOf(mqDto.getBody())).getCode(), String.valueOf(mqDto.getProperties().get("remark")), Long.parseLong(String.valueOf(mqDto.getObjId())), Long.parseLong(String.valueOf(mqDto.getProperties().get("examStudentId"))), Long.parseLong(String.valueOf(mqDto.getProperties().get("examRecordId"))));
@@ -182,11 +185,11 @@ public class MqLogicServiceImpl implements MqLogicService {
         myThreadPool.arbitratePoolTaskExecutor.execute(() -> {
             if (tag.contains("Import".toUpperCase())) {
                 TaskImportTemplete taskImportTemplete = null;
-                if (tag.contains(MqTagEnum.EXAM_STUDENT_IMPORT.name())) {
+                if (Objects.equals(MqTagEnum.EXAM_STUDENT_IMPORT.name(), tag)) {
                     taskImportTemplete = SpringContextHolder.getBean(TaskExamStudentImportTemplete.class);
-                } else if (tag.contains(MqTagEnum.ROOM_CODE_IMPORT.name())) {
+                } else if (Objects.equals(MqTagEnum.ROOM_CODE_IMPORT.name(), tag)) {
                     taskImportTemplete = SpringContextHolder.getBean(TaskRoomCodeImportTemplete.class);
-                } else if (tag.contains(MqTagEnum.EXAM_PAPER_IMPORT.name())) {
+                } else if (Objects.equals(MqTagEnum.EXAM_PAPER_IMPORT.name(), tag)) {
                     taskImportTemplete = SpringContextHolder.getBean(TaskExamPaperImportTemplete.class);
                 }
                 try {
@@ -196,7 +199,7 @@ public class MqLogicServiceImpl implements MqLogicService {
                 }
             } else {
                 TaskExportTemplete taskExportTemplete = null;
-                if (tag.contains(MqTagEnum.ROOM_CODE_EXPORT.name())) {
+                if (Objects.equals(MqTagEnum.ROOM_CODE_EXPORT.name(), tag)) {
                     taskExportTemplete = SpringContextHolder.getBean(TaskRoomCodeExportTemplete.class);
                 }
                 try {
@@ -235,7 +238,7 @@ public class MqLogicServiceImpl implements MqLogicService {
                 Long l = (System.currentTimeMillis() - clientLastSyncTime.getTime()) / 1000;
                 if (l >= 2 && !Objects.equals(ExamRecordCacheUtil.getStatus(recordId), ExamRecordStatusEnum.FINISHED)) {
                     diff = l.intValue();
-                    ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.BREAK_OFF);
+                    ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.BREAK_OFF, true);
                 }
             }
             ExamRecordStatusEnum status = ExamRecordCacheUtil.getStatus(recordId);
@@ -256,11 +259,16 @@ public class MqLogicServiceImpl implements MqLogicService {
                 } else {
                     alreadyBreakCount++;
                     breakId = Constants.idGen.next();
-                    ExamRecordCacheUtil.setLastBreakId(recordId, breakId);
-                    ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.BREAK_OFF);
-                    ExamRecordCacheUtil.setLastBreakTime(recordId);
-                    ExamRecordCacheUtil.setAlreadyBreakCount(recordId, alreadyBreakCount);
-                    ExamRecordCacheUtil.setLastStartTime(recordId);
+                    ExamRecordCacheUtil.setLastBreakId(recordId, breakId, false);
+                    ExamRecordCacheUtil.setStatus(recordId, ExamRecordStatusEnum.BREAK_OFF, false);
+                    Date lastBreakTime = new Date();
+                    ExamRecordCacheUtil.setLastBreakTime(recordId, lastBreakTime, false);
+                    ExamRecordCacheUtil.setAlreadyBreakCount(recordId, alreadyBreakCount, false);
+                    Date lastStartTime = new Date();
+                    ExamRecordCacheUtil.setLastStartTime(recordId, lastStartTime, false);
+                    String[] columns = new String[]{ExamRecordFieldEnum.last_break_id.name(), ExamRecordFieldEnum.status.name(), ExamRecordFieldEnum.last_break_time.name(), ExamRecordFieldEnum.already_break_count.name(), ExamRecordFieldEnum.last_start_time.name()};
+                    Object[] values = new Object[]{breakId, ExamRecordStatusEnum.BREAK_OFF, lastBreakTime, alreadyBreakCount, lastStartTime};
+                    examRecordService.dataUpdatesMq(recordId, columns, values);
                     //考试断点异常原因 发送mq start
                     MqDto mqDtoBreak = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_BREAK.name(), ExceptionEnum.NET_TIME_OUT, MqTagEnum.EXAM_BREAK, String.valueOf(recordId), String.valueOf(recordId));
                     mqDtoService.assembleSendOneWayMsg(mqDtoBreak);
@@ -417,17 +425,32 @@ public class MqLogicServiceImpl implements MqLogicService {
     @Transactional
     public void execMqRecordUpdateLogic(MqDto mqDto, String key) {
         Gson gson = new Gson();
-        Map<String, Object> param = (Map<String, Object>) mqDto.getBody();
-        Long recordId = Long.parseLong(String.valueOf(param.get("recordId")));
-        String colName = String.valueOf(param.get("colName"));
-        Object colValue = param.get("colValue");
-        Integer isDate = Integer.parseInt(String.valueOf(param.get("isDate")));
-        if (colName.contains("client_last_sync_time") || colName.contains("last_break_time") || colName.contains("last_start_time")) {
-            Date date = new Date();
-            date.setTime(Long.parseLong(String.valueOf(colValue)));
-            examRecordService.dataUpdate(recordId, colName, date, isDate);
-        } else {
+        String tag = mqDto.getTag();
+        if (Objects.equals(tag, MqTagEnum.EXAM_RECORD_UPDATE.name())) {//单字段更新
+            Map<String, Object> param = (Map<String, Object>) mqDto.getBody();
+            Long recordId = (Long) param.get("recordId");
+            String colName = (String) param.get("colName");
+            Object colValue = param.get("colValue");
+            Integer isDate = (Integer) param.get("isDate");
             examRecordService.dataUpdate(recordId, colName, colValue, isDate);
+        } else if (Objects.equals(tag, MqTagEnum.EXAM_RECORD_UPDATE_COLUMNS.name())) {//多字段更新
+            Map<String, Object> param = (Map<String, Object>) mqDto.getBody();
+            Long recordId = Long.parseLong(String.valueOf(param.get("recordId")));
+            List<String> colNames = (List<String>) (param.get("colNames"));
+            List<Object> colValues = (List<Object>) param.get("colValues");
+            UpdateWrapper<TOeExamRecord> tOeExamRecordUpdateWrapper = new UpdateWrapper<>();
+            for (int i = 0; i < colNames.size(); i++) {
+                String colName = colNames.get(i);
+                Object colValue = colValues.get(i);
+                if (Objects.equals(ExamRecordFieldEnum.finish_time.name(), colName) || Objects.equals(ExamRecordFieldEnum.first_start_time.name(), colName) || Objects.equals(ExamRecordFieldEnum.first_prepare_time.name(), colName) || Objects.equals(ExamRecordFieldEnum.start_time.name(), colName) || Objects.equals(ExamRecordFieldEnum.end_time.name(), colName) || Objects.equals(ExamRecordFieldEnum.client_last_sync_time.name(), colName) || Objects.equals(ExamRecordFieldEnum.last_break_time.name(), colName) || Objects.equals(ExamRecordFieldEnum.last_start_time.name(), colName) || Objects.equals(ExamRecordFieldEnum.last_prepare_time.name(), colName)) {
+                    Date date = new Date((Long) colValue);
+                    tOeExamRecordUpdateWrapper.set(colName, date);
+                } else {
+                    tOeExamRecordUpdateWrapper.set(colName, colValue);
+                }
+            }
+            tOeExamRecordUpdateWrapper.lambda().eq(TOeExamRecord::getId, recordId);
+            examRecordService.update(tOeExamRecordUpdateWrapper);
         }
         mqDto.setAck(SystemConstant.STANDARD_ACK_TYPE);
         TMRocketMessage tmRocketMessage = gson.fromJson(gson.toJson(mqDto), TMRocketMessage.class);
@@ -460,7 +483,7 @@ public class MqLogicServiceImpl implements MqLogicService {
     public void execMqLogLogic(MqDto mqDto, String key) {
         Gson gson = new Gson();
         String tag = mqDto.getTag();
-        if (tag.contains(MqTagEnum.MONITOR_LOG.name())) {//监考日志
+        if (Objects.equals(MqTagEnum.MONITOR_LOG.name(), tag)) {//监考日志
             TIeExamInvigilateCallLog tIeExamInvigilateCallLog = JacksonUtil.readJson(JacksonUtil.parseJson(mqDto.getBody()), TIeExamInvigilateCallLog.class);
             Long recordId = tIeExamInvigilateCallLog.getExamRecordId();
             Long examId = null, examActivityId = null, examStudentId = null;
@@ -497,7 +520,7 @@ public class MqLogicServiceImpl implements MqLogicService {
                 tIeExamInvigilateCallService.saveOrUpdate(tIeExamInvigilateCall);
             }
             tIeExamInvigilateCallLogService.saveOrUpdate(tIeExamInvigilateCallLog);
-        } else if (tag.contains(MqTagEnum.EXCEPTION_LOG.name())) {//考试断点异常日志
+        } else if (Objects.equals(MqTagEnum.EXCEPTION_LOG.name(), tag)) {//考试断点异常日志
             JSONObject jsonObject = JSONObject.parseObject(String.valueOf(mqDto.getBody()));
             ExceptionEnum exceptionEnum = ExceptionEnum.valueOf(ExceptionEnum.convertToName(String.valueOf(jsonObject.getJSONObject("reason").get("type"))));
             Long recordId = Long.parseLong(mqDto.getObjId());
@@ -527,7 +550,7 @@ public class MqLogicServiceImpl implements MqLogicService {
                         .eq(TEExamStudentLog::getObjId, breakId);
                 teExamStudentLogService.update(teExamStudentLogUpdateWrapper);
             }
-        } else if (tag.contains(MqTagEnum.WARNING_LOG.name())) {//考试预警日志
+        } else if (Objects.equals(MqTagEnum.WARNING_LOG.name(), tag)) {//考试预警日志
             //todo 预警先预留
         }
         mqDto.setAck(SystemConstant.STANDARD_ACK_TYPE);

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

@@ -95,7 +95,7 @@ public class StartRunning implements CommandLineRunner {
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_PERSISTED_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_PERSISTED.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordPersistedConcurrentlyImpl.class));
 
         //考试记录数据更新
-        rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_UPDATE_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_UPDATE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordUpdateConcurrentlyImpl.class));
+        rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_UPDATE_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_UPDATE.name() + "||" + MqTagEnum.EXAM_RECORD_UPDATE_COLUMNS.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordUpdateConcurrentlyImpl.class));
 
         //考试记录数据初始化
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.EXAM_RECORD_INIT_GROUP.getCode(), MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.EXAM_RECORD_INIT.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(ExamRecordInitConcurrentlyImpl.class));