Browse Source

优化代码

wangliang 1 year ago
parent
commit
86fdf28914
18 changed files with 379 additions and 371 deletions
  1. 1 2
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamController.java
  2. 52 0
      themis-business/src/main/java/com/qmth/themis/business/bean/admin/ExamListBean.java
  3. 3 2
      themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java
  4. 15 0
      themis-business/src/main/java/com/qmth/themis/business/entity/TEExamSummary.java
  5. 2 0
      themis-business/src/main/java/com/qmth/themis/business/entity/TEOrgSummary.java
  6. 16 0
      themis-business/src/main/java/com/qmth/themis/business/entity/TERegionSummary.java
  7. 5 1
      themis-business/src/main/java/com/qmth/themis/business/enums/FieldUniqueEnum.java
  8. 0 15
      themis-business/src/main/java/com/qmth/themis/business/service/TEOrgSummaryService.java
  9. 3 25
      themis-business/src/main/java/com/qmth/themis/business/service/ThemisCacheService.java
  10. 1 1
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamActivityServiceImpl.java
  11. 71 108
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamSummaryServiceImpl.java
  12. 4 72
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEOrgSummaryServiceImpl.java
  13. 15 24
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TERegionSummaryServiceImpl.java
  14. 21 18
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java
  15. 70 50
      themis-business/src/main/java/com/qmth/themis/business/service/impl/ThemisCacheServiceImpl.java
  16. 21 0
      themis-business/src/main/java/com/qmth/themis/business/util/RedisUtil.java
  17. 47 34
      themis-task/src/main/java/com/qmth/themis/task/quartz/ExamSummaryJob.java
  18. 32 19
      themis-task/src/main/java/com/qmth/themis/task/quartz/MqActivityJob.java

+ 1 - 2
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamController.java

@@ -223,10 +223,9 @@ public class TEExamController {
                 teExamActivityService.saveOrUpdate(teExamActivity);
                 teExamActivityService.updateExamActivityCacheBean(teExamActivity.getId());
             }
-            themisCacheService.updateTodayExamIdListCache(teExam.getId());
             List<TEExamActivity> teExamActivityList = teExamActivityService.list(new QueryWrapper<TEExamActivity>().lambda().eq(TEExamActivity::getExamId, teExam.getId()).eq(TEExamActivity::getEnable, 1));
             for (TEExamActivity t : teExamActivityList) {
-                themisCacheService.updateTodayExamListCache(t.getExamId().toString(), t.getId().toString());
+                themisCacheService.updateTodayExamListCache(t.getExamId().toString(), t.getId());
                 themisCacheService.updateOrgExamListCache(teExam.getOrgId().toString(), t.getExamId().toString(), t.getId());
             }
         } catch (Exception e) {

+ 52 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/admin/ExamListBean.java

@@ -0,0 +1,52 @@
+package com.qmth.themis.business.bean.admin;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * @Description: 考试列表集合
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2023/10/27
+ */
+public class ExamListBean implements Serializable {
+
+    @ApiModelProperty(name = "考试场次id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Long examActivityId;
+
+    @ApiModelProperty(name = "考场编码集合")
+    @JsonSerialize(using = ToStringSerializer.class)
+    private Set<String> roomCodeSet;
+
+    public ExamListBean() {
+
+    }
+
+    public ExamListBean(Long examActivityId, Set<String> roomCodeSet) {
+        this.examActivityId = examActivityId;
+        this.roomCodeSet = roomCodeSet;
+    }
+
+    public Long getExamActivityId() {
+        return examActivityId;
+    }
+
+    public void setExamActivityId(Long examActivityId) {
+        this.examActivityId = examActivityId;
+    }
+
+    public Set<String> getRoomCodeSet() {
+        return roomCodeSet;
+    }
+
+    public void setRoomCodeSet(Set<String> roomCodeSet) {
+        this.roomCodeSet = roomCodeSet;
+    }
+}
+

+ 3 - 2
themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java

@@ -209,14 +209,15 @@ public class SystemConstant {
     public static final Integer BEFORE_AUDIO_SECOND = 60;
     public static final Integer AFTER_AUDIO_SECOND = 900;
     public static final long FINISH_DELAY_TIME = 1000 * 60 * 5;
+    public static final String EXAM_ACTIVITY_ID = "examActivityId";
+    public static final String ROOM_CODE_SET = "roomCodeSet";
     //    public static final String AUTH_INFO_CACHE = "auth:info:cache";
     public static final String EXAM_AUDIO_CACHE = "exam:audio:cache";
     public static final String ATTACHMENT_CACHE = "attachment:cache";
     public static final String BLACK_LIST_CACHE = "blacklist:cache";
     public static final String SYS_NOTIFY_CACHE = "sys:notify:cache";
     public static final String PROBLEM_CACHE = "problem:cache";
-    public static final String TODAY_EXAM_MAP_CACHE = "today:exam:list:map:cache:";
-    public static final String TODAY_EXAM_ID_LIST_CACHE = "today:exam:id:list:cache";
+    public static final String TODAY_EXAM_LIST_MAP_CACHE = "today:exam:list:map:cache";
     public static final String ORG_EXAM_LIST_MAP_CACHE = "org:exam:list:map:cache:";
 
     public volatile static Searcher SEARCHER = null;

+ 15 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TEExamSummary.java

@@ -20,6 +20,11 @@ import java.io.Serializable;
 public class TEExamSummary implements Serializable {
     private static final long serialVersionUID = 1L;
 
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id")
+    private Long id;
+
     @ApiModelProperty(value = "考试批次id")
     @JsonSerialize(using = ToStringSerializer.class)
     private Long examId;
@@ -67,6 +72,16 @@ public class TEExamSummary implements Serializable {
     @ApiModelProperty(value = "异常数据总数")
     private Integer exceptionCount = 0;
 
+
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
     public Long getExamId() {
         return examId;
     }

+ 2 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TEOrgSummary.java

@@ -1,5 +1,6 @@
 package com.qmth.themis.business.entity;
 
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import io.swagger.annotations.ApiModel;
@@ -22,6 +23,7 @@ public class TEOrgSummary implements Serializable {
 
     @ApiModelProperty(value = "机构ID,全局为0")
     @JsonSerialize(using = ToStringSerializer.class)
+    @TableId(value = "org_id")
     private Long orgId = 0L;
 
     @ApiModelProperty(value = "在线人数")

+ 16 - 0
themis-business/src/main/java/com/qmth/themis/business/entity/TERegionSummary.java

@@ -1,5 +1,8 @@
 package com.qmth.themis.business.entity;
 
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
@@ -17,6 +20,11 @@ import java.io.Serializable;
 public class TERegionSummary implements Serializable {
     private static final long serialVersionUID = 1L;
 
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty(value = "主键")
+    @TableId(value = "id")
+    private Long id;
+
     @ApiModelProperty(value = "国家")
     private String country;
 
@@ -26,6 +34,14 @@ public class TERegionSummary implements Serializable {
     @ApiModelProperty(value = "在线人数")
     private Integer onlineCount;
 
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
     public String getCountry() {
         return country;
     }

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

@@ -43,7 +43,11 @@ public enum FieldUniqueEnum {
 
     soft_index("软件和进程名称"),
 
-    t_ie_exam_media_log_UN_content("多媒体消息");
+    t_ie_exam_media_log_UN_content("多媒体消息"),
+
+    t_e_exam_summary_UN("考试统计"),
+
+    t_e_region_summary_UN("地区统计");
 
     private String code;
 

+ 0 - 15
themis-business/src/main/java/com/qmth/themis/business/service/TEOrgSummaryService.java

@@ -23,21 +23,6 @@ public interface TEOrgSummaryService extends IService<TEOrgSummary> {
      */
     public void orgSummary(Long orgId, List<Long> examIdSet);
 
-    /**
-     * 保存机构统计信息
-     *
-     * @param teOrgSummary
-     */
-    public void saveOrgSummaryCommon(TEOrgSummary teOrgSummary);
-
-    /**
-     * 更新机构统计信息
-     *
-     * @param orgId
-     * @param teOrgSummary
-     */
-    public void updateOrgSummaryCommon(Long orgId, TEOrgSummary teOrgSummary);
-
     /**
      * 更新全局机构考试完成数量和考生完成数量
      *

+ 3 - 25
themis-business/src/main/java/com/qmth/themis/business/service/ThemisCacheService.java

@@ -372,7 +372,7 @@ public interface ThemisCacheService {
      * @param examId
      * @return
      */
-    public Map<String, Set<String>> getTodayExamListCache(String examId);
+    public Map<String, List<String>> getTodayExamListCache(String examId);
 
     /**
      * 更新当天考试缓存
@@ -380,7 +380,7 @@ public interface ThemisCacheService {
      * @param examId
      * @param examActivityId
      */
-    public void updateTodayExamListCache(String examId, String examActivityId);
+    public void updateTodayExamListCache(String examId, Long examActivityId);
 
     /**
      * 删除当天考试缓存
@@ -394,29 +394,7 @@ public interface ThemisCacheService {
      *
      * @return
      */
-    public void removeTodayExamListCache(String examId, String examActivityId);
-
-    /**
-     * 获取当天考试列表缓存
-     *
-     * @return
-     */
-    public Set<Long> getTodayExamIdListCache();
-
-    /**
-     * 更新当天考试列表缓存
-     *
-     * @param examId
-     * @return
-     */
-    public void updateTodayExamIdListCache(Long examId);
-
-    /**
-     * 删除当天考试列表缓存
-     *
-     * @return
-     */
-    public void removeTodayExamIdListCache(Long examId);
+    public void removeTodayExamListCache(String examId, Long examActivityId);
 
     /**
      * 获取考试统计缓存

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

@@ -413,7 +413,7 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
             teExamActivityService.saveOrUpdateBatch(teExamActivityList);
 
             for (TEExamActivity ac : teExamActivityList) {
-                themisCacheService.updateTodayExamListCache(ac.getExamId().toString(), ac.getId().toString());
+                themisCacheService.updateTodayExamListCache(ac.getExamId().toString(), ac.getId());
                 themisCacheService.updateOrgExamListCache(teExam.getOrgId().toString(), ac.getExamId().toString(), ac.getId());
                 teExamActivityService.updateExamActivityCacheBean(ac.getId());
             }

+ 71 - 108
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamSummaryServiceImpl.java

@@ -1,5 +1,6 @@
 package com.qmth.themis.business.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
@@ -7,18 +8,18 @@ import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dao.TEExamSummaryMapper;
 import com.qmth.themis.business.entity.TEExamSummary;
 import com.qmth.themis.business.enums.ExamModeEnum;
-import com.qmth.themis.business.enums.ExamSummaryEnum;
 import com.qmth.themis.business.service.TEExamActivityService;
 import com.qmth.themis.business.service.TEExamService;
 import com.qmth.themis.business.service.TEExamSummaryService;
 import com.qmth.themis.business.service.ThemisCacheService;
+import com.qmth.themis.business.util.UidUtil;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
 import java.util.Objects;
 import java.util.Set;
-import java.util.StringJoiner;
 
 /**
  * <p>
@@ -48,114 +49,76 @@ public class TEExamSummaryServiceImpl extends ServiceImpl<TEExamSummaryMapper, T
      * @param roomCodeSet
      */
     @Override
-    @Transactional
+//    @Transactional
     public void examSummary(Long examId, Long examActivityId, Set<String> roomCodeSet) {
-        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
-        for (String s : roomCodeSet) {
-            //根据考试批次、场次、考场编码统计信息
-            TEExamSummary teExamSummary = this.baseMapper.examSummary(examId, examActivityId, s);
-            if (Objects.nonNull(teExamSummary)) {
-                teExamSummary.setExamId(examId);
-                teExamSummary.setExamActivityId(examActivityId);
-                teExamSummary.setRoomCode(s);
-                ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(examActivityId);
-                //换算开始时间和结束时间
-                Long startTime = null, endTime = null;
-                if (ExamModeEnum.ANYTIME.equals(examCacheBean.getMode())) {
-                    startTime = ac.getStartTime() - (ac.getPrepareSeconds() * 1000);
-                    endTime = ac.getFinishTime();
-                    endTime = endTime + (1000 * 60 * 5);//额外加5分钟,有可能后台交卷未完成
-                } else {
-                    startTime = ac.getStartTime() - (ac.getPrepareSeconds() * 1000);
-                    Integer openingSecondsTemp = ac.getOpeningSeconds();
-                    openingSecondsTemp = Objects.nonNull(openingSecondsTemp) && openingSecondsTemp.intValue() == 0 ? SystemConstant.DEFAULT_OPENING_SECONDS : openingSecondsTemp;
-                    endTime = ac.getStartTime() + (openingSecondsTemp * 1000);
-                    endTime = endTime + (1000 * 60 * 5);//额外加5分钟,有可能后台交卷未完成
-                }
+        if (!CollectionUtils.isEmpty(roomCodeSet)) {
+            for (String s : roomCodeSet) {
+                //根据考试批次、场次、考场编码统计信息
+                TEExamSummary teExamSummary = this.baseMapper.examSummary(examId, examActivityId, s);
+                this.examSummaryCommon(examId, examActivityId, s, teExamSummary);
+            }
+        } else {
+            TEExamSummary teExamSummary = this.baseMapper.examSummary(examId, examActivityId, null);
+            this.examSummaryCommon(examId, examActivityId, null, teExamSummary);
+        }
+    }
+
+    /**
+     * 考试计算公用
+     *
+     * @param examId
+     * @param examActivityId
+     * @param s
+     * @param teExamSummary
+     */
+    protected void examSummaryCommon(Long examId, Long examActivityId, String s, TEExamSummary teExamSummary) {
+        if (Objects.nonNull(teExamSummary) && teExamSummary.getTotalCount().intValue() > 0) {
+            teExamSummary.setExamId(examId);
+            teExamSummary.setExamActivityId(examActivityId);
+            teExamSummary.setRoomCode(s);
+            ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
+            ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(examActivityId);
+            //换算开始时间和结束时间
+            Long startTime = null, endTime = null;
+            if (ExamModeEnum.ANYTIME.equals(examCacheBean.getMode())) {
+                startTime = ac.getStartTime() - (ac.getPrepareSeconds() * 1000);
+                endTime = ac.getFinishTime();
+                endTime = endTime + (1000 * 60 * 5);//额外加5分钟,有可能后台交卷未完成
+            } else {
+                startTime = ac.getStartTime() - (ac.getPrepareSeconds() * 1000);
+                Integer openingSecondsTemp = ac.getOpeningSeconds();
+                openingSecondsTemp = Objects.nonNull(openingSecondsTemp) && openingSecondsTemp.intValue() == 0 ? SystemConstant.DEFAULT_OPENING_SECONDS : openingSecondsTemp;
+                endTime = ac.getStartTime() + (openingSecondsTemp * 1000);
+                endTime = endTime + (1000 * 60 * 5);//额外加5分钟,有可能后台交卷未完成
+            }
 
-                //当考试场次开始时间已过且未结束考试,当前侯考数设为0,缺考数设为侯考数
-                long timestamp = System.currentTimeMillis();
-                if (teExamSummary.getPrepareCount().intValue() > 0) {//侯考
-                    teExamSummary.setAbsentCount(teExamSummary.getTotalCount() - teExamSummary.getPrepareCount());
-                }
-                //考试中
-                if (startTime <= timestamp && endTime >= timestamp) {
-                    teExamSummary.setPrepareCount(0);
-                    teExamSummary.setAbsentCount(teExamSummary.getTotalCount() - teExamSummary.getExamCount() - teExamSummary.getFinishCount());
-                }//交卷
-                else if (endTime <= timestamp) {//当考试场次结束时间已过,缺考=全部应考-已完成考试
-                    teExamSummary.setAbsentCount(teExamSummary.getTotalCount() - teExamSummary.getFinishCount());
-                }
-                int count = this.baseMapper.selectExamSummaryCount(examId, examActivityId, s);
-                StringJoiner stringJoinerFieldName = new StringJoiner(",");
-                StringJoiner stringJoinerFieldValue = new StringJoiner(",");
-                ExamSummaryEnum[] examSummaryEnums = ExamSummaryEnum.values();
-                if (count == 0) {
-                    for (int i = 0; i < examSummaryEnums.length; i++) {
-                        stringJoinerFieldName.add(examSummaryEnums[i].getCode());
-                    }
-                    stringJoinerFieldValue.add("'" + teExamSummary.getExamId() + "'")
-                            .add("'" + teExamSummary.getExamActivityId() + "'")
-                            .add("'" + teExamSummary.getRoomCode() + "'")
-                            .add(teExamSummary.getTotalCount() + "")
-                            .add(teExamSummary.getPrepareCount() + "")
-                            .add(teExamSummary.getExamCount() + "")
-                            .add(teExamSummary.getFinishCount() + "")
-                            .add(teExamSummary.getAbsentCount() + "")
-                            .add(teExamSummary.getOnlineCount() + "")
-                            .add(teExamSummary.getOfflineCount() + "")
-                            .add(teExamSummary.getMonitorStopCount() + "")
-                            .add(teExamSummary.getWarningCount() + "")
-                            .add(teExamSummary.getWarningUnread() + "")
-                            .add(teExamSummary.getWarningMultipleFaceCount() + "")
-                            .add(teExamSummary.getExceptionCount() + "");
-                    this.baseMapper.saveExamSummary(stringJoinerFieldName.toString(), stringJoinerFieldValue.toString());
-                } else {
-                    for (int i = 0; i < examSummaryEnums.length; i++) {
-                        switch (examSummaryEnums[i]) {
-                            case totalCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getTotalCount());
-                                break;
-                            case prepareCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getPrepareCount());
-                                break;
-                            case examCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getExamCount());
-                                break;
-                            case finishCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getFinishCount());
-                                break;
-                            case absentCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getAbsentCount());
-                                break;
-                            case onlineCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getOnlineCount());
-                                break;
-                            case offlineCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getOfflineCount());
-                                break;
-                            case monitorStopCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getMonitorStopCount());
-                                break;
-                            case warningCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getWarningCount());
-                                break;
-                            case warningUnread:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getWarningUnread());
-                                break;
-                            case warningMultipleFaceCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getWarningMultipleFaceCount());
-                                break;
-                            case exceptionCount:
-                                stringJoinerFieldValue.add(examSummaryEnums[i].getCode() + "=" + teExamSummary.getExceptionCount());
-                                break;
-                            default:
-                                break;
-                        }
-                    }
-                    this.baseMapper.updateExamSummary(examId, examActivityId, s, stringJoinerFieldValue.toString());
-                }
+            //当考试场次开始时间已过且未结束考试,当前侯考数设为0,缺考数设为侯考数
+            long timestamp = System.currentTimeMillis();
+            if (teExamSummary.getPrepareCount().intValue() > 0) {//侯考
+                teExamSummary.setAbsentCount(teExamSummary.getTotalCount() - teExamSummary.getPrepareCount());
+            }
+            //考试中
+            if (startTime <= timestamp && endTime >= timestamp) {
+                teExamSummary.setPrepareCount(0);
+                teExamSummary.setAbsentCount(teExamSummary.getTotalCount() - teExamSummary.getExamCount() - teExamSummary.getFinishCount());
+            }//交卷
+            else if (endTime <= timestamp) {//当考试场次结束时间已过,缺考=全部应考-已完成考试
+                teExamSummary.setAbsentCount(teExamSummary.getTotalCount() - teExamSummary.getFinishCount());
+            }
+            TEExamSummary teExamSummaryDb = this.getOne(new QueryWrapper<TEExamSummary>().lambda()
+                    .eq(TEExamSummary::getExamId, examId)
+                    .eq(TEExamSummary::getExamActivityId, examActivityId)
+                    .eq(TEExamSummary::getRoomCode, s));
+            if (Objects.isNull(teExamSummaryDb)) {
+                teExamSummaryDb = new TEExamSummary();
+                BeanUtils.copyProperties(teExamSummary, teExamSummaryDb);
+                teExamSummaryDb.setId(UidUtil.nextId());
+            } else {
+                Long id = teExamSummaryDb.getId();
+                BeanUtils.copyProperties(teExamSummary, teExamSummaryDb);
+                teExamSummaryDb.setId(id);
             }
+            this.saveOrUpdate(teExamSummaryDb);
             themisCacheService.updateExamSummaryCache(examId);
             themisCacheService.updateExamSummaryCache(examId, examActivityId);
             themisCacheService.updateExamSummaryCache(examId, examActivityId, s);

+ 4 - 72
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEOrgSummaryServiceImpl.java

@@ -6,7 +6,6 @@ import com.qmth.themis.business.dao.TEOrgSummaryMapper;
 import com.qmth.themis.business.entity.TBOrg;
 import com.qmth.themis.business.entity.TEExamSummary;
 import com.qmth.themis.business.entity.TEOrgSummary;
-import com.qmth.themis.business.enums.OrgSummaryEnum;
 import com.qmth.themis.business.service.TEExamService;
 import com.qmth.themis.business.service.TEOrgSummaryService;
 import com.qmth.themis.business.service.ThemisCacheService;
@@ -17,7 +16,6 @@ import org.springframework.util.LinkedMultiValueMap;
 
 import javax.annotation.Resource;
 import java.util.List;
-import java.util.StringJoiner;
 
 /**
  * <p>
@@ -46,19 +44,14 @@ public class TEOrgSummaryServiceImpl extends ServiceImpl<TEOrgSummaryMapper, TEO
      * @param examIdSet
      */
     @Override
-    @Transactional
+//    @Transactional
     public void orgSummary(Long orgId, List<Long> examIdSet) {
-        int count = this.baseMapper.selectOrgSummaryCount(orgId);
         if (orgId.longValue() == 0) {//全局机构
             Integer onlineCount = this.baseMapper.orgSummaryByOnlineCount(examIdSet);
             Integer examCount = this.baseMapper.orgSummaryByExamCount(examIdSet);
             List<Integer> finishCountList = this.baseMapper.orgSummaryByFinishCountAndFinishStudentCount(examIdSet);
             TEOrgSummary teOrgSummary = new TEOrgSummary(orgId, onlineCount, examCount, finishCountList.get(0), finishCountList.get(1));
-            if (count == 0) {
-                teOrgSummaryService.saveOrgSummaryCommon(teOrgSummary);
-            } else {
-                teOrgSummaryService.updateOrgSummaryCommon(orgId, teOrgSummary);
-            }
+            teOrgSummaryService.saveOrUpdate(teOrgSummary);
         } else {
             LinkedMultiValueMap<Long, Long> orgExamIdMap = new LinkedMultiValueMap<>();
             boolean reloadDb = false;
@@ -79,11 +72,7 @@ public class TEOrgSummaryServiceImpl extends ServiceImpl<TEOrgSummaryMapper, TEO
                 Integer examCount = this.baseMapper.orgSummaryByExamCount(examIdSet);
                 List<Integer> finishCountList = this.baseMapper.orgSummaryByFinishCountAndFinishStudentCount(examIdSet);
                 TEOrgSummary teOrgSummary = new TEOrgSummary(orgId, onlineCount, examCount, finishCountList.get(0), finishCountList.get(1));
-                if (count == 0) {
-                    teOrgSummaryService.saveOrgSummaryCommon(teOrgSummary);
-                } else {
-                    teOrgSummaryService.updateOrgSummaryCommon(orgId, teOrgSummary);
-                }
+                teOrgSummaryService.saveOrUpdate(teOrgSummary);
             } else {
                 orgExamIdMap.forEach((k, v) -> {//从考试批次缓存信息里拿取在线人数、考试人数、完成考生数
                     Integer onlineCount = 0, examCount = 0, finishStudentCount = 0;
@@ -97,69 +86,12 @@ public class TEOrgSummaryServiceImpl extends ServiceImpl<TEOrgSummaryMapper, TEO
                     }
                     Integer finishCount = this.baseMapper.orgSummaryByFinishCount(v);
                     TEOrgSummary teOrgSummary = new TEOrgSummary(orgId, onlineCount, examCount, finishCount, finishStudentCount);
-                    if (count == 0) {
-                        teOrgSummaryService.saveOrgSummaryCommon(teOrgSummary);
-                    } else {
-                        teOrgSummaryService.updateOrgSummaryCommon(orgId, teOrgSummary);
-                    }
+                    teOrgSummaryService.saveOrUpdate(teOrgSummary);
                 });
             }
         }
     }
 
-    /**
-     * 保存机构统计信息
-     *
-     * @param teOrgSummary
-     */
-    @Override
-    @Transactional
-    public void saveOrgSummaryCommon(TEOrgSummary teOrgSummary) {
-        StringJoiner stringJoinerFieldName = new StringJoiner(",");
-        StringJoiner stringJoinerFieldValue = new StringJoiner(",");
-        OrgSummaryEnum[] orgSummaryEnums = OrgSummaryEnum.values();
-        for (int i = 0; i < orgSummaryEnums.length; i++) {
-            stringJoinerFieldName.add(orgSummaryEnums[i].getCode());
-        }
-        stringJoinerFieldValue.add("'" + teOrgSummary.getOrgId() + "'")
-                .add(teOrgSummary.getOnlineCount() + "")
-                .add(teOrgSummary.getExamCount() + "")
-                .add(teOrgSummary.getFinishCount() + "")
-                .add(teOrgSummary.getFinishStudentCount() + "");
-        this.baseMapper.saveOrgSummary(stringJoinerFieldName.toString(), stringJoinerFieldValue.toString());
-    }
-
-    /**
-     * 更新机构统计信息
-     *
-     * @param teOrgSummary
-     */
-    @Override
-    @Transactional
-    public void updateOrgSummaryCommon(Long orgId, TEOrgSummary teOrgSummary) {
-        StringJoiner stringJoinerFieldValue = new StringJoiner(",");
-        OrgSummaryEnum[] orgSummaryEnums = OrgSummaryEnum.values();
-        for (int i = 0; i < orgSummaryEnums.length; i++) {
-            switch (orgSummaryEnums[i]) {
-                case onlineCount:
-                    stringJoinerFieldValue.add(orgSummaryEnums[i].getCode() + "=" + teOrgSummary.getOnlineCount());
-                    break;
-                case examCount:
-                    stringJoinerFieldValue.add(orgSummaryEnums[i].getCode() + "=" + teOrgSummary.getExamCount());
-                    break;
-                case finishCount:
-                    stringJoinerFieldValue.add(orgSummaryEnums[i].getCode() + "=" + teOrgSummary.getFinishCount());
-                    break;
-                case finishStudentCount:
-                    stringJoinerFieldValue.add(orgSummaryEnums[i].getCode() + "=" + teOrgSummary.getFinishStudentCount());
-                    break;
-                default:
-                    break;
-            }
-        }
-        this.baseMapper.updateOrgSummary(orgId, stringJoinerFieldValue.toString());
-    }
-
     /**
      * 更新全局机构考试完成数量和考生完成数量
      *

+ 15 - 24
themis-business/src/main/java/com/qmth/themis/business/service/impl/TERegionSummaryServiceImpl.java

@@ -1,17 +1,19 @@
 package com.qmth.themis.business.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qmth.themis.business.dao.TERegionSummaryMapper;
 import com.qmth.themis.business.entity.TERegionSummary;
-import com.qmth.themis.business.enums.RegionSummaryEnum;
 import com.qmth.themis.business.service.TERegionSummaryService;
 import com.qmth.themis.business.service.ThemisCacheService;
+import com.qmth.themis.business.util.UidUtil;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
 import java.util.List;
-import java.util.StringJoiner;
+import java.util.Objects;
 
 /**
  * <p>
@@ -35,30 +37,19 @@ public class TERegionSummaryServiceImpl extends ServiceImpl<TERegionSummaryMappe
         List<TERegionSummary> teRegionSummaryList = this.baseMapper.regionSummary();
         if (!CollectionUtils.isEmpty(teRegionSummaryList)) {
             for (TERegionSummary t : teRegionSummaryList) {
-                int count = this.baseMapper.selectRegionSummaryCount(t.getCountry(), t.getProvince());
-                StringJoiner stringJoinerFieldName = new StringJoiner(",");
-                StringJoiner stringJoinerFieldValue = new StringJoiner(",");
-                RegionSummaryEnum[] regionSummaryEnums = RegionSummaryEnum.values();
-                if (count == 0) {
-                    for (int i = 0; i < regionSummaryEnums.length; i++) {
-                        stringJoinerFieldName.add(regionSummaryEnums[i].getCode());
-                    }
-                    stringJoinerFieldValue.add("'" + t.getCountry() + "'")
-                            .add("'" + t.getProvince() + "'")
-                            .add(t.getOnlineCount() + "");
-                    this.baseMapper.saveRegionSummary(stringJoinerFieldName.toString(), stringJoinerFieldValue.toString());
+                TERegionSummary teRegionSummaryDb = this.getOne(new QueryWrapper<TERegionSummary>().lambda()
+                        .eq(TERegionSummary::getCountry, t.getCountry())
+                        .eq(TERegionSummary::getProvince, t.getProvince()));
+                if (Objects.isNull(teRegionSummaryDb)) {
+                    teRegionSummaryDb = new TERegionSummary();
+                    BeanUtils.copyProperties(t, teRegionSummaryDb);
+                    teRegionSummaryDb.setId(UidUtil.nextId());
                 } else {
-                    for (int i = 0; i < regionSummaryEnums.length; i++) {
-                        switch (regionSummaryEnums[i]) {
-                            case onlineCount:
-                                stringJoinerFieldValue.add(regionSummaryEnums[i].getCode() + "=" + t.getOnlineCount());
-                                break;
-                            default:
-                                break;
-                        }
-                    }
-                    this.baseMapper.updateRegionSummary(t.getCountry(), t.getProvince(), stringJoinerFieldValue.toString());
+                    Long id = teRegionSummaryDb.getId();
+                    BeanUtils.copyProperties(t, teRegionSummaryDb);
+                    teRegionSummaryDb.setId(id);
                 }
+                this.saveOrUpdate(teRegionSummaryDb);
             }
             themisCacheService.updateRegionSummaryCache();
         }

+ 21 - 18
themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java

@@ -43,6 +43,7 @@ import java.io.IOException;
 import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @Description: 考试记录 服务实现类
@@ -1766,25 +1767,27 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
      */
     @Override
     public List<OrgDataCountBean> orgDataCount() {
-        Set<Long> examIdSet = themisCacheService.getTodayExamIdListCache();
-        LinkedMultiValueMap<Long, Long> orgExamIdMap = tbOrgService.mergeOrgId(examIdSet);
-        if (Objects.nonNull(orgExamIdMap) && orgExamIdMap.size() > 0) {
-            List<OrgDataCountBean> orgDataCountBeanList = new ArrayList<>();
-            //统计机构信息
-            orgExamIdMap.forEach((k, v) -> {
-                TEOrgSummary teOrgSummary = themisCacheService.addOrgSummaryCache(k);
-                if (Objects.nonNull(teOrgSummary) && ((Objects.nonNull(teOrgSummary.getExamCount()) &&
-                        teOrgSummary.getExamCount().intValue() > 0)
-                        || (Objects.nonNull(teOrgSummary) && Objects.nonNull(teOrgSummary.getOnlineCount()) &&
-                        teOrgSummary.getOnlineCount().intValue() > 0))) {
-                    TBOrg tbOrg = themisCacheService.addOrgCache(k);
-                    orgDataCountBeanList.add(new OrgDataCountBean(tbOrg.getCode(), tbOrg.getName(), Objects.nonNull(teOrgSummary) && Objects.nonNull(teOrgSummary.getOnlineCount()) ? teOrgSummary.getOnlineCount() : 0, Objects.nonNull(teOrgSummary) && Objects.nonNull(teOrgSummary.getExamCount()) ? teOrgSummary.getExamCount() : 0));
-                }
-            });
-            return orgDataCountBeanList;
-        } else {
-            return null;
+        Set<String> examIdSetSet = redisUtil.getHashKeys(SystemConstant.TODAY_EXAM_LIST_MAP_CACHE);
+        if (!CollectionUtils.isEmpty(examIdSetSet)) {
+            Set<Long> examIdSet = examIdSetSet.stream().map(s -> Long.parseLong(s)).collect(Collectors.toSet());
+            LinkedMultiValueMap<Long, Long> orgExamIdMap = tbOrgService.mergeOrgId(examIdSet);
+            if (Objects.nonNull(orgExamIdMap) && orgExamIdMap.size() > 0) {
+                List<OrgDataCountBean> orgDataCountBeanList = new ArrayList<>();
+                //统计机构信息
+                orgExamIdMap.forEach((k, v) -> {
+                    TEOrgSummary teOrgSummary = themisCacheService.addOrgSummaryCache(k);
+                    if (Objects.nonNull(teOrgSummary) && ((Objects.nonNull(teOrgSummary.getExamCount()) &&
+                            teOrgSummary.getExamCount().intValue() > 0)
+                            || (Objects.nonNull(teOrgSummary) && Objects.nonNull(teOrgSummary.getOnlineCount()) &&
+                            teOrgSummary.getOnlineCount().intValue() > 0))) {
+                        TBOrg tbOrg = themisCacheService.addOrgCache(k);
+                        orgDataCountBeanList.add(new OrgDataCountBean(tbOrg.getCode(), tbOrg.getName(), Objects.nonNull(teOrgSummary) && Objects.nonNull(teOrgSummary.getOnlineCount()) ? teOrgSummary.getOnlineCount() : 0, Objects.nonNull(teOrgSummary) && Objects.nonNull(teOrgSummary.getExamCount()) ? teOrgSummary.getExamCount() : 0));
+                    }
+                });
+                return orgDataCountBeanList;
+            }
         }
+        return null;
     }
 
     /**

+ 70 - 50
themis-business/src/main/java/com/qmth/themis/business/service/impl/ThemisCacheServiceImpl.java

@@ -1,7 +1,8 @@
 package com.qmth.themis.business.service.impl;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qmth.themis.business.bean.admin.ExamActivityTodayBean;
+import com.qmth.themis.business.bean.admin.ExamListBean;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.constant.SystemConstant;
@@ -10,6 +11,7 @@ import com.qmth.themis.business.dto.cache.TEStudentCacheDto;
 import com.qmth.themis.business.entity.*;
 import com.qmth.themis.business.enums.RoleEnum;
 import com.qmth.themis.business.service.*;
+import com.qmth.themis.business.util.JacksonUtil;
 import com.qmth.themis.business.util.RedisUtil;
 import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.exception.BusinessException;
@@ -27,6 +29,7 @@ import org.springframework.util.LinkedMultiValueMap;
 import javax.annotation.Resource;
 import java.text.SimpleDateFormat;
 import java.util.*;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.stream.Collectors;
 
@@ -620,23 +623,34 @@ public class ThemisCacheServiceImpl implements ThemisCacheService {
             List<TEExamActivity> teExamActivityList = teExamActivityService.list(new QueryWrapper<TEExamActivity>().lambda().ge(TEExamActivity::getStartTime, startTime).le(TEExamActivity::getStartTime, endTime).eq(TEExamActivity::getEnable, 1));
             //统计当天00:00:00~23:59:59可以进行的考试批次、场次、考场编码信息
             if (!CollectionUtils.isEmpty(teExamActivityList)) {
-                LinkedMultiValueMap<Long, ExamActivityTodayBean> examActivityMap = new LinkedMultiValueMap<>();
+                LinkedMultiValueMap<Long, String> examActivityMap = new LinkedMultiValueMap<>();
+                Map<Long, Set<Long>> examActivityIdMap = new HashMap<>();//考试批次id,场次id集合
+                Map<Long, Set<String>> roomCodeMap = new HashMap<>();//考试场次id,考场编码集合
                 for (TEExamActivity t : teExamActivityList) {
                     ExamCacheBean examCacheBean = teExamService.getExamCacheBean(t.getExamId());
-                    if (Objects.nonNull(examCacheBean.getEnable()) && examCacheBean.getEnable().intValue() == 1) {
+                    if (Objects.nonNull(examCacheBean.getEnable()) && examCacheBean.getEnable().intValue() == 1 && Objects.nonNull(t.getEnable()) && t.getEnable().intValue() == 1) {
                         List<TEExamStudent> teExamStudentList = teExamStudentService.list(new QueryWrapper<TEExamStudent>().lambda().eq(TEExamStudent::getExamId, t.getExamId()).eq(TEExamStudent::getExamActivityId, t.getId()));
                         if (!CollectionUtils.isEmpty(teExamStudentList)) {
                             Set<String> roomCodeSet = teExamStudentList.stream().map(s -> s.getRoomCode()).collect(Collectors.toSet());
-                            examActivityMap.add(t.getExamId(), new ExamActivityTodayBean(t.getId(), roomCodeSet));
+                            if (examActivityIdMap.containsKey(t.getExamId())) {
+                                Set<Long> examActivityIdSet = examActivityIdMap.get(t.getExamId());
+                                examActivityIdSet.add(t.getId());
+                                examActivityIdMap.put(t.getExamId(), examActivityIdSet);
+                            } else {
+                                examActivityIdMap.put(t.getExamId(), new HashSet<>(Arrays.asList(t.getId())));
+                            }
+                            roomCodeMap.put(t.getId(), roomCodeSet);
                         }
                     }
                 }
-                examActivityMap.forEach((k, v) -> {
-                    for (ExamActivityTodayBean e : v) {
-                        redisUtil.set(SystemConstant.TODAY_EXAM_MAP_CACHE + k, e.getExamActivityId().toString(), e.getRoomCodeList());
-                        redisUtil.addSet(SystemConstant.TODAY_EXAM_ID_LIST_CACHE, k);
+                examActivityIdMap.forEach((k, v) -> {
+                    for (Long l : v) {
+                        examActivityMap.add(k, JacksonUtil.parseJson(new ExamListBean(l, roomCodeMap.get(l))));
                     }
                 });
+                examActivityMap.forEach((k, v) -> {
+                    redisUtil.set(SystemConstant.TODAY_EXAM_LIST_MAP_CACHE, k.toString(), v);
+                });
             }
             teOrgSummaryService.orgSummary(0L, null);//统计全局机构信息
             teRegionSummaryService.regionSummary();
@@ -653,8 +667,8 @@ public class ThemisCacheServiceImpl implements ThemisCacheService {
         //查询考试场次结束时间大于当前时间的所有考试
         List<TEExamActivity> teExamActivityList = teExamActivityService.list(new QueryWrapper<TEExamActivity>().lambda().gt(TEExamActivity::getFinishTime, System.currentTimeMillis()).eq(TEExamActivity::getEnable, 1));
         if (!CollectionUtils.isEmpty(teExamActivityList)) {
-            Map<Long, Set<Long>> examMap = new HashMap<>();
-            Map<Long, Set<Long>> orgMap = new HashMap<>();
+            Map<Long, Set<Long>> examMap = new HashMap<>();//考试批次id,场次id集合
+            Map<Long, Set<Long>> orgMap = new HashMap<>();//机构id,考试批次id集合
             for (TEExamActivity t : teExamActivityList) {
                 ExamCacheBean examCacheBean = teExamService.getExamCacheBean(t.getExamId());
                 if (Objects.nonNull(examCacheBean.getEnable()) && examCacheBean.getEnable().intValue() == 1) {
@@ -722,6 +736,9 @@ public class ThemisCacheServiceImpl implements ThemisCacheService {
             redisUtil.set(SystemConstant.ORG_EXAM_LIST_MAP_CACHE + orgId, examId, new HashSet<>(Arrays.asList(examActivityId)));
         } else {
             Set<Long> examActivityIdSet = map.get(examId);
+            if (Objects.isNull(examActivityIdSet)) {
+                examActivityIdSet = new HashSet<>();
+            }
             examActivityIdSet.add(examActivityId);
             redisUtil.set(SystemConstant.ORG_EXAM_LIST_MAP_CACHE + orgId, examId, examActivityIdSet);
         }
@@ -781,8 +798,14 @@ public class ThemisCacheServiceImpl implements ThemisCacheService {
      * @return
      */
     @Override
-    public Map<String, Set<String>> getTodayExamListCache(String examId) {
-        return redisUtil.getHashEntries(SystemConstant.TODAY_EXAM_MAP_CACHE + examId);
+    public Map<String, List<String>> getTodayExamListCache(String examId) {
+        Map<String, List<String>> examActityIdMap = null;
+        Map<String, List<String>> map = redisUtil.getHashEntries(SystemConstant.TODAY_EXAM_LIST_MAP_CACHE);
+        if (!CollectionUtils.isEmpty(map) && Objects.nonNull(map.get(examId))) {
+            examActityIdMap = new HashMap<>();
+            examActityIdMap.put(examId, map.get(examId));
+        }
+        return examActityIdMap;
     }
 
     /**
@@ -792,12 +815,21 @@ public class ThemisCacheServiceImpl implements ThemisCacheService {
      * @return
      */
     @Override
-    public void updateTodayExamListCache(String examId, String examActivityId) {
+    public void updateTodayExamListCache(String examId, Long examActivityId) {
         List<TEExamStudent> teExamStudentList = teExamStudentService.list(new QueryWrapper<TEExamStudent>().lambda().eq(TEExamStudent::getExamId, Long.parseLong(examId)).eq(TEExamStudent::getExamActivityId, examActivityId));
         if (!CollectionUtils.isEmpty(teExamStudentList)) {
             Set<String> roomCodeSet = teExamStudentList.stream().map(s -> s.getRoomCode()).collect(Collectors.toSet());
             this.removeTodayExamListCache(examId, examActivityId);
-            redisUtil.set(SystemConstant.TODAY_EXAM_MAP_CACHE + examId, examActivityId, roomCodeSet);
+            Map<String, List<String>> map = this.getTodayExamListCache(examId);
+            if (!CollectionUtils.isEmpty(map)) {
+                CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList(map.values());
+                copyOnWriteArrayList.add(JacksonUtil.parseJson(new ExamListBean(examActivityId, roomCodeSet)));
+                redisUtil.set(SystemConstant.TODAY_EXAM_LIST_MAP_CACHE, examId, new LinkedList<>(copyOnWriteArrayList));
+            } else {
+                CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList();
+                copyOnWriteArrayList.add(JacksonUtil.parseJson(new ExamListBean(examActivityId, roomCodeSet)));
+                redisUtil.set(SystemConstant.TODAY_EXAM_LIST_MAP_CACHE, examId, new LinkedList<>(copyOnWriteArrayList));
+            }
         }
     }
 
@@ -808,7 +840,7 @@ public class ThemisCacheServiceImpl implements ThemisCacheService {
      */
     @Override
     public void removeTodayExamListCache(String examId) {
-        redisUtil.delete(SystemConstant.TODAY_EXAM_MAP_CACHE + examId);
+        redisUtil.delete(SystemConstant.TODAY_EXAM_LIST_MAP_CACHE, examId);
     }
 
     /**
@@ -818,38 +850,28 @@ public class ThemisCacheServiceImpl implements ThemisCacheService {
      * @param examActivityId
      */
     @Override
-    public void removeTodayExamListCache(String examId, String examActivityId) {
-        redisUtil.delete(SystemConstant.TODAY_EXAM_MAP_CACHE + examId, examActivityId);
-    }
-
-    /**
-     * 获取当天考试列表缓存
-     *
-     * @return
-     */
-    @Override
-    public Set<Long> getTodayExamIdListCache() {
-        return redisUtil.getSet(SystemConstant.TODAY_EXAM_ID_LIST_CACHE);
-    }
-
-    /**
-     * 更新当天考试列表缓存
-     *
-     * @param examId
-     */
-    @Override
-    public void updateTodayExamIdListCache(Long examId) {
-        redisUtil.addSet(SystemConstant.TODAY_EXAM_ID_LIST_CACHE, examId);
-    }
-
-    /**
-     * 删除当天考试列表缓存
-     *
-     * @param examId
-     */
-    @Override
-    public void removeTodayExamIdListCache(Long examId) {
-        redisUtil.removeSet(SystemConstant.TODAY_EXAM_ID_LIST_CACHE, examId);
+    public void removeTodayExamListCache(String examId, Long examActivityId) {
+        Map<String, List<String>> map = this.getTodayExamListCache(examId);
+        if (!CollectionUtils.isEmpty(map)) {
+            map.forEach((k, v) -> {
+                if (!CollectionUtils.isEmpty(v)) {
+                    CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList(v);
+                    for (String s : copyOnWriteArrayList) {
+                        JSONObject jsonObject = JSONObject.parseObject(s);
+                        Long examActivityIdJs = jsonObject.getLong(SystemConstant.EXAM_ACTIVITY_ID);
+                        if (examActivityIdJs.longValue() == examActivityId.longValue()) {
+                            copyOnWriteArrayList.remove(s);
+                            break;
+                        }
+                    }
+                    if (!CollectionUtils.isEmpty(copyOnWriteArrayList)) {
+                        redisUtil.set(SystemConstant.TODAY_EXAM_LIST_MAP_CACHE, k, new LinkedList<>(copyOnWriteArrayList));
+                    } else {
+                        this.removeTodayExamListCache(examId);
+                    }
+                }
+            });
+        }
     }
 
     /**
@@ -871,9 +893,7 @@ public class ThemisCacheServiceImpl implements ThemisCacheService {
         }
         List<TEExamSummary> teExamSummaryList = teExamSummaryService.list(teExamSummaryQueryWrapper);
         if (CollectionUtils.isEmpty(teExamSummaryList)) {
-            if (Objects.nonNull(examActivityId) && Objects.nonNull(roomCode)) {
-                teExamSummaryService.examSummary(examId, examActivityId, new HashSet<>(Arrays.asList(roomCode)));
-            }
+            teExamSummaryService.examSummary(examId, examActivityId, Objects.nonNull(roomCode) ? new HashSet<>(Arrays.asList(roomCode)) : null);
             teExamSummaryList = teExamSummaryService.list(teExamSummaryQueryWrapper);
         }
         return teExamSummaryList;

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

@@ -131,6 +131,27 @@ public class RedisUtil {
         return redisTemplate.opsForHash().entries(key);
     }
 
+    /**
+     * 获取hash map
+     *
+     * @param key
+     * @return
+     */
+    public Set getHashKeys(String key) {
+        return redisTemplate.opsForHash().keys(key);
+    }
+
+    /**
+     * 获取hash map
+     *
+     * @param key
+     * @return
+     */
+    public List getHashValues(String key) {
+        return redisTemplate.opsForHash().values(key);
+    }
+
+
     /**
      * 分布式锁,尝试上锁一定次数,失败后抛出异常
      *

+ 47 - 34
themis-task/src/main/java/com/qmth/themis/task/quartz/ExamSummaryJob.java

@@ -1,11 +1,13 @@
 package com.qmth.themis.task.quartz;
 
+import com.alibaba.fastjson.JSONObject;
 import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.entity.TBOrg;
 import com.qmth.themis.business.enums.ExamModeEnum;
 import com.qmth.themis.business.service.*;
+import com.qmth.themis.business.util.RedisUtil;
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
 import org.slf4j.Logger;
@@ -16,9 +18,7 @@ import org.springframework.util.CollectionUtils;
 import org.springframework.util.LinkedMultiValueMap;
 
 import javax.annotation.Resource;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
 
 /**
  * @Description: 考试统计
@@ -49,52 +49,65 @@ public class ExamSummaryJob extends QuartzJobBean {
     @Resource
     TERegionSummaryService teRegionSummaryService;
 
+    @Resource
+    RedisUtil redisUtil;
+
     @Override
     protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
         log.info("ExamSummaryJob进来了,context:{}", context);
+        Map<String, List<String>> examListMap = redisUtil.getHashEntries(SystemConstant.TODAY_EXAM_LIST_MAP_CACHE);
         //获取当天考试列表
-        Set<Long> examIdSet = themisCacheService.getTodayExamIdListCache();
-        if (!CollectionUtils.isEmpty(examIdSet)) {
+        if (!CollectionUtils.isEmpty(examListMap)) {
             LinkedMultiValueMap<Long, Long> orgExamIdMap = new LinkedMultiValueMap<>();
-            for (Long l : examIdSet) {
-                ExamCacheBean examCacheBean = teExamService.getExamCacheBean(l);
+            for (Map.Entry<String, List<String>> entry : examListMap.entrySet()) {
+                Long examId = Long.parseLong(entry.getKey());
+                ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
                 //不在考试时间范围内或者禁用,则删除当前考试批次id,更新缓存
                 if (examCacheBean.getEnable().intValue() == 0 || examCacheBean.getEndTime().longValue() <= System.currentTimeMillis()) {
-                    themisCacheService.removeTodayExamListCache(l.toString());
-                    themisCacheService.removeTodayExamIdListCache(l);
+                    themisCacheService.removeTodayExamListCache(entry.getKey());
+                    continue;
                 }
                 TBOrg tbOrg = themisCacheService.addOrgCache(examCacheBean.getOrgId());
-                orgExamIdMap.add(tbOrg.getId(), l);
+                orgExamIdMap.add(tbOrg.getId(), examId);
 
-                Map<String, Set<String>> map = themisCacheService.getTodayExamListCache(l.toString());
+                Map<String, List<String>> map = themisCacheService.getTodayExamListCache(entry.getKey());
                 if (!CollectionUtils.isEmpty(map)) {
                     map.forEach((k, v) -> {
-                        //换算开始时间和结束时间
-                        Long startTime = null, endTime = null;
-                        ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(Long.parseLong(k));
-                        if (ExamModeEnum.ANYTIME.equals(examCacheBean.getMode())) {
-                            startTime = ac.getStartTime() - (ac.getPrepareSeconds() * 1000);
-                            endTime = ac.getFinishTime();
-                            endTime = endTime + SystemConstant.FINISH_DELAY_TIME;//额外加5分钟,有可能后台交卷未完成
-                        } else {
-                            startTime = ac.getStartTime() - (ac.getPrepareSeconds() * 1000);
-                            Integer openingSecondsTemp = ac.getOpeningSeconds();
-                            openingSecondsTemp = Objects.nonNull(openingSecondsTemp) && openingSecondsTemp.intValue() == 0 ? SystemConstant.DEFAULT_OPENING_SECONDS : openingSecondsTemp;
-                            endTime = ac.getStartTime() + (openingSecondsTemp * 1000);
-                            endTime = endTime + SystemConstant.FINISH_DELAY_TIME;//额外加5分钟,有可能后台交卷未完成
-                        }
-                        long timestamp = System.currentTimeMillis();
-                        //当考试场次开始时间和场次结束时间在范围内,则统计,否则删除考试批次缓存列表,考试批次统计缓存信息
-                        if (ac.getEnable().intValue() == 1 && startTime <= timestamp && endTime >= timestamp) {
-                            teExamSummaryService.examSummary(l, Long.parseLong(k), v);
-                            teRegionSummaryService.regionSummary();
+                        if (!CollectionUtils.isEmpty(v)) {
+                            for (String s : v) {
+                                JSONObject jsonObject = JSONObject.parseObject(s);
+                                Long examActivityId = jsonObject.getLong(SystemConstant.EXAM_ACTIVITY_ID);
+                                String roomCodeStr = jsonObject.getString(SystemConstant.ROOM_CODE_SET);
+                                roomCodeStr = roomCodeStr.replaceAll("\\[", "").replaceAll("\\]", "");
+                                String[] strs = roomCodeStr.split(", ");
+                                Set<String> roomCodeSet = new HashSet<>(Arrays.asList(strs));
+                                //换算开始时间和结束时间
+                                Long startTime = null, endTime = null;
+                                ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(examActivityId);
+                                if (ExamModeEnum.ANYTIME.equals(examCacheBean.getMode())) {
+                                    startTime = ac.getStartTime() - (ac.getPrepareSeconds() * 1000);
+                                    endTime = ac.getFinishTime();
+                                    endTime = endTime + SystemConstant.FINISH_DELAY_TIME;//额外加5分钟,有可能后台交卷未完成
+                                } else {
+                                    startTime = ac.getStartTime() - (ac.getPrepareSeconds() * 1000);
+                                    Integer openingSecondsTemp = ac.getOpeningSeconds();
+                                    openingSecondsTemp = Objects.nonNull(openingSecondsTemp) && openingSecondsTemp.intValue() == 0 ? SystemConstant.DEFAULT_OPENING_SECONDS : openingSecondsTemp;
+                                    endTime = ac.getStartTime() + (openingSecondsTemp * 1000);
+                                    endTime = endTime + SystemConstant.FINISH_DELAY_TIME;//额外加5分钟,有可能后台交卷未完成
+                                }
+                                long timestamp = System.currentTimeMillis();
+                                //当考试场次开始时间和场次结束时间在范围内,则统计,否则删除考试批次缓存列表,考试批次统计缓存信息
+                                if (ac.getEnable().intValue() == 1 && startTime <= timestamp && endTime >= timestamp) {
+                                    teExamSummaryService.examSummary(examId, examActivityId, roomCodeSet);
+                                    teRegionSummaryService.regionSummary();
+                                } else {
+                                    themisCacheService.removeTodayExamListCache(entry.getKey(), examActivityId);
+                                }
+                            }
                         } else {
-                            themisCacheService.removeTodayExamListCache(l.toString(), k);
+                            themisCacheService.removeTodayExamListCache(entry.getKey());
                         }
                     });
-                } else {
-                    themisCacheService.removeTodayExamListCache(l.toString());
-                    themisCacheService.removeTodayExamIdListCache(l);
                 }
             }
             //统计机构信息

+ 32 - 19
themis-task/src/main/java/com/qmth/themis/task/quartz/MqActivityJob.java

@@ -1,5 +1,6 @@
 package com.qmth.themis.task.quartz;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
@@ -12,6 +13,7 @@ import com.qmth.themis.business.enums.ExamRecordStatusEnum;
 import com.qmth.themis.business.enums.FinishTypeEnum;
 import com.qmth.themis.business.enums.WebsocketStatusEnum;
 import com.qmth.themis.business.service.*;
+import com.qmth.themis.business.util.RedisUtil;
 import org.quartz.JobExecutionContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,6 +52,9 @@ public class MqActivityJob extends QuartzJobBean {
     @Resource
     ThemisCacheService themisCacheService;
 
+    @Resource
+    RedisUtil redisUtil;
+
     /**
      * 每天凌晨定时任务
      *
@@ -60,24 +65,32 @@ public class MqActivityJob extends QuartzJobBean {
         log.info("mq_activity_job进来了,context:{}", context);
         themisCacheService.setTodayExamCache();
         //每天凌晨清理考试缓存数据
-        Set<Long> examIdSet = themisCacheService.getTodayExamIdListCache();
-        for (Long l : examIdSet) {
-            ExamCacheBean examCacheBean = teExamService.getExamCacheBean(l);
-            if (examCacheBean.getEnable().intValue() == 0 || examCacheBean.getEndTime().longValue() <= System.currentTimeMillis()) {
-                themisCacheService.removeTodayExamListCache(l.toString());
-                themisCacheService.removeTodayExamIdListCache(l);
-            }
-            Map<String, Set<String>> map = themisCacheService.getTodayExamListCache(l.toString());
-            if (!CollectionUtils.isEmpty(map)) {
-                map.forEach((k, v) -> {
-                    ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(Long.parseLong(k));
-                    if (examActivityCacheBean.getEnable().intValue() == 0 || examActivityCacheBean.getFinishTime().longValue() <= System.currentTimeMillis()) {
-                        themisCacheService.removeTodayExamListCache(l.toString(), k);
-                    }
-                });
-            } else {
-                themisCacheService.removeTodayExamListCache(l.toString());
-                themisCacheService.removeTodayExamIdListCache(l);
+        Map<String, List<String>> examListMap = redisUtil.getHashEntries(SystemConstant.TODAY_EXAM_LIST_MAP_CACHE);
+        if (!CollectionUtils.isEmpty(examListMap)) {
+            for (Map.Entry<String, List<String>> entry : examListMap.entrySet()) {
+                Long examId = Long.parseLong(entry.getKey());
+                ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
+                if (examCacheBean.getEnable().intValue() == 0 || examCacheBean.getEndTime().longValue() <= System.currentTimeMillis()) {
+                    themisCacheService.removeTodayExamListCache(entry.getKey());
+                    continue;
+                }
+                Map<String, List<String>> map = themisCacheService.getTodayExamListCache(entry.getKey());
+                if (!CollectionUtils.isEmpty(map)) {
+                    map.forEach((k, v) -> {
+                        if (!CollectionUtils.isEmpty(v)) {
+                            for (String s : v) {
+                                JSONObject jsonObject = JSONObject.parseObject(s);
+                                Long examActivityId = jsonObject.getLong(SystemConstant.EXAM_ACTIVITY_ID);
+                                ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(examActivityId);
+                                if (examActivityCacheBean.getEnable().intValue() == 0 || examActivityCacheBean.getFinishTime().longValue() <= System.currentTimeMillis()) {
+                                    themisCacheService.removeTodayExamListCache(entry.getKey(), examActivityId);
+                                }
+                            }
+                        }
+                    });
+                } else {
+                    themisCacheService.removeTodayExamListCache(entry.getKey());
+                }
             }
         }
         Long finishTime = System.currentTimeMillis();
@@ -124,7 +137,7 @@ public class MqActivityJob extends QuartzJobBean {
                                             updateExamRecordList.add(s);
                                             commonService.dismissRoomByStrRoomId(s.getId());
                                         } else {//交卷
-                                           teExamService.finish(examStudentCacheBean.getStudentId(), s.getId(), FinishTypeEnum.AUTO.name(), durationSeconds);
+                                            teExamService.finish(examStudentCacheBean.getStudentId(), s.getId(), FinishTypeEnum.AUTO.name(), durationSeconds);
                                         }
                                         themisCacheService.removeExamSummaryAllCache(s.getExamId(), s.getExamActivityId(), examStudentCacheBean.getRoomCode());
                                     } catch (Exception e) {