Browse Source

新加入考试语音消息

wangliang 2 years ago
parent
commit
40874dec09
36 changed files with 728 additions and 172 deletions
  1. 1 1
      pom.xml
  2. 2 2
      themis-admin/pom.xml
  3. 95 14
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamActivityController.java
  4. 6 6
      themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamController.java
  5. 1 1
      themis-admin/src/main/java/com/qmth/themis/admin/api/TIeInvigilateController.java
  6. 1 1
      themis-admin/src/main/resources/application-dev.properties
  7. 2 2
      themis-business/pom.xml
  8. 11 0
      themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java
  9. 9 0
      themis-business/src/main/java/com/qmth/themis/business/dao/TOeExamRecordMapper.java
  10. 13 1
      themis-business/src/main/java/com/qmth/themis/business/entity/TEAudio.java
  11. 3 1
      themis-business/src/main/java/com/qmth/themis/business/enums/MqTagEnum.java
  12. 3 1
      themis-business/src/main/java/com/qmth/themis/business/enums/WebsocketTypeEnum.java
  13. 47 5
      themis-business/src/main/java/com/qmth/themis/business/service/CacheService.java
  14. 7 1
      themis-business/src/main/java/com/qmth/themis/business/service/TEAudioService.java
  15. 9 0
      themis-business/src/main/java/com/qmth/themis/business/service/TOeExamRecordService.java
  16. 76 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/CacheServiceImpl.java
  17. 71 2
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEAudioServiceImpl.java
  18. 20 13
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamActivityServiceImpl.java
  19. 2 2
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TEExamServiceImpl.java
  20. 12 0
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java
  21. 11 0
      themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml
  22. 2 2
      themis-common/pom.xml
  23. 2 2
      themis-exam/pom.xml
  24. 215 97
      themis-exam/src/main/java/com/qmth/themis/exam/listener/service/impl/MqOeLogicServiceImpl.java
  25. 1 1
      themis-exam/src/main/java/com/qmth/themis/exam/start/StartRunning.java
  26. 0 1
      themis-exam/src/main/java/com/qmth/themis/exam/websocket/WebSocketMobileServer.java
  27. 0 1
      themis-exam/src/main/java/com/qmth/themis/exam/websocket/WebSocketOeServer.java
  28. 2 2
      themis-mq/pom.xml
  29. 2 2
      themis-task/pom.xml
  30. 4 2
      themis-task/src/main/java/com/qmth/themis/task/enums/QuartzTaskEnum.java
  31. 1 0
      themis-task/src/main/java/com/qmth/themis/task/listener/MyJobListener.java
  32. 19 6
      themis-task/src/main/java/com/qmth/themis/task/listener/service/impl/MqTaskLogicServiceImpl.java
  33. 44 0
      themis-task/src/main/java/com/qmth/themis/task/quartz/ExamAudioJob.java
  34. 7 0
      themis-task/src/main/java/com/qmth/themis/task/quartz/service/QuartzLogicService.java
  35. 26 2
      themis-task/src/main/java/com/qmth/themis/task/quartz/service/impl/QuartzLogicServiceImpl.java
  36. 1 1
      themis-task/src/main/java/com/qmth/themis/task/start/StartRunning.java

+ 1 - 1
pom.xml

@@ -4,7 +4,7 @@
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.themis</groupId>
     <groupId>com.qmth.themis</groupId>
     <artifactId>themis-service</artifactId>
     <artifactId>themis-service</artifactId>
-    <version>1.2.2</version>
+    <version>1.2.3</version>
     <packaging>pom</packaging>
     <packaging>pom</packaging>
 
 
     <modules>
     <modules>

+ 2 - 2
themis-admin/pom.xml

@@ -4,13 +4,13 @@
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.themis.admin</groupId>
     <groupId>com.qmth.themis.admin</groupId>
     <artifactId>themis-admin</artifactId>
     <artifactId>themis-admin</artifactId>
-    <version>1.2.2</version>
+    <version>1.2.3</version>
     <packaging>jar</packaging>
     <packaging>jar</packaging>
 
 
     <parent>
     <parent>
         <groupId>com.qmth.themis</groupId>
         <groupId>com.qmth.themis</groupId>
         <artifactId>themis-service</artifactId>
         <artifactId>themis-service</artifactId>
-        <version>1.2.2</version>
+        <version>1.2.3</version>
     </parent>
     </parent>
 
 
     <dependencies>
     <dependencies>

+ 95 - 14
themis-admin/src/main/java/com/qmth/themis/admin/api/TEExamActivityController.java

@@ -1,23 +1,31 @@
 package com.qmth.themis.admin.api;
 package com.qmth.themis.admin.api;
 
 
+import cn.hutool.core.date.DateUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.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.constant.SystemConstant;
-import com.qmth.themis.business.entity.TBAttachment;
-import com.qmth.themis.business.entity.TBUser;
-import com.qmth.themis.business.entity.TEAudio;
-import com.qmth.themis.business.entity.TEExamActivity;
-import com.qmth.themis.business.service.TBAttachmentService;
-import com.qmth.themis.business.service.TEAudioService;
-import com.qmth.themis.business.service.TEExamActivityService;
-import com.qmth.themis.business.service.TEExamPaperService;
+import com.qmth.themis.business.dto.MqDto;
+import com.qmth.themis.business.entity.*;
+import com.qmth.themis.business.enums.AudioTypeEnum;
+import com.qmth.themis.business.enums.ExamModeEnum;
+import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
+import com.qmth.themis.business.enums.MqTagEnum;
+import com.qmth.themis.business.service.*;
+import com.qmth.themis.business.service.impl.TEExamActivityServiceImpl;
+import com.qmth.themis.business.util.JacksonUtil;
+import com.qmth.themis.business.util.MqUtil;
 import com.qmth.themis.business.util.OssUtil;
 import com.qmth.themis.business.util.OssUtil;
 import com.qmth.themis.business.util.ServletUtil;
 import com.qmth.themis.business.util.ServletUtil;
+import com.qmth.themis.common.contanst.Constants;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.util.Result;
 import com.qmth.themis.common.util.Result;
 import com.qmth.themis.common.util.ResultUtil;
 import com.qmth.themis.common.util.ResultUtil;
 import io.swagger.annotations.*;
 import io.swagger.annotations.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.CollectionUtils;
 import org.springframework.validation.BindingResult;
 import org.springframework.validation.BindingResult;
@@ -28,9 +36,7 @@ import javax.annotation.Resource;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
 import javax.validation.constraints.Min;
 import java.io.File;
 import java.io.File;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
+import java.util.*;
 
 
 /**
 /**
  * @Description: 考试场次 前端控制器
  * @Description: 考试场次 前端控制器
@@ -44,6 +50,7 @@ import java.util.Optional;
 @RequestMapping("/${prefix.url.admin}/activity")
 @RequestMapping("/${prefix.url.admin}/activity")
 @Validated
 @Validated
 public class TEExamActivityController {
 public class TEExamActivityController {
+    private final static Logger log = LoggerFactory.getLogger(TEExamActivityServiceImpl.class);
 
 
     @Resource
     @Resource
     private TEExamActivityService teExamActivityService;
     private TEExamActivityService teExamActivityService;
@@ -58,7 +65,16 @@ public class TEExamActivityController {
     OssUtil ossUtil;
     OssUtil ossUtil;
 
 
     @Resource
     @Resource
-    TBAttachmentService tbAttachmentService;
+    TEExamService teExamService;
+
+    @Resource
+    CacheService cacheService;
+
+    @Resource
+    private MqUtil mqUtil;
+
+    @Resource
+    private MqDtoService mqDtoService;
 
 
     @ApiOperation(value = "考试场次修改/新增接口")
     @ApiOperation(value = "考试场次修改/新增接口")
     @RequestMapping(value = "/save", method = RequestMethod.POST)
     @RequestMapping(value = "/save", method = RequestMethod.POST)
@@ -95,8 +111,8 @@ public class TEExamActivityController {
         if (Objects.nonNull(teAudioIPage) && !CollectionUtils.isEmpty(teAudioIPage.getRecords())) {
         if (Objects.nonNull(teAudioIPage) && !CollectionUtils.isEmpty(teAudioIPage.getRecords())) {
             for (TEAudio t : teAudioIPage.getRecords()) {
             for (TEAudio t : teAudioIPage.getRecords()) {
                 if (Objects.nonNull(t.getAttachmentId())) {
                 if (Objects.nonNull(t.getAttachmentId())) {
-                    TBAttachment tbAttachment = tbAttachmentService.getById(t.getAttachmentId());
-                    if (Objects.nonNull(tbAttachment.getRemark())) {
+                    TBAttachment tbAttachment = cacheService.attachmentCache(t.getAttachmentId());
+                    if (Objects.nonNull(tbAttachment) && Objects.nonNull(tbAttachment.getRemark())) {
                         JSONObject jsonObject = JSONObject.parseObject(tbAttachment.getRemark());
                         JSONObject jsonObject = JSONObject.parseObject(tbAttachment.getRemark());
                         t.setAttachmentPath(ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + jsonObject.getString(SystemConstant.PATH));
                         t.setAttachmentPath(ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + jsonObject.getString(SystemConstant.PATH));
                     }
                     }
@@ -117,12 +133,25 @@ public class TEExamActivityController {
         }
         }
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         teAudio.setOrgId(Objects.nonNull(tbUser.getOrgId()) ? tbUser.getOrgId() : -1L);
         teAudio.setOrgId(Objects.nonNull(tbUser.getOrgId()) ? tbUser.getOrgId() : -1L);
+        ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(teAudio.getActivityId());
+        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examActivityCacheBean.getExamId());
+        if (Objects.nonNull(examCacheBean) && examCacheBean.getMode() == ExamModeEnum.ANYTIME) {
+            throw new BusinessException("只有集中统一的考试才能使用语音播报");
+        }
+        if (Objects.nonNull(examCacheBean.getForceFinish()) && examCacheBean.getForceFinish().intValue() == 0) {
+            throw new BusinessException("考试未启用集中收卷");
+        }
+        if (Objects.nonNull(examCacheBean.getMonitorRecord()) && (!examCacheBean.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_FIRST.name())
+                && !examCacheBean.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_SECOND.name()))) {
+            throw new BusinessException("考试未启用手机直播");
+        }
         if (Objects.isNull(teAudio.getId())) {
         if (Objects.isNull(teAudio.getId())) {
             teAudio.insertInfo(tbUser.getId());
             teAudio.insertInfo(tbUser.getId());
         } else {
         } else {
             teAudio.updateInfo(tbUser.getId());
             teAudio.updateInfo(tbUser.getId());
         }
         }
         teAudioService.saveOrUpdate(teAudio);
         teAudioService.saveOrUpdate(teAudio);
+        teAudioService.sendAudioMessage(teAudio);
         return ResultUtil.ok(true);
         return ResultUtil.ok(true);
     }
     }
 
 
@@ -135,9 +164,61 @@ public class TEExamActivityController {
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         TEAudio teAudio = teAudioService.getById(audioId);
         TEAudio teAudio = teAudioService.getById(audioId);
         Optional.ofNullable(teAudio).orElseThrow(() -> new BusinessException("语音信息不存在"));
         Optional.ofNullable(teAudio).orElseThrow(() -> new BusinessException("语音信息不存在"));
+        if (enable) {
+            ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(teAudio.getActivityId());
+            ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examActivityCacheBean.getExamId());
+            if (Objects.nonNull(examCacheBean) && examCacheBean.getMode() == ExamModeEnum.ANYTIME) {
+                throw new BusinessException("只有集中统一的考试才能使用语音播报");
+            }
+            if (Objects.nonNull(examCacheBean.getForceFinish()) && examCacheBean.getForceFinish().intValue() == 0) {
+                throw new BusinessException("考试未启用集中收卷");
+            }
+            if (Objects.nonNull(examCacheBean.getMonitorRecord()) && (!examCacheBean.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_FIRST.name())
+                    && !examCacheBean.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_SECOND.name()))) {
+                throw new BusinessException("考试未启用手机直播");
+            }
+        }
         teAudio.setEnable(enable);
         teAudio.setEnable(enable);
         teAudio.updateInfo(tbUser.getId());
         teAudio.updateInfo(tbUser.getId());
         teAudioService.updateById(teAudio);
         teAudioService.updateById(teAudio);
+        cacheService.updateExamAudioCache(teAudio.getId());
+        return ResultUtil.ok(true);
+    }
+
+    @ApiOperation(value = "考试场次语音测试接口")
+    @RequestMapping(value = "/audio/test", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "常规信息", response = Result.class)})
+    public Result audioTest(@ApiParam(value = "考试场次语音id", required = true) @RequestParam Long audioId) {
+        TEAudio teAudio = teAudioService.getById(audioId);
+        Optional.ofNullable(teAudio).orElseThrow(() -> new BusinessException("语音信息不存在"));
+        ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(teAudio.getActivityId());
+        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(ac.getExamId());
+        TEExam teExam = teExamService.cacheConvert(examCacheBean);
+//        Long start = ac.getStartTime();
+//        Long end = ac.getStartTime() + (ac.getOpeningSeconds() * 1000);
+        long currentTime = System.currentTimeMillis();
+        Long execTime = null, realExecTime = null;
+        if (teAudio.getType() == AudioTypeEnum.BEFORE) {//开考前语音
+            realExecTime = currentTime + (60 * 1000);//当前时间往后一分钟
+        } else if (teAudio.getType() == AudioTypeEnum.AFTER) {//考试结束前语音
+            realExecTime = currentTime + (120 * 1000);//当前时间往后二分钟
+        }
+        execTime = realExecTime - SystemConstant.EXAM_AUDIO_BEFORE_TIME;
+        //新增quartz任务,发送mq消息start
+        Map<String, Object> prop = new HashMap<>();
+        prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+        prop.put(SystemConstant.EXAM, teExam);
+        prop.put(SystemConstant.EXEC_TIME, execTime);
+        prop.put(SystemConstant.REAL_EXEC_TIME, realExecTime);
+        log.info(SystemConstant.EXEC_TIME + ":{}," + SystemConstant.REAL_EXEC_TIME + ":{}", DateUtil.format(new Date(execTime), Constants.DEFAULT_DATE_PATTERN), DateUtil.format(new Date(realExecTime), Constants.DEFAULT_DATE_PATTERN));
+//        if (execTime >= System.currentTimeMillis()) {
+        cacheService.updateExamAudioCache(teAudio.getId());
+        MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_AUDIO.name(),
+                JacksonUtil.parseJson(teAudio), MqTagEnum.EXAM_AUDIO,
+                String.valueOf(teExam.getId()), prop, "test");
+        mqDtoService.assembleSendOneOrderMsg(mqDto);
+//        }
+        //新增quartz任务,发送mq消息end
         return ResultUtil.ok(true);
         return ResultUtil.ok(true);
     }
     }
 }
 }

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

@@ -165,8 +165,8 @@ public class TEExamController {
                         if (teExam.getForceFinish().intValue() == 1) {//从非强制交卷改成强制交卷,这时需生成场次定时任务
                         if (teExam.getForceFinish().intValue() == 1) {//从非强制交卷改成强制交卷,这时需生成场次定时任务
                             //新增quartz任务,发送mq消息start
                             //新增quartz任务,发送mq消息start
                             Map<String, Object> prop = new HashMap<>();
                             Map<String, Object> prop = new HashMap<>();
-                            prop.put("oper", "insert");
-                            prop.put("exam", teExam);
+                            prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+                            prop.put(SystemConstant.EXAM, teExam);
                             MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                             MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                                     JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
                                     JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
                                     String.valueOf(teExam.getId()), prop, tbUser.getName());
                                     String.valueOf(teExam.getId()), prop, tbUser.getName());
@@ -175,8 +175,8 @@ public class TEExamController {
                         } else {//否则删除场次定时任务
                         } else {//否则删除场次定时任务
                             //删除quartz任务,发送mq消息start
                             //删除quartz任务,发送mq消息start
                             Map<String, Object> prop = new HashMap<>();
                             Map<String, Object> prop = new HashMap<>();
-                            prop.put("oper", "delete");
-                            prop.put("exam", teExam);
+                            prop.put(SystemConstant.OPER, SystemConstant.DELETE);
+                            prop.put(SystemConstant.EXAM, teExam);
                             MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                             MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                                     JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
                                     JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
                                     String.valueOf(teExam.getId()), prop, tbUser.getName());
                                     String.valueOf(teExam.getId()), prop, tbUser.getName());
@@ -393,8 +393,8 @@ public class TEExamController {
                 if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1) {
                 if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1) {
                     //新增quartz任务,发送mq消息start
                     //新增quartz任务,发送mq消息start
                     Map<String, Object> prop = new HashMap<>();
                     Map<String, Object> prop = new HashMap<>();
-                    prop.put("oper", "insert");
-                    prop.put("exam", teExam);
+                    prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+                    prop.put(SystemConstant.EXAM, teExam);
                     MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                     MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                             JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
                             JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
                             String.valueOf(teExam.getId()), prop, tbUser.getName());
                             String.valueOf(teExam.getId()), prop, tbUser.getName());

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

@@ -604,7 +604,7 @@ public class TIeInvigilateController {
         }
         }
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
         //发送mq给客户端监考消息start
         //发送mq给客户端监考消息start
-        mapParameter.put("formUserId", tbUser.getId());
+        mapParameter.put(SystemConstant.FORM_USER_ID, tbUser.getId());
         MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.OE_IM_CLUSTERING.name(), recordId, MqTagEnum.OE_IM_CLUSTERING, String.valueOf(recordId), mapParameter, tbUser.getName());
         MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.OE_IM_CLUSTERING.name(), recordId, MqTagEnum.OE_IM_CLUSTERING, String.valueOf(recordId), mapParameter, tbUser.getName());
         mqDtoService.assembleSendOneOrderMsg(mqDto);
         mqDtoService.assembleSendOneOrderMsg(mqDto);
         //发送mq给客户端监考消息end
         //发送mq给客户端监考消息end

+ 1 - 1
themis-admin/src/main/resources/application-dev.properties

@@ -219,5 +219,5 @@ com.qmth.solar.access-key=8134f6aae0134770b8618913705d3667
 com.qmth.solar.access-secret=s1NENpvc8Jq5evcE0B7GfLmoQOvwmlCy
 com.qmth.solar.access-secret=s1NENpvc8Jq5evcE0B7GfLmoQOvwmlCy
 
 
 #\u65E0\u9700\u9274\u6743\u7684url
 #\u65E0\u9700\u9274\u6743\u7684url
-no.auth.urls=/webjars/**,/druid/**,/swagger-ui.html,/doc.html,/swagger-resources/**,/v2/api-docs,/webjars/springfox-swagger-ui/**,/api/admin/user/login/account,/api/admin/sys/org/queryByOrgCode,/file/**,/upload/**,/client/**,/base_photo/**,/frontend/**,/api/admin/client/save,/api/admin/client/upload,/api/admin/client/query,/api/admin/app/save,/api/admin/app/query,/api/notify/monitor/record/tencent,/api/notify/monitor/status/tencent
+no.auth.urls=/webjars/**,/druid/**,/swagger-ui.html,/doc.html,/swagger-resources/**,/v2/api-docs,/webjars/springfox-swagger-ui/**,/api/admin/user/login/account,/api/admin/sys/org/queryByOrgCode,/file/**,/upload/**,/client/**,/base_photo/**,/frontend/**,/api/admin/client/save,/api/admin/client/upload,/api/admin/client/query,/api/admin/app/save,/api/admin/app/query,/api/notify/monitor/record/tencent,/api/notify/monitor/status/tencent,/api/admin/activity/audio/test
 common.system.urls=/api/admin/sys/getMenu,/api/admin/user/logout,/api/admin/sys/env,/api/admin/sys/file/upload,/api/admin/sys/file/download,/api/admin/sys/org/query,/api/admin/sys/role/query,/api/admin/sys/examActivity/query,/api/admin/sys/exam/query,/api/admin/sys/examRoom/query,/api/admin/sys/exam/privilegeQuery,/api/admin/student/photo/upload,/api/admin/sys/getPlayUrls,/api/admin/sys/exam/finish/query,/api/admin/sys/get_tencent_video
 common.system.urls=/api/admin/sys/getMenu,/api/admin/user/logout,/api/admin/sys/env,/api/admin/sys/file/upload,/api/admin/sys/file/download,/api/admin/sys/org/query,/api/admin/sys/role/query,/api/admin/sys/examActivity/query,/api/admin/sys/exam/query,/api/admin/sys/examRoom/query,/api/admin/sys/exam/privilegeQuery,/api/admin/student/photo/upload,/api/admin/sys/getPlayUrls,/api/admin/sys/exam/finish/query,/api/admin/sys/get_tencent_video

+ 2 - 2
themis-business/pom.xml

@@ -5,13 +5,13 @@
 	<modelVersion>4.0.0</modelVersion>
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>com.qmth.themis.business</groupId>
 	<groupId>com.qmth.themis.business</groupId>
 	<artifactId>themis-business</artifactId>
 	<artifactId>themis-business</artifactId>
-	<version>1.2.2</version>
+	<version>1.2.3</version>
 	<packaging>jar</packaging>
 	<packaging>jar</packaging>
 
 
 	<parent>
 	<parent>
 		<groupId>com.qmth.themis</groupId>
 		<groupId>com.qmth.themis</groupId>
 		<artifactId>themis-service</artifactId>
 		<artifactId>themis-service</artifactId>
-		<version>1.2.2</version>
+		<version>1.2.3</version>
 	</parent>
 	</parent>
 
 
 	<dependencies>
 	<dependencies>

+ 11 - 0
themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java

@@ -92,11 +92,22 @@ public class SystemConstant {
     /**
     /**
      * 系统相关
      * 系统相关
      */
      */
+    public static final String CONTENT = "content";
+    public static final String FORM_USER_ID = "formUserId";
+    public static final String OPER = "oper";
+    public static final String EXAM = "exam";
+    public static final String EXEC_TIME = "execTime";
+    public static final String REAL_EXEC_TIME = "realExecTime";
+    public static final String INSERT = "insert";
+    public static final String DELETE = "delete";
+    public static final Long EXAM_AUDIO_BEFORE_TIME = 3000L;
     public static final Long BEFORE_AUDIO_ATTACHMENT_Id = 1L;
     public static final Long BEFORE_AUDIO_ATTACHMENT_Id = 1L;
     public static final Long AFTER_AUDIO_ATTACHMENT_Id = 2L;
     public static final Long AFTER_AUDIO_ATTACHMENT_Id = 2L;
     public static final Integer BEFORE_AUDIO_SECOND = 300;
     public static final Integer BEFORE_AUDIO_SECOND = 300;
     public static final Integer AFTER_AUDIO_SECOND = 600;
     public static final Integer AFTER_AUDIO_SECOND = 600;
     public static final String AUTH_INFO_CACHE = "auth:info:cache";
     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 volatile static Searcher SEARCHER = null;
     public volatile static Searcher SEARCHER = null;
     public static final String SYS_CONFIG_KEY_CHARSETS = "sys.txt.charset";
     public static final String SYS_CONFIG_KEY_CHARSETS = "sys.txt.charset";
     public static final String ONLINE_WARN_INTERVAL = "online.warn.interval";
     public static final String ONLINE_WARN_INTERVAL = "online.warn.interval";

+ 9 - 0
themis-business/src/main/java/com/qmth/themis/business/dao/TOeExamRecordMapper.java

@@ -512,4 +512,13 @@ public interface TOeExamRecordMapper extends BaseMapper<TOeExamRecord> {
      * @return
      * @return
      */
      */
     public List<TOeExamRecord> findExamRecordByNotVideoUrl(@Param("examId") Long examId);
     public List<TOeExamRecord> findExamRecordByNotVideoUrl(@Param("examId") Long examId);
+
+    /**
+     * 根据考试批次id和场次id查找考试数据
+     *
+     * @param examId
+     * @param examActivityId
+     * @return
+     */
+    public List<TOeExamRecord> findExamRecordByExamIdAndExamActivityId(@Param("examId") Long examId, @Param("examActivityId") Long examActivityId);
 }
 }

+ 13 - 1
themis-business/src/main/java/com/qmth/themis/business/entity/TEAudio.java

@@ -6,12 +6,14 @@ import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.qmth.themis.business.base.BaseEntity;
 import com.qmth.themis.business.base.BaseEntity;
 import com.qmth.themis.business.enums.AudioDefaultEnum;
 import com.qmth.themis.business.enums.AudioDefaultEnum;
 import com.qmth.themis.business.enums.AudioTypeEnum;
 import com.qmth.themis.business.enums.AudioTypeEnum;
+import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
 import com.qmth.themis.business.util.UidUtil;
 import com.qmth.themis.business.util.UidUtil;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import io.swagger.annotations.ApiModelProperty;
 
 
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 import java.io.Serializable;
+import java.util.Objects;
 
 
 /**
 /**
  * <p>
  * <p>
@@ -72,7 +74,7 @@ public class TEAudio extends BaseEntity implements Serializable {
 
 
     }
     }
 
 
-    public TEAudio(Long orgId, Long activityId, Long attachmentId, String content, AudioTypeEnum type, AudioDefaultEnum audioDefault, Long userId, Integer playTime) {
+    public TEAudio(Long orgId, Long activityId, Long attachmentId, String content, AudioTypeEnum type, AudioDefaultEnum audioDefault, Long userId, Integer playTime, TEExam teExam, TEExamActivity teExamActivity) {
         setId(UidUtil.nextId());
         setId(UidUtil.nextId());
         this.orgId = orgId;
         this.orgId = orgId;
         this.activityId = activityId;
         this.activityId = activityId;
@@ -82,6 +84,16 @@ public class TEAudio extends BaseEntity implements Serializable {
         this.audioDefault = audioDefault;
         this.audioDefault = audioDefault;
         this.playTime = playTime;
         this.playTime = playTime;
         setCreateId(userId);
         setCreateId(userId);
+        if (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1
+                && Objects.nonNull(teExam.getEnable()) && teExam.getEnable() == 1
+                && Objects.nonNull(teExamActivity.getEnable()) && teExamActivity.getEnable() == 1
+                && Objects.nonNull(teExam.getMonitorRecord())
+                && (teExam.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_FIRST.name())
+                || teExam.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_SECOND.name()))) {
+            this.enable = true;
+        } else {
+            this.enable = false;
+        }
     }
     }
 
 
     public void insertInfo(Long userId) {
     public void insertInfo(Long userId) {

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

@@ -56,7 +56,9 @@ public enum MqTagEnum {
     OE_WEBSOCKET_MOBILE_MONITOR_STATUS("通知客户端移动端当前监控状态标签", "通知客户端移动端当前监控状态", "broadcast", 48),
     OE_WEBSOCKET_MOBILE_MONITOR_STATUS("通知客户端移动端当前监控状态标签", "通知客户端移动端当前监控状态", "broadcast", 48),
     TENCENT_VIDEO("腾讯云视频回调标签", "腾讯云视频回调", "delay", 49),
     TENCENT_VIDEO("腾讯云视频回调标签", "腾讯云视频回调", "delay", 49),
     MARK_CLOUD_SCORE_PUSH("同步云阅卷成绩任务标签", "同步云阅卷成绩任务", "normal", 50),
     MARK_CLOUD_SCORE_PUSH("同步云阅卷成绩任务标签", "同步云阅卷成绩任务", "normal", 50),
-    ONLINE_LOG("考生上下线标签", "考生上下线", "normal", 51);
+    ONLINE_LOG("考生上下线标签", "考生上下线", "normal", 51),
+    EXAM_AUDIO("考试语音任务标签", "考试语音任务", "normal", 52),
+    EXAM_AUDIO_MOBILE("考试语音移动端任务标签", "考试语音移动端任务", "normal", 53);
 
 
     private MqTagEnum(String desc, String code, String type, int id) {
     private MqTagEnum(String desc, String code, String type, int id) {
         this.desc = desc;
         this.desc = desc;

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

@@ -41,7 +41,9 @@ public enum WebsocketTypeEnum {
 
 
     MOBILE_MONITOR_STOP("移动端监控停止", "mobileMonitorStop"),
     MOBILE_MONITOR_STOP("移动端监控停止", "mobileMonitorStop"),
 
 
-    MOBILE_MONITOR_STATUS("移动端监控状态", "mobileMonitorStatus");
+    MOBILE_MONITOR_STATUS("移动端监控状态", "mobileMonitorStatus"),
+
+    EXAM_AUDIO("考试语音", "examAudio");
 
 
     private String code;
     private String code;
     private String desc;
     private String desc;

+ 47 - 5
themis-business/src/main/java/com/qmth/themis/business/service/CacheService.java

@@ -3,11 +3,7 @@ package com.qmth.themis.business.service;
 import com.qmth.themis.business.dto.AuthDto;
 import com.qmth.themis.business.dto.AuthDto;
 import com.qmth.themis.business.dto.AuthOrgInfoDto;
 import com.qmth.themis.business.dto.AuthOrgInfoDto;
 import com.qmth.themis.business.dto.cache.TEStudentCacheDto;
 import com.qmth.themis.business.dto.cache.TEStudentCacheDto;
-import com.qmth.themis.business.entity.SysConfig;
-import com.qmth.themis.business.entity.TBOrg;
-import com.qmth.themis.business.entity.TBUser;
-
-import java.util.Map;
+import com.qmth.themis.business.entity.*;
 
 
 /**
 /**
  * @Description: 缓存 服务类
  * @Description: 缓存 服务类
@@ -195,4 +191,50 @@ public interface CacheService {
      * @param code
      * @param code
      */
      */
     public void removeAuthInfoCache(String code);
     public void removeAuthInfoCache(String code);
+
+    /**
+     * 添加考试语音缓存
+     *
+     * @param id
+     * @return
+     */
+    public TEAudio examAudioCache(Long id);
+
+    /**
+     * 修改考试语音缓存
+     *
+     * @param id
+     * @return
+     */
+    public TEAudio updateExamAudioCache(Long id);
+
+    /**
+     * 删除考试语音缓存
+     *
+     * @param id
+     */
+    public void removeExamAudioCache(Long id);
+
+    /**
+     * 添加附件缓存
+     *
+     * @param id
+     * @return
+     */
+    public TBAttachment attachmentCache(Long id);
+
+    /**
+     * 修改附件缓存
+     *
+     * @param id
+     * @return
+     */
+    public TBAttachment updateAttachmentCache(Long id);
+
+    /**
+     * 删除附件缓存
+     *
+     * @param id
+     */
+    public void removeAttachmentCache(Long id);
 }
 }

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

@@ -5,7 +5,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.themis.business.entity.TEAudio;
 import com.qmth.themis.business.entity.TEAudio;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Param;
 
 
-import java.util.List;
 import java.util.Map;
 import java.util.Map;
 
 
 /**
 /**
@@ -26,4 +25,11 @@ public interface TEAudioService extends IService<TEAudio> {
      * @return
      * @return
      */
      */
     IPage<TEAudio> query(IPage<Map> iPage, @Param("activityId") Long activityId);
     IPage<TEAudio> query(IPage<Map> iPage, @Param("activityId") Long activityId);
+
+    /**
+     * 发送语音mq消息
+     *
+     * @param teAudio
+     */
+    public void sendAudioMessage(TEAudio teAudio);
 }
 }

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

@@ -503,4 +503,13 @@ public interface TOeExamRecordService extends IService<TOeExamRecord> {
      * @return
      * @return
      */
      */
     public List<TOeExamRecord> findExamRecordByNotVideoUrl(Long examId);
     public List<TOeExamRecord> findExamRecordByNotVideoUrl(Long examId);
+
+    /**
+     * 根据考试批次id和场次id查找考试数据
+     *
+     * @param examId
+     * @param examActivityId
+     * @return
+     */
+    public List<TOeExamRecord> findExamRecordByExamIdAndExamActivityId(Long examId, Long examActivityId);
 }
 }

+ 76 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/CacheServiceImpl.java

@@ -64,6 +64,12 @@ public class CacheServiceImpl implements CacheService {
     @Resource
     @Resource
     SolarService solarService;
     SolarService solarService;
 
 
+    @Resource
+    TEAudioService teAudioService;
+
+    @Resource
+    TBAttachmentService tbAttachmentService;
+
     /**
     /**
      * 添加机构缓存
      * 添加机构缓存
      *
      *
@@ -397,4 +403,74 @@ public class CacheServiceImpl implements CacheService {
     public void removeAuthInfoCache(String code) {
     public void removeAuthInfoCache(String code) {
 
 
     }
     }
+
+    /**
+     * 添加考试语音缓存
+     *
+     * @param id
+     * @return
+     */
+    @Override
+    @Cacheable(value = SystemConstant.EXAM_AUDIO_CACHE, key = "#p0", unless = "#result == null")
+    public TEAudio examAudioCache(Long id) {
+        return teAudioService.getById(id);
+    }
+
+    /**
+     * 修改考试语音缓存
+     *
+     * @param id
+     * @return
+     */
+    @Override
+    @CachePut(value = SystemConstant.EXAM_AUDIO_CACHE, key = "#p0", unless = "#result == null")
+    public TEAudio updateExamAudioCache(Long id) {
+        return teAudioService.getById(id);
+    }
+
+    /**
+     * 删除考试语音缓存
+     *
+     * @param id
+     */
+    @Override
+    @CacheEvict(value = SystemConstant.EXAM_AUDIO_CACHE, key = "#p0")
+    public void removeExamAudioCache(Long id) {
+
+    }
+
+    /**
+     * 添加附件缓存
+     *
+     * @param id
+     * @return
+     */
+    @Override
+    @Cacheable(value = SystemConstant.ATTACHMENT_CACHE, key = "#p0", unless = "#result == null")
+    public TBAttachment attachmentCache(Long id) {
+        return tbAttachmentService.getById(id);
+    }
+
+    /**
+     * 修改附件缓存
+     *
+     * @param id
+     * @return
+     */
+    @Override
+    @CachePut(value = SystemConstant.ATTACHMENT_CACHE, key = "#p0", unless = "#result == null")
+    public TBAttachment updateAttachmentCache(Long id) {
+        return tbAttachmentService.getById(id);
+    }
+
+    /**
+     * 删除附件缓存
+     *
+     * @param id
+     */
+    @Override
+    @CacheEvict(value = SystemConstant.ATTACHMENT_CACHE, key = "#p0")
+    public void removeAttachmentCache(Long id) {
+
+    }
 }
 }

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

@@ -1,14 +1,30 @@
 package com.qmth.themis.business.service.impl;
 package com.qmth.themis.business.service.impl;
 
 
+import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
+import com.qmth.themis.business.cache.bean.ExamCacheBean;
+import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dao.TEAudioMapper;
 import com.qmth.themis.business.dao.TEAudioMapper;
+import com.qmth.themis.business.dto.MqDto;
+import com.qmth.themis.business.entity.TBUser;
 import com.qmth.themis.business.entity.TEAudio;
 import com.qmth.themis.business.entity.TEAudio;
-import com.qmth.themis.business.service.TEAudioService;
+import com.qmth.themis.business.entity.TEExam;
+import com.qmth.themis.business.enums.AudioTypeEnum;
+import com.qmth.themis.business.enums.MqTagEnum;
+import com.qmth.themis.business.service.*;
+import com.qmth.themis.business.util.JacksonUtil;
+import com.qmth.themis.business.util.MqUtil;
+import com.qmth.themis.business.util.ServletUtil;
+import com.qmth.themis.common.contanst.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
-import java.util.List;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 
 
 /**
 /**
@@ -21,10 +37,26 @@ import java.util.Map;
  */
  */
 @Service
 @Service
 public class TEAudioServiceImpl extends ServiceImpl<TEAudioMapper, TEAudio> implements TEAudioService {
 public class TEAudioServiceImpl extends ServiceImpl<TEAudioMapper, TEAudio> implements TEAudioService {
+    private final static Logger log = LoggerFactory.getLogger(TEAudioServiceImpl.class);
 
 
     @Resource
     @Resource
     TEAudioMapper teAudioMapper;
     TEAudioMapper teAudioMapper;
 
 
+    @Resource
+    TEExamActivityService teExamActivityService;
+
+    @Resource
+    TEExamService teExamService;
+
+    @Resource
+    private MqUtil mqUtil;
+
+    @Resource
+    private MqDtoService mqDtoService;
+
+    @Resource
+    CacheService cacheService;
+
     /**
     /**
      * 根据场次id查询音频信息
      * 根据场次id查询音频信息
      *
      *
@@ -36,4 +68,41 @@ public class TEAudioServiceImpl extends ServiceImpl<TEAudioMapper, TEAudio> impl
     public IPage<TEAudio> query(IPage<Map> iPage, Long activityId) {
     public IPage<TEAudio> query(IPage<Map> iPage, Long activityId) {
         return teAudioMapper.query(iPage, activityId);
         return teAudioMapper.query(iPage, activityId);
     }
     }
+
+    /**
+     * 发送语音mq消息
+     *
+     * @param teAudio
+     */
+    @Override
+    public void sendAudioMessage(TEAudio teAudio) {
+        TBUser tbUser = (TBUser) ServletUtil.getRequestAccount();
+        ExamActivityCacheBean ac = teExamActivityService.getExamActivityCacheBean(teAudio.getActivityId());
+        ExamCacheBean examCacheBean = teExamService.getExamCacheBean(ac.getExamId());
+        TEExam teExam = teExamService.cacheConvert(examCacheBean);
+        Long start = ac.getStartTime();
+        Long end = ac.getStartTime() + (ac.getOpeningSeconds() * 1000);
+        Long execTime = null, realExecTime = null;
+        if (teAudio.getType() == AudioTypeEnum.BEFORE) {//开考前语音
+            realExecTime = start - (teAudio.getPlayTime() * 1000);
+        } else if (teAudio.getType() == AudioTypeEnum.AFTER) {//考试结束前语音
+            realExecTime = end - (teAudio.getPlayTime() * 1000);
+        }
+        execTime = realExecTime - SystemConstant.EXAM_AUDIO_BEFORE_TIME;
+        //新增quartz任务,发送mq消息start
+        Map<String, Object> prop = new HashMap<>();
+        prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+        prop.put(SystemConstant.EXAM, teExam);
+        prop.put(SystemConstant.EXEC_TIME, execTime);
+        prop.put(SystemConstant.REAL_EXEC_TIME, realExecTime);
+        log.info(SystemConstant.EXEC_TIME + ":{}," + SystemConstant.REAL_EXEC_TIME + ":{}", DateUtil.format(new Date(execTime), Constants.DEFAULT_DATE_PATTERN), DateUtil.format(new Date(realExecTime), Constants.DEFAULT_DATE_PATTERN));
+        if (execTime >= System.currentTimeMillis()) {
+            cacheService.updateExamAudioCache(teAudio.getId());
+            MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_AUDIO.name(),
+                    JacksonUtil.parseJson(teAudio), MqTagEnum.EXAM_AUDIO,
+                    String.valueOf(teExam.getId()), prop, tbUser.getName());
+            mqDtoService.assembleSendOneOrderMsg(mqDto);
+        }
+        //新增quartz任务,发送mq消息end
+    }
 }
 }

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

@@ -80,6 +80,9 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
     @Resource
     @Resource
     TSLogService tsLogService;
     TSLogService tsLogService;
 
 
+    @Resource
+    CacheService cacheService;
+
     /**
     /**
      * 表是否存在
      * 表是否存在
      *
      *
@@ -353,7 +356,7 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
                             .eq(TEAudio::getAudioDefault, AudioDefaultEnum.SYS.name());
                             .eq(TEAudio::getAudioDefault, AudioDefaultEnum.SYS.name());
                     int count = teAudioService.count(teAudioQueryWrapper);
                     int count = teAudioService.count(teAudioQueryWrapper);
                     if (count == 0) {
                     if (count == 0) {
-                        teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.BEFORE_AUDIO_ATTACHMENT_Id, AudioTypeEnum.BEFORE.getTitle(), AudioTypeEnum.BEFORE, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.BEFORE_AUDIO_SECOND));//开考前语音
+                        teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.BEFORE_AUDIO_ATTACHMENT_Id, AudioTypeEnum.BEFORE.getTitle(), AudioTypeEnum.BEFORE, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.BEFORE_AUDIO_SECOND, teExam, s));//开考前语音
                     }
                     }
 
 
                     teAudioQueryWrapper = new QueryWrapper<>();
                     teAudioQueryWrapper = new QueryWrapper<>();
@@ -362,7 +365,7 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
                             .eq(TEAudio::getAudioDefault, AudioDefaultEnum.SYS.name());
                             .eq(TEAudio::getAudioDefault, AudioDefaultEnum.SYS.name());
                     count = teAudioService.count(teAudioQueryWrapper);
                     count = teAudioService.count(teAudioQueryWrapper);
                     if (count == 0) {
                     if (count == 0) {
-                        teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.AFTER_AUDIO_ATTACHMENT_Id, AudioTypeEnum.AFTER.getTitle(), AudioTypeEnum.AFTER, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.AFTER_AUDIO_SECOND));//考试结束前语音
+                        teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.AFTER_AUDIO_ATTACHMENT_Id, AudioTypeEnum.AFTER.getTitle(), AudioTypeEnum.AFTER, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.AFTER_AUDIO_SECOND, teExam, s));//考试结束前语音
                     }
                     }
                     TEExamActivity teExamActivityDb = teExamActivityService.getById(s.getId());
                     TEExamActivity teExamActivityDb = teExamActivityService.getById(s.getId());
                     if (Objects.nonNull(teExamActivityDb)) {
                     if (Objects.nonNull(teExamActivityDb)) {
@@ -375,8 +378,8 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
                                     && s.getFinishTime().longValue() != teExamActivityDb.getFinishTime().longValue()) {
                                     && s.getFinishTime().longValue() != teExamActivityDb.getFinishTime().longValue()) {
                                 //删除quartz任务,发送mq消息start
                                 //删除quartz任务,发送mq消息start
                                 Map<String, Object> prop = new HashMap<>();
                                 Map<String, Object> prop = new HashMap<>();
-                                prop.put("oper", "delete");
-                                prop.put("exam", teExam);
+                                prop.put(SystemConstant.OPER, SystemConstant.DELETE);
+                                prop.put(SystemConstant.EXAM, teExam);
                                 MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                                 MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                                         JacksonUtil.parseJson(Arrays.asList(s)), MqTagEnum.EXAM_ACTIVITY,
                                         JacksonUtil.parseJson(Arrays.asList(s)), MqTagEnum.EXAM_ACTIVITY,
                                         String.valueOf(teExam.getId()), prop, tbUser.getName());
                                         String.valueOf(teExam.getId()), prop, tbUser.getName());
@@ -385,8 +388,8 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
 
 
                                 //新增quartz任务,发送mq消息start
                                 //新增quartz任务,发送mq消息start
                                 prop = new HashMap<>();
                                 prop = new HashMap<>();
-                                prop.put("oper", "insert");
-                                prop.put("exam", teExam);
+                                prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+                                prop.put(SystemConstant.EXAM, teExam);
                                 mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                                 mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                                         JacksonUtil.parseJson(Arrays.asList(s)), MqTagEnum.EXAM_ACTIVITY,
                                         JacksonUtil.parseJson(Arrays.asList(s)), MqTagEnum.EXAM_ACTIVITY,
                                         String.valueOf(teExam.getId()), prop, tbUser.getName());
                                         String.valueOf(teExam.getId()), prop, tbUser.getName());
@@ -404,23 +407,27 @@ public class TEExamActivityServiceImpl extends ServiceImpl<TEExamActivityMapper,
                     s.setId(uidUtil.getId());
                     s.setId(uidUtil.getId());
                     s.setCreateId(tbUser.getId());
                     s.setCreateId(tbUser.getId());
                     s.setCode(String.valueOf(redisUtil.getRedisActivityCodeSequence(s.getExamId())));
                     s.setCode(String.valueOf(redisUtil.getRedisActivityCodeSequence(s.getExamId())));
-                    teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.BEFORE_AUDIO_ATTACHMENT_Id, AudioTypeEnum.BEFORE.getTitle(), AudioTypeEnum.BEFORE, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.BEFORE_AUDIO_SECOND));//开考前语音
-                    teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.AFTER_AUDIO_ATTACHMENT_Id, AudioTypeEnum.AFTER.getTitle(), AudioTypeEnum.AFTER, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.AFTER_AUDIO_SECOND));//考试结束前语音
+                    teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.BEFORE_AUDIO_ATTACHMENT_Id, AudioTypeEnum.BEFORE.getTitle(), AudioTypeEnum.BEFORE, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.BEFORE_AUDIO_SECOND, teExam, s));//开考前语音
+                    teAudioList.add(new TEAudio(tbUser.getOrgId(), s.getId(), SystemConstant.AFTER_AUDIO_ATTACHMENT_Id, AudioTypeEnum.AFTER.getTitle(), AudioTypeEnum.AFTER, AudioDefaultEnum.SYS, tbUser.getId(), SystemConstant.AFTER_AUDIO_SECOND, teExam, s));//考试结束前语音
                 }
                 }
             });
             });
             teExamActivityService.saveOrUpdateBatch(teExamActivityList);
             teExamActivityService.saveOrUpdateBatch(teExamActivityList);
-            if (!CollectionUtils.isEmpty(teAudioList)) {
-                teAudioService.saveOrUpdateBatch(teAudioList);
-            }
 
 
             for (TEExamActivity ac : teExamActivityList) {
             for (TEExamActivity ac : teExamActivityList) {
                 teExamActivityService.updateExamActivityCacheBean(ac.getId());
                 teExamActivityService.updateExamActivityCacheBean(ac.getId());
             }
             }
+
+            if (!CollectionUtils.isEmpty(teAudioList)) {
+                teAudioService.saveOrUpdateBatch(teAudioList);
+                for (TEAudio t : teAudioList) {
+                    teAudioService.sendAudioMessage(t);
+                }
+            }
             if (size.get() > 0 && (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1)) {
             if (size.get() > 0 && (Objects.nonNull(teExam.getForceFinish()) && teExam.getForceFinish().intValue() == 1)) {
                 //新增quartz任务,发送mq消息start
                 //新增quartz任务,发送mq消息start
                 Map<String, Object> prop = new HashMap<>();
                 Map<String, Object> prop = new HashMap<>();
-                prop.put("oper", "insert");
-                prop.put("exam", teExam);
+                prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+                prop.put(SystemConstant.EXAM, teExam);
                 MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                 MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name(),
                         JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
                         JacksonUtil.parseJson(teExamActivityList), MqTagEnum.EXAM_ACTIVITY,
                         String.valueOf(teExam.getId()), prop, tbUser.getName());
                         String.valueOf(teExam.getId()), prop, tbUser.getName());

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

@@ -583,8 +583,8 @@ public class TEExamServiceImpl extends ServiceImpl<TEExamMapper, TEExam> impleme
                     ExamRecordCacheUtil.setExamFinalFinishTime(recordId, finalFinishTime);
                     ExamRecordCacheUtil.setExamFinalFinishTime(recordId, finalFinishTime);
                     //新增quartz任务,发送mq消息start
                     //新增quartz任务,发送mq消息start
                     Map<String, Object> prop = new HashMap<>();
                     Map<String, Object> prop = new HashMap<>();
-                    prop.put("oper", "insert");
-                    prop.put("exam", exam);
+                    prop.put(SystemConstant.OPER, SystemConstant.INSERT);
+                    prop.put(SystemConstant.EXAM, exam);
                     MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_STUDENT.name(),
                     MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_STUDENT.name(),
                             JacksonUtil.parseJson(examStudentCacheBean), MqTagEnum.EXAM_STUDENT, String.valueOf(recordId),
                             JacksonUtil.parseJson(examStudentCacheBean), MqTagEnum.EXAM_STUDENT, String.valueOf(recordId),
                             prop, es.getName());
                             prop, es.getName());

+ 12 - 0
themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeExamRecordServiceImpl.java

@@ -1426,6 +1426,18 @@ public class TOeExamRecordServiceImpl extends ServiceImpl<TOeExamRecordMapper, T
         return tOeExamRecordMapper.findExamRecordByNotVideoUrl(examId);
         return tOeExamRecordMapper.findExamRecordByNotVideoUrl(examId);
     }
     }
 
 
+    /**
+     * 根据考试批次id和场次id查找考试数据
+     *
+     * @param examId
+     * @param examActivityId
+     * @return
+     */
+    @Override
+    public List<TOeExamRecord> findExamRecordByExamIdAndExamActivityId(Long examId, Long examActivityId) {
+        return tOeExamRecordMapper.findExamRecordByExamIdAndExamActivityId(examId, examActivityId);
+    }
+
     /**
     /**
      * 取最高分
      * 取最高分
      *
      *

+ 11 - 0
themis-business/src/main/resources/mapper/TOeExamRecordMapper.xml

@@ -1705,4 +1705,15 @@
                 )
                 )
           and toer.exam_id = #{examId}
           and toer.exam_id = #{examId}
     </select>
     </select>
+
+    <select id="findExamRecordByExamIdAndExamActivityId" resultType="com.qmth.themis.business.entity.TOeExamRecord">
+        select * from t_oe_exam_record toer
+        where
+            toer.exam_id = #{examId}
+            and toer.exam_activity_id = #{examActivityId}
+            and (toer.status = 'FIRST_PREPARE'
+            or toer.status = 'ANSWERING'
+            or toer.status = 'BREAK_OFF'
+            or toer.status = 'RESUME_PREPARE')
+    </select>
 </mapper>
 </mapper>

+ 2 - 2
themis-common/pom.xml

@@ -5,13 +5,13 @@
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.themis.common</groupId>
     <groupId>com.qmth.themis.common</groupId>
     <artifactId>themis-common</artifactId>
     <artifactId>themis-common</artifactId>
-    <version>1.2.2</version>
+    <version>1.2.3</version>
     <packaging>jar</packaging>
     <packaging>jar</packaging>
 
 
     <parent>
     <parent>
         <groupId>com.qmth.themis</groupId>
         <groupId>com.qmth.themis</groupId>
         <artifactId>themis-service</artifactId>
         <artifactId>themis-service</artifactId>
-        <version>1.2.2</version>
+        <version>1.2.3</version>
     </parent>
     </parent>
 
 
     <dependencies>
     <dependencies>

+ 2 - 2
themis-exam/pom.xml

@@ -4,13 +4,13 @@
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.themis.exam</groupId>
     <groupId>com.qmth.themis.exam</groupId>
     <artifactId>themis-exam</artifactId>
     <artifactId>themis-exam</artifactId>
-    <version>1.2.2</version>
+    <version>1.2.3</version>
     <packaging>jar</packaging>
     <packaging>jar</packaging>
 
 
     <parent>
     <parent>
         <groupId>com.qmth.themis</groupId>
         <groupId>com.qmth.themis</groupId>
         <artifactId>themis-service</artifactId>
         <artifactId>themis-service</artifactId>
-        <version>1.2.2</version>
+        <version>1.2.3</version>
     </parent>
     </parent>
 
 
     <dependencies>
     <dependencies>

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

@@ -1,22 +1,20 @@
 package com.qmth.themis.exam.listener.service.impl;
 package com.qmth.themis.exam.listener.service.impl;
 
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.qmth.themis.business.bean.status.MonitorStatusBean;
 import com.qmth.themis.business.bean.status.MonitorStatusBean;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
+import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
+import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.dto.WebsocketDto;
 import com.qmth.themis.business.dto.WebsocketDto;
-import com.qmth.themis.business.entity.TEExamStudent;
-import com.qmth.themis.business.entity.TEExamStudentLog;
-import com.qmth.themis.business.entity.TIeExamInvigilateNotice;
-import com.qmth.themis.business.entity.TOeExamRecord;
+import com.qmth.themis.business.entity.*;
 import com.qmth.themis.business.enums.*;
 import com.qmth.themis.business.enums.*;
-import com.qmth.themis.business.service.TEExamStudentLogService;
-import com.qmth.themis.business.service.TEExamStudentService;
-import com.qmth.themis.business.service.TIeExamInvigilateNoticeService;
-import com.qmth.themis.business.service.TMRocketMessageService;
+import com.qmth.themis.business.service.*;
 import com.qmth.themis.business.util.JacksonUtil;
 import com.qmth.themis.business.util.JacksonUtil;
+import com.qmth.themis.business.util.OssUtil;
 import com.qmth.themis.common.contanst.Constants;
 import com.qmth.themis.common.contanst.Constants;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.exam.listener.service.MqOeLogicService;
 import com.qmth.themis.exam.listener.service.MqOeLogicService;
@@ -26,8 +24,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
+import java.io.File;
 import java.io.IOException;
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchAlgorithmException;
 import java.util.*;
 import java.util.*;
@@ -56,6 +56,21 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
     @Resource
     @Resource
     TIeExamInvigilateNoticeService tIeExamInvigilateNoticeService;
     TIeExamInvigilateNoticeService tIeExamInvigilateNoticeService;
 
 
+    @Resource
+    TEExamActivityService teExamActivityService;
+
+    @Resource
+    TEExamService teExamService;
+
+    @Resource
+    CacheService cacheService;
+
+    @Resource
+    TOeExamRecordService tOeExamRecordService;
+
+    @Resource
+    OssUtil ossUtil;
+
     /**
     /**
      * 强制离线交卷持久化逻辑
      * 强制离线交卷持久化逻辑
      *
      *
@@ -170,8 +185,8 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
                 map.put("from", mqDto.getObjName());
                 map.put("from", mqDto.getObjName());
                 map.put(SystemConstant.WEB_SOCKET_OE_SERVER, webSocketOeServer);
                 map.put(SystemConstant.WEB_SOCKET_OE_SERVER, webSocketOeServer);
                 map.put(SystemConstant.TYPE, prop.get(SystemConstant.TYPE));
                 map.put(SystemConstant.TYPE, prop.get(SystemConstant.TYPE));
-                map.put("content", prop.get("content"));
-                TIeExamInvigilateNotice tIeExamInvigilateNotice = new TIeExamInvigilateNotice(examId, examActivityId, recordId, Long.parseLong(String.valueOf(prop.get("formUserId"))), examStudentId, MessageTypeEnum.valueOf(String.valueOf(prop.get(SystemConstant.TYPE)).toUpperCase()), String.valueOf(prop.get("content")));
+                map.put(SystemConstant.CONTENT, prop.get(SystemConstant.CONTENT));
+                TIeExamInvigilateNotice tIeExamInvigilateNotice = new TIeExamInvigilateNotice(examId, examActivityId, recordId, Long.parseLong(String.valueOf(prop.get(SystemConstant.FORM_USER_ID))), examStudentId, MessageTypeEnum.valueOf(String.valueOf(prop.get(SystemConstant.TYPE)).toUpperCase()), String.valueOf(prop.get(SystemConstant.CONTENT)));
                 tIeExamInvigilateNoticeService.saveOrUpdate(tIeExamInvigilateNotice);
                 tIeExamInvigilateNoticeService.saveOrUpdate(tIeExamInvigilateNotice);
 
 
                 tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
                 tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
@@ -386,105 +401,208 @@ public class MqOeLogicServiceImpl implements MqOeLogicService {
     @Override
     @Override
     public void execMqOeMobileLogic(MqDto mqDto, String key) throws NoSuchAlgorithmException, IOException {
     public void execMqOeMobileLogic(MqDto mqDto, String key) throws NoSuchAlgorithmException, IOException {
         String tag = mqDto.getTag();
         String tag = mqDto.getTag();
-        ConcurrentHashMap<String, WebSocketMobileServer> webSocketMap = WebSocketMobileServer.getWebSocketMap();
         if (Objects.equals(MqTagEnum.EXAM_STOP.name(), tag)//考试退出
         if (Objects.equals(MqTagEnum.EXAM_STOP.name(), tag)//考试退出
-                || Objects.equals(MqTagEnum.EXAM_START.name(), tag)) {//考试开始
-            Long recordId = Long.parseLong(String.valueOf(mqDto.getBody()));
-            TOeExamRecord tOeExamRecord = null;
-            ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(recordId);
-            if (Objects.isNull(examRecordStatusEnum)) {
-                tOeExamRecord = SystemConstant.getExamRecord(recordId);
-                examRecordStatusEnum = tOeExamRecord.getStatus();
-            }
-            Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
-            Long studentId = null;
-            if (Objects.isNull(examStudentId)) {
-                tOeExamRecord = Objects.isNull(tOeExamRecord) ? SystemConstant.getExamRecord(recordId) : tOeExamRecord;
-                TEExamStudent teExamStudent = teExamStudentService.getById(tOeExamRecord.getExamStudentId());
-                studentId = teExamStudent.getStudentId();
-            } else {
-                ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
-                Optional.ofNullable(examStudentCacheBean).orElseThrow(() -> new BusinessException("考生数据为空"));
-                studentId = examStudentCacheBean.getStudentId();
-            }
+                || Objects.equals(MqTagEnum.EXAM_START.name(), tag)//考试开始
+                || Objects.equals(MqTagEnum.EXAM_AUDIO_MOBILE.name(), tag)) {//考试语音
+            if (Objects.equals(MqTagEnum.EXAM_STOP.name(), tag) || Objects.equals(MqTagEnum.EXAM_START.name(), tag)) {
+                examStartAndStopLogic(mqDto, key);
+            } else if (Objects.equals(MqTagEnum.EXAM_AUDIO_MOBILE.name(), tag)) {
+                Map<String, Object> properties = mqDto.getProperties();
+                if (!CollectionUtils.isEmpty(properties) && Objects.nonNull(properties.get(SystemConstant.CONTENT))) {
+                    List<String> list = (List<String>) properties.get(SystemConstant.CONTENT);
+                    Long teAudioId = Long.parseLong(list.get(0));
+                    Long examActivityId = Long.parseLong(list.get(1));
+                    Long examId = Long.parseLong(list.get(2));
+                    Long execTime = Long.parseLong(list.get(3));
+                    if (Objects.nonNull(teAudioId)) {
+                        List<TOeExamRecord> tOeExamRecordList = tOeExamRecordService.findExamRecordByExamIdAndExamActivityId(examId, examActivityId);
+                        if (!CollectionUtils.isEmpty(tOeExamRecordList)) {
+                            ConcurrentHashMap<String, WebSocketMobileServer> webSocketMap = WebSocketMobileServer.getWebSocketMap();
+                            for (TOeExamRecord t : tOeExamRecordList) {
+                                ExamCacheBean examCacheBean = teExamService.getExamCacheBean(examId);
+                                ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(examActivityId);
+                                TEAudio teAudio = cacheService.examAudioCache(teAudioId);
+                                if (Objects.nonNull(examCacheBean) && Objects.nonNull(examActivityCacheBean) && Objects.nonNull(teAudio)
+                                        && Objects.nonNull(examCacheBean.getForceFinish()) && examCacheBean.getForceFinish().intValue() == 1
+                                        && Objects.nonNull(examCacheBean.getEnable()) && examCacheBean.getEnable() == 1
+                                        && Objects.nonNull(examActivityCacheBean.getEnable()) && examActivityCacheBean.getEnable() == 1
+                                        && Objects.nonNull(teAudio.getEnable()) && teAudio.getEnable()
+                                        && Objects.nonNull(t.getMonitorRecord())
+                                        && (t.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_FIRST.name())
+                                        || t.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_SECOND.name()))) {
+                                    ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(t.getId());
+                                    examRecordStatusEnum = Objects.isNull(examRecordStatusEnum) ? t.getStatus() : examRecordStatusEnum;
 
 
-            String mobileFirstWebsocketId = ExamRecordCacheUtil.getMobileFirstWebsocketId(recordId);
-            if (Objects.isNull(mobileFirstWebsocketId)) {
-                tOeExamRecord = Objects.isNull(tOeExamRecord) ? SystemConstant.getExamRecord(recordId) : tOeExamRecord;
-                mobileFirstWebsocketId = tOeExamRecord.getMobileFirstWebsocketId();
-            }
-            if (Objects.nonNull(mobileFirstWebsocketId) && Objects.nonNull(webSocketMap.get(mobileFirstWebsocketId))) {
-                WebSocketMobileServer webSocketFirstMobileServer = webSocketMap.get(mobileFirstWebsocketId);
-                if (Objects.nonNull(examRecordStatusEnum)
-                        && Objects.nonNull(webSocketFirstMobileServer.getRecordId())
-                        && webSocketFirstMobileServer.getRecordId().longValue() == recordId.longValue()) {
-                    WebsocketDto websocketDto = null;
-                    switch (tag.toUpperCase()) {
-                        case "EXAM_STOP":
-                            if (!Objects.equals(ExamRecordStatusEnum.ANSWERING, examRecordStatusEnum)) {
-                                websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_STOP.name(), mqDto.getProperties());
-                                webSocketFirstMobileServer.sendMessage(websocketDto);
-                                SystemConstant.mobileMonitorStatusStop(studentId, recordId, false);
-                                Map<String, Object> properties = mqDto.getProperties();
-                                if (Objects.nonNull(properties) && properties.size() > 0) {
-                                    Boolean removeWebsocket = (Boolean) properties.get(SystemConstant.REMOVE_WEBSOCKET);
-                                    if (Objects.nonNull(removeWebsocket) && removeWebsocket) {
-                                        WebSocketMobileServer.close(webSocketFirstMobileServer);
+                                    if (Objects.nonNull(t.getMonitorRecord()) && t.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_FIRST.name())) {
+                                        //第一机位
+                                        String mobileFirstWebsocketId = ExamRecordCacheUtil.getMobileFirstWebsocketId(t.getId());
+                                        mobileFirstWebsocketId = Objects.isNull(mobileFirstWebsocketId) ? t.getMobileFirstWebsocketId() : mobileFirstWebsocketId;
+                                        if (Objects.nonNull(mobileFirstWebsocketId) && Objects.nonNull(webSocketMap.get(mobileFirstWebsocketId))) {
+                                            WebSocketMobileServer webSocketFirstMobileServer = webSocketMap.get(mobileFirstWebsocketId);
+                                            if (Objects.nonNull(examRecordStatusEnum)
+                                                    && Objects.nonNull(webSocketFirstMobileServer.getRecordId())
+                                                    && webSocketFirstMobileServer.getRecordId().longValue() == t.getId().longValue()) {
+                                                if (!Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
+                                                        && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum)) {
+                                                    Map<String, Object> map = new HashMap<>();
+                                                    map.put(SystemConstant.RECORD_ID, t.getId());
+                                                    map.put(SystemConstant.EXEC_TIME, execTime);
+                                                    TBAttachment tbAttachment = cacheService.attachmentCache(teAudio.getAttachmentId());
+                                                    if (Objects.nonNull(tbAttachment) && Objects.nonNull(tbAttachment.getRemark())) {
+                                                        JSONObject jsonObject = JSONObject.parseObject(tbAttachment.getRemark());
+                                                        map.put(SystemConstant.PATH, ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + jsonObject.getString(SystemConstant.PATH));
+                                                        map.put(SystemConstant.NAME, tbAttachment.getName() + tbAttachment.getType());
+                                                    }
+                                                    WebsocketDto websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_AUDIO.name(), map);
+                                                    webSocketFirstMobileServer.sendMessage(websocketDto);
+                                                }
+                                            }
+                                        }
+                                    }
+
+                                    if (Objects.nonNull(t.getMonitorRecord()) && t.getMonitorRecord().contains(MonitorVideoSourceEnum.MOBILE_SECOND.name())) {
+                                        //第二机位
+                                        String mobileSecondWebsocketId = ExamRecordCacheUtil.getMobileSecondWebsocketId(t.getId());
+                                        mobileSecondWebsocketId = Objects.isNull(mobileSecondWebsocketId) ? t.getMobileSecondWebsocketId() : mobileSecondWebsocketId;
+                                        if (Objects.nonNull(mobileSecondWebsocketId) && Objects.nonNull(webSocketMap.get(mobileSecondWebsocketId))) {
+                                            WebSocketMobileServer webSocketSecondMobileServer = webSocketMap.get(mobileSecondWebsocketId);
+                                            if (Objects.nonNull(examRecordStatusEnum)
+                                                    && Objects.nonNull(webSocketSecondMobileServer.getRecordId())
+                                                    && webSocketSecondMobileServer.getRecordId().longValue() == t.getId().longValue()) {
+                                                if (!Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
+                                                        && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum)) {
+                                                    Map<String, Object> map = new HashMap<>();
+                                                    map.put(SystemConstant.RECORD_ID, t.getId());
+                                                    map.put(SystemConstant.EXEC_TIME, execTime);
+                                                    TBAttachment tbAttachment = cacheService.attachmentCache(teAudio.getAttachmentId());
+                                                    if (Objects.nonNull(tbAttachment) && Objects.nonNull(tbAttachment.getRemark())) {
+                                                        JSONObject jsonObject = JSONObject.parseObject(tbAttachment.getRemark());
+                                                        map.put(SystemConstant.PATH, ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + jsonObject.getString(SystemConstant.PATH));
+                                                        map.put(SystemConstant.NAME, tbAttachment.getName() + tbAttachment.getType());
+                                                    }
+                                                    WebsocketDto websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_AUDIO.name(), map);
+                                                    webSocketSecondMobileServer.sendMessage(websocketDto);
+                                                }
+                                            }
+                                        }
                                     }
                                     }
                                 }
                                 }
                             }
                             }
-                            break;
-                        case "EXAM_START":
-                            if (!Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
-                                    && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum)) {
-                                websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_START.name(), mqDto.getProperties());
-                                webSocketFirstMobileServer.sendMessage(websocketDto);
-                            }
-                            break;
-                        default:
-                            break;
+                        }
                     }
                     }
-                    tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
                 }
                 }
+                tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
             }
             }
-            String mobileSecondWebsocketId = ExamRecordCacheUtil.getMobileSecondWebsocketId(recordId);
-            if (Objects.isNull(mobileSecondWebsocketId)) {
-                tOeExamRecord = Objects.isNull(tOeExamRecord) ? SystemConstant.getExamRecord(recordId) : tOeExamRecord;
-                mobileSecondWebsocketId = tOeExamRecord.getMobileSecondWebsocketId();
-            }
-            if (Objects.nonNull(mobileSecondWebsocketId) && Objects.nonNull(webSocketMap.get(mobileSecondWebsocketId))) {
-                WebSocketMobileServer webSocketSecondMobileServer = webSocketMap.get(mobileSecondWebsocketId);
-                if (Objects.nonNull(examRecordStatusEnum)
-                        && Objects.nonNull(webSocketSecondMobileServer.getRecordId())
-                        && webSocketSecondMobileServer.getRecordId().longValue() == recordId.longValue()) {
-                    WebsocketDto websocketDto = null;
-                    switch (tag.toUpperCase()) {
-                        case "EXAM_STOP":
-                            if (!Objects.equals(ExamRecordStatusEnum.ANSWERING, examRecordStatusEnum)) {
-                                websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_STOP.name(), mqDto.getProperties());
-                                webSocketSecondMobileServer.sendMessage(websocketDto);
-                                SystemConstant.mobileMonitorStatusStop(studentId, recordId, false);
-                                Map<String, Object> properties = mqDto.getProperties();
-                                if (Objects.nonNull(properties) && properties.size() > 0) {
-                                    Boolean mobileRemoveWebsocket = (Boolean) properties.get(SystemConstant.REMOVE_WEBSOCKET);
-                                    if (Objects.nonNull(mobileRemoveWebsocket) && mobileRemoveWebsocket) {
-                                        WebSocketMobileServer.close(webSocketSecondMobileServer);
-                                    }
+        }
+    }
+
+
+    /**
+     * 考试开始和停止逻辑
+     *
+     * @param mqDto
+     * @param key
+     * @throws NoSuchAlgorithmException
+     * @throws IOException
+     */
+    public void examStartAndStopLogic(MqDto mqDto, String key) throws NoSuchAlgorithmException, IOException {
+        ConcurrentHashMap<String, WebSocketMobileServer> webSocketMap = WebSocketMobileServer.getWebSocketMap();
+        String tag = mqDto.getTag();
+        Long recordId = Long.parseLong(String.valueOf(mqDto.getBody()));
+        TOeExamRecord tOeExamRecord = null;
+        ExamRecordStatusEnum examRecordStatusEnum = ExamRecordCacheUtil.getStatus(recordId);
+        if (Objects.isNull(examRecordStatusEnum)) {
+            tOeExamRecord = SystemConstant.getExamRecord(recordId);
+            examRecordStatusEnum = tOeExamRecord.getStatus();
+        }
+        Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
+        Long studentId = null;
+        if (Objects.isNull(examStudentId)) {
+            tOeExamRecord = Objects.isNull(tOeExamRecord) ? SystemConstant.getExamRecord(recordId) : tOeExamRecord;
+            TEExamStudent teExamStudent = teExamStudentService.getById(tOeExamRecord.getExamStudentId());
+            studentId = teExamStudent.getStudentId();
+        } else {
+            ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
+            Optional.ofNullable(examStudentCacheBean).orElseThrow(() -> new BusinessException("考生数据为空"));
+            studentId = examStudentCacheBean.getStudentId();
+        }
+
+        String mobileFirstWebsocketId = ExamRecordCacheUtil.getMobileFirstWebsocketId(recordId);
+        if (Objects.isNull(mobileFirstWebsocketId)) {
+            tOeExamRecord = Objects.isNull(tOeExamRecord) ? SystemConstant.getExamRecord(recordId) : tOeExamRecord;
+            mobileFirstWebsocketId = tOeExamRecord.getMobileFirstWebsocketId();
+        }
+        if (Objects.nonNull(mobileFirstWebsocketId) && Objects.nonNull(webSocketMap.get(mobileFirstWebsocketId))) {
+            WebSocketMobileServer webSocketFirstMobileServer = webSocketMap.get(mobileFirstWebsocketId);
+            if (Objects.nonNull(examRecordStatusEnum)
+                    && Objects.nonNull(webSocketFirstMobileServer.getRecordId())
+                    && webSocketFirstMobileServer.getRecordId().longValue() == recordId.longValue()) {
+                WebsocketDto websocketDto = null;
+                switch (tag.toUpperCase()) {
+                    case "EXAM_STOP":
+                        if (!Objects.equals(ExamRecordStatusEnum.ANSWERING, examRecordStatusEnum)) {
+                            websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_STOP.name(), mqDto.getProperties());
+                            webSocketFirstMobileServer.sendMessage(websocketDto);
+                            SystemConstant.mobileMonitorStatusStop(studentId, recordId, false);
+                            Map<String, Object> properties = mqDto.getProperties();
+                            if (Objects.nonNull(properties) && properties.size() > 0) {
+                                Boolean removeWebsocket = (Boolean) properties.get(SystemConstant.REMOVE_WEBSOCKET);
+                                if (Objects.nonNull(removeWebsocket) && removeWebsocket) {
+                                    WebSocketMobileServer.close(webSocketFirstMobileServer);
                                 }
                                 }
                             }
                             }
-                            break;
-                        case "EXAM_START":
-                            if (!Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
-                                    && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum)) {
-                                websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_START.name(), mqDto.getProperties());
-                                webSocketSecondMobileServer.sendMessage(websocketDto);
+                        }
+                        break;
+                    case "EXAM_START":
+                        if (!Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
+                                && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum)) {
+                            websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_START.name(), mqDto.getProperties());
+                            webSocketFirstMobileServer.sendMessage(websocketDto);
+                        }
+                        break;
+                    default:
+                        break;
+                }
+                tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
+            }
+        }
+        String mobileSecondWebsocketId = ExamRecordCacheUtil.getMobileSecondWebsocketId(recordId);
+        if (Objects.isNull(mobileSecondWebsocketId)) {
+            tOeExamRecord = Objects.isNull(tOeExamRecord) ? SystemConstant.getExamRecord(recordId) : tOeExamRecord;
+            mobileSecondWebsocketId = tOeExamRecord.getMobileSecondWebsocketId();
+        }
+        if (Objects.nonNull(mobileSecondWebsocketId) && Objects.nonNull(webSocketMap.get(mobileSecondWebsocketId))) {
+            WebSocketMobileServer webSocketSecondMobileServer = webSocketMap.get(mobileSecondWebsocketId);
+            if (Objects.nonNull(examRecordStatusEnum)
+                    && Objects.nonNull(webSocketSecondMobileServer.getRecordId())
+                    && webSocketSecondMobileServer.getRecordId().longValue() == recordId.longValue()) {
+                WebsocketDto websocketDto = null;
+                switch (tag.toUpperCase()) {
+                    case "EXAM_STOP":
+                        if (!Objects.equals(ExamRecordStatusEnum.ANSWERING, examRecordStatusEnum)) {
+                            websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_STOP.name(), mqDto.getProperties());
+                            webSocketSecondMobileServer.sendMessage(websocketDto);
+                            SystemConstant.mobileMonitorStatusStop(studentId, recordId, false);
+                            Map<String, Object> properties = mqDto.getProperties();
+                            if (Objects.nonNull(properties) && properties.size() > 0) {
+                                Boolean mobileRemoveWebsocket = (Boolean) properties.get(SystemConstant.REMOVE_WEBSOCKET);
+                                if (Objects.nonNull(mobileRemoveWebsocket) && mobileRemoveWebsocket) {
+                                    WebSocketMobileServer.close(webSocketSecondMobileServer);
+                                }
                             }
                             }
-                            break;
-                        default:
-                            break;
-                    }
-                    tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
+                        }
+                        break;
+                    case "EXAM_START":
+                        if (!Objects.equals(ExamRecordStatusEnum.PERSISTED, examRecordStatusEnum)
+                                && !Objects.equals(ExamRecordStatusEnum.FINISHED, examRecordStatusEnum)) {
+                            websocketDto = new WebsocketDto(WebsocketTypeEnum.EXAM_START.name(), mqDto.getProperties());
+                            webSocketSecondMobileServer.sendMessage(websocketDto);
+                        }
+                        break;
+                    default:
+                        break;
                 }
                 }
+                tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
             }
             }
         }
         }
     }
     }

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

@@ -44,7 +44,7 @@ public class StartRunning implements CommandLineRunner {
          * websocket mq start
          * websocket mq start
          */
          */
         rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.WEBSOCKET_OE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.OE_IM_BROADCASTING.name() + "||" + MqTagEnum.OE_IM_CLUSTERING.name() + "||" + MqTagEnum.OE_LIVENESS_VERIFY.name() + "||" + MqTagEnum.OE_MONITOR_FINISH.name() + "||" + MqTagEnum.OE_WARNING_FINISH.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_READY.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_UPLOAD.name() + "||" + MqTagEnum.OE_WEBSOCKET_EXAM_STOP.name() + "||" + MqTagEnum.MONITOR_START.name() + "||" + MqTagEnum.MONITOR_STOP.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_MONITOR_STATUS.name(), MessageModel.BROADCASTING, SpringContextHolder.getBean(WebSocketOeServer.class));
         rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.WEBSOCKET_OE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.OE_IM_BROADCASTING.name() + "||" + MqTagEnum.OE_IM_CLUSTERING.name() + "||" + MqTagEnum.OE_LIVENESS_VERIFY.name() + "||" + MqTagEnum.OE_MONITOR_FINISH.name() + "||" + MqTagEnum.OE_WARNING_FINISH.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_READY.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_UPLOAD.name() + "||" + MqTagEnum.OE_WEBSOCKET_EXAM_STOP.name() + "||" + MqTagEnum.MONITOR_START.name() + "||" + MqTagEnum.MONITOR_STOP.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_MONITOR_STATUS.name(), MessageModel.BROADCASTING, SpringContextHolder.getBean(WebSocketOeServer.class));
-        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.WEBSOCKET_OE_MOBILE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_STOP.name() + "||" + MqTagEnum.EXAM_START.name(), MessageModel.BROADCASTING, SpringContextHolder.getBean(WebSocketMobileServer.class));
+        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.WEBSOCKET_OE_MOBILE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_STOP.name() + "||" + MqTagEnum.EXAM_START.name() + "||" + MqTagEnum.EXAM_AUDIO_MOBILE.name(), MessageModel.BROADCASTING, SpringContextHolder.getBean(WebSocketMobileServer.class));
         //TODO 因单机广播模式出现消费者无法消费消息的问题,所以开发时改成CLUSTERING模式,正式环境要改成BROADCASTING模式
         //TODO 因单机广播模式出现消费者无法消费消息的问题,所以开发时改成CLUSTERING模式,正式环境要改成BROADCASTING模式
 //        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.WEBSOCKET_OE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.OE_IM_BROADCASTING.name() + "||" + MqTagEnum.OE_IM_CLUSTERING.name() + "||" + MqTagEnum.OE_LIVENESS_VERIFY.name() + "||" + MqTagEnum.OE_MONITOR_FINISH.name() + "||" + MqTagEnum.OE_WARNING_FINISH.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_READY.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_UPLOAD.name() + "||" + MqTagEnum.OE_WEBSOCKET_EXAM_STOP.name() + "||" + MqTagEnum.MONITOR_START.name() + "||" + MqTagEnum.MONITOR_STOP.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_MONITOR_STATUS.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(WebSocketOeServer.class));
 //        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.WEBSOCKET_OE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.OE_IM_BROADCASTING.name() + "||" + MqTagEnum.OE_IM_CLUSTERING.name() + "||" + MqTagEnum.OE_LIVENESS_VERIFY.name() + "||" + MqTagEnum.OE_MONITOR_FINISH.name() + "||" + MqTagEnum.OE_WARNING_FINISH.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_READY.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_ANSWER_UPLOAD.name() + "||" + MqTagEnum.OE_WEBSOCKET_EXAM_STOP.name() + "||" + MqTagEnum.MONITOR_START.name() + "||" + MqTagEnum.MONITOR_STOP.name() + "||" + MqTagEnum.OE_WEBSOCKET_MOBILE_MONITOR_STATUS.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(WebSocketOeServer.class));
 //        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.WEBSOCKET_OE_MOBILE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_STOP.name() + "||" + MqTagEnum.EXAM_START.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(WebSocketMobileServer.class));
 //        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.WEBSOCKET_OE_MOBILE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_STOP.name() + "||" + MqTagEnum.EXAM_START.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(WebSocketMobileServer.class));

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

@@ -75,7 +75,6 @@ public class WebSocketMobileServer implements Concurrently {
         this.redisUtil = SpringContextHolder.getBean(RedisUtil.class);
         this.redisUtil = SpringContextHolder.getBean(RedisUtil.class);
         this.recordId = (Long) session.getUserProperties().get(Constants.HEADER_RECORD_ID);
         this.recordId = (Long) session.getUserProperties().get(Constants.HEADER_RECORD_ID);
         this.deviceId = (String) session.getUserProperties().get(Constants.HEADER_DEVICE_ID);
         this.deviceId = (String) session.getUserProperties().get(Constants.HEADER_DEVICE_ID);
-        TBSession tbSession = (TBSession) session.getUserProperties().get(Constants.HEADER_TB_SESSION);
         this.source = (MonitorVideoSourceEnum) session.getUserProperties().get(Constants.HEADER_SOURCE);
         this.source = (MonitorVideoSourceEnum) session.getUserProperties().get(Constants.HEADER_SOURCE);
         this.session = session;
         this.session = session;
         session.setMaxIdleTimeout(SystemConstant.WEBSOCKET_MAX_TIME_OUT);
         session.setMaxIdleTimeout(SystemConstant.WEBSOCKET_MAX_TIME_OUT);

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

@@ -76,7 +76,6 @@ public class WebSocketOeServer implements Concurrently {
         this.redisUtil = SpringContextHolder.getBean(RedisUtil.class);
         this.redisUtil = SpringContextHolder.getBean(RedisUtil.class);
         this.recordId = (Long) session.getUserProperties().get(Constants.HEADER_RECORD_ID);
         this.recordId = (Long) session.getUserProperties().get(Constants.HEADER_RECORD_ID);
         this.deviceId = (String) session.getUserProperties().get(Constants.HEADER_DEVICE_ID);
         this.deviceId = (String) session.getUserProperties().get(Constants.HEADER_DEVICE_ID);
-        TBSession tbSession = (TBSession) session.getUserProperties().get(Constants.HEADER_TB_SESSION);
         this.session = session;
         this.session = session;
         session.setMaxIdleTimeout(SystemConstant.WEBSOCKET_MAX_TIME_OUT);
         session.setMaxIdleTimeout(SystemConstant.WEBSOCKET_MAX_TIME_OUT);
         websocketSessionId = String.valueOf(UidUtil.nextId());
         websocketSessionId = String.valueOf(UidUtil.nextId());

+ 2 - 2
themis-mq/pom.xml

@@ -4,13 +4,13 @@
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.themis.mq</groupId>
     <groupId>com.qmth.themis.mq</groupId>
     <artifactId>themis-mq</artifactId>
     <artifactId>themis-mq</artifactId>
-    <version>1.2.2</version>
+    <version>1.2.3</version>
     <packaging>jar</packaging>
     <packaging>jar</packaging>
 
 
     <parent>
     <parent>
         <groupId>com.qmth.themis</groupId>
         <groupId>com.qmth.themis</groupId>
         <artifactId>themis-service</artifactId>
         <artifactId>themis-service</artifactId>
-        <version>1.2.2</version>
+        <version>1.2.3</version>
     </parent>
     </parent>
 
 
     <dependencies>
     <dependencies>

+ 2 - 2
themis-task/pom.xml

@@ -4,13 +4,13 @@
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.qmth.themis.task</groupId>
     <groupId>com.qmth.themis.task</groupId>
     <artifactId>themis-task</artifactId>
     <artifactId>themis-task</artifactId>
-    <version>1.2.2</version>
+    <version>1.2.3</version>
     <packaging>jar</packaging>
     <packaging>jar</packaging>
 
 
     <parent>
     <parent>
         <groupId>com.qmth.themis</groupId>
         <groupId>com.qmth.themis</groupId>
         <artifactId>themis-service</artifactId>
         <artifactId>themis-service</artifactId>
-        <version>1.2.2</version>
+        <version>1.2.3</version>
     </parent>
     </parent>
 
 
     <dependencies>
     <dependencies>

+ 4 - 2
themis-task/src/main/java/com/qmth/themis/task/enums/QuartzTaskEnum.java

@@ -17,12 +17,14 @@ public enum QuartzTaskEnum {
 
 
     EXAM_STUDENT_JOB_GROUP_NAME("考生一次性延时job group"),
     EXAM_STUDENT_JOB_GROUP_NAME("考生一次性延时job group"),
 
 
+    EXAM_AUDIO_JOB_GROUP_NAME("考试语音播报一次性延时job group"),
+
     MQ_ACTIVITY_JOB_NAME("mq_activity_job"),
     MQ_ACTIVITY_JOB_NAME("mq_activity_job"),
 
 
     MQ_ACTIVITY_JOB_GROUP_NAME("mq_activity_job group"),
     MQ_ACTIVITY_JOB_GROUP_NAME("mq_activity_job group"),
-    
+
     OBJECTIVE_ANSWER_CACHE_LOAD_JOB_NAME("客观题缓存加载"),
     OBJECTIVE_ANSWER_CACHE_LOAD_JOB_NAME("客观题缓存加载"),
-    
+
     OBJECTIVE_ANSWER_CACHE_LOAD_JOB_GROUP_NAME("客观题缓存加载");
     OBJECTIVE_ANSWER_CACHE_LOAD_JOB_GROUP_NAME("客观题缓存加载");
 
 
     private QuartzTaskEnum(String code) {
     private QuartzTaskEnum(String code) {

+ 1 - 0
themis-task/src/main/java/com/qmth/themis/task/listener/MyJobListener.java

@@ -49,6 +49,7 @@ public class MyJobListener implements JobListener {
             case EXAM_ACTIVITY_JOB_GROUP_NAME:
             case EXAM_ACTIVITY_JOB_GROUP_NAME:
             case EXAM_STUDENT_JOB_GROUP_NAME:
             case EXAM_STUDENT_JOB_GROUP_NAME:
             case MQ_ACTIVITY_JOB_GROUP_NAME:
             case MQ_ACTIVITY_JOB_GROUP_NAME:
+            case EXAM_AUDIO_JOB_GROUP_NAME:
                 try {
                 try {
                     TSLogService tsLogService = SpringContextHolder.getBean(TSLogService.class);
                     TSLogService tsLogService = SpringContextHolder.getBean(TSLogService.class);
                     tsLogService.save(new TSLog(LogEnum.JOB, JacksonUtil.parseJson(context.getTrigger().getJobKey()),
                     tsLogService.save(new TSLog(LogEnum.JOB, JacksonUtil.parseJson(context.getTrigger().getJobKey()),

+ 19 - 6
themis-task/src/main/java/com/qmth/themis/task/listener/service/impl/MqTaskLogicServiceImpl.java

@@ -7,6 +7,7 @@ import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.dto.MqDto;
+import com.qmth.themis.business.entity.TEAudio;
 import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.entity.TEExam;
 import com.qmth.themis.business.entity.TEExamActivity;
 import com.qmth.themis.business.entity.TEExamActivity;
 import com.qmth.themis.business.enums.MqTagEnum;
 import com.qmth.themis.business.enums.MqTagEnum;
@@ -15,6 +16,7 @@ import com.qmth.themis.business.util.JacksonUtil;
 import com.qmth.themis.task.enums.QuartzTaskEnum;
 import com.qmth.themis.task.enums.QuartzTaskEnum;
 import com.qmth.themis.task.listener.service.MqTaskLogicService;
 import com.qmth.themis.task.listener.service.MqTaskLogicService;
 import com.qmth.themis.task.quartz.ExamActivityJob;
 import com.qmth.themis.task.quartz.ExamActivityJob;
+import com.qmth.themis.task.quartz.ExamAudioJob;
 import com.qmth.themis.task.quartz.ExamStudentJob;
 import com.qmth.themis.task.quartz.ExamStudentJob;
 import com.qmth.themis.task.service.QuartzService;
 import com.qmth.themis.task.service.QuartzService;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
@@ -62,15 +64,15 @@ public class MqTaskLogicServiceImpl implements MqTaskLogicService {
     @Transactional
     @Transactional
     public void execMqQuartzLogic(MqDto mqDto, String key) {
     public void execMqQuartzLogic(MqDto mqDto, String key) {
         Map<String, Object> tranMap = mqDto.getProperties();
         Map<String, Object> tranMap = mqDto.getProperties();
-        String oper = String.valueOf(tranMap.get("oper"));
-        Object o = JacksonUtil.parseJson(tranMap.get("exam"));
+        String oper = String.valueOf(tranMap.get(SystemConstant.OPER));
+        Object o = JacksonUtil.parseJson(tranMap.get(SystemConstant.EXAM));
         String tag = mqDto.getTag();
         String tag = mqDto.getTag();
         TEExam teExam = JSONObject.toJavaObject(JSONObject.parseObject(String.valueOf(o)), TEExam.class);
         TEExam teExam = JSONObject.toJavaObject(JSONObject.parseObject(String.valueOf(o)), TEExam.class);
-        if (Objects.equals(tag, MqTagEnum.EXAM_ACTIVITY.name())) {
+        if (Objects.equals(tag, MqTagEnum.EXAM_ACTIVITY.name())) {//考场任务
             JSONArray jsonArray = (JSONArray) JSONArray.parse(String.valueOf(mqDto.getBody()));
             JSONArray jsonArray = (JSONArray) JSONArray.parse(String.valueOf(mqDto.getBody()));
             for (int i = 0; i < jsonArray.size(); i++) {
             for (int i = 0; i < jsonArray.size(); i++) {
                 TEExamActivity teExamActivity = JSONObject.toJavaObject((JSON) jsonArray.get(i), TEExamActivity.class);
                 TEExamActivity teExamActivity = JSONObject.toJavaObject((JSON) jsonArray.get(i), TEExamActivity.class);
-                if (Objects.equals("delete", oper)) {
+                if (Objects.equals(SystemConstant.DELETE, oper)) {
                     quartzService.deleteJob(String.valueOf(teExamActivity.getId()), QuartzTaskEnum.EXAM_ACTIVITY_JOB_GROUP_NAME.name());
                     quartzService.deleteJob(String.valueOf(teExamActivity.getId()), QuartzTaskEnum.EXAM_ACTIVITY_JOB_GROUP_NAME.name());
                 } else {
                 } else {
                     if (Objects.nonNull(teExam.getEnable()) && teExam.getEnable().intValue() == 1 && Objects.nonNull(teExamActivity.getEnable()) && teExamActivity.getEnable().intValue() == 1) {
                     if (Objects.nonNull(teExam.getEnable()) && teExam.getEnable().intValue() == 1 && Objects.nonNull(teExamActivity.getEnable()) && teExamActivity.getEnable().intValue() == 1) {
@@ -78,15 +80,26 @@ public class MqTaskLogicServiceImpl implements MqTaskLogicService {
                     }
                     }
                 }
                 }
             }
             }
-        } else if (Objects.equals(tag, MqTagEnum.EXAM_STUDENT.name())) {
+        } else if (Objects.equals(tag, MqTagEnum.EXAM_STUDENT.name())) {//考生任务
             JSONObject jsonObject = JSONObject.parseObject(String.valueOf(mqDto.getBody()));
             JSONObject jsonObject = JSONObject.parseObject(String.valueOf(mqDto.getBody()));
             ExamStudentCacheBean examStudentCacheBean = JSONObject.toJavaObject(jsonObject, ExamStudentCacheBean.class);
             ExamStudentCacheBean examStudentCacheBean = JSONObject.toJavaObject(jsonObject, ExamStudentCacheBean.class);
             Long recordId = Long.parseLong(String.valueOf(mqDto.getObjId()));
             Long recordId = Long.parseLong(String.valueOf(mqDto.getObjId()));
-            if (Objects.equals("delete", oper)) {
+            if (Objects.equals(SystemConstant.DELETE, oper)) {
                 quartzService.deleteJob(examStudentCacheBean.getId() + "-" + recordId, QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME.name());
                 quartzService.deleteJob(examStudentCacheBean.getId() + "-" + recordId, QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME.name());
             } else {
             } else {
                 this.setCron(ExamRecordCacheUtil.getExamFinalFinishTime(recordId), examStudentCacheBean.getId() + "-" + recordId, ExamStudentJob.class, QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME);
                 this.setCron(ExamRecordCacheUtil.getExamFinalFinishTime(recordId), examStudentCacheBean.getId() + "-" + recordId, ExamStudentJob.class, QuartzTaskEnum.EXAM_STUDENT_JOB_GROUP_NAME);
             }
             }
+        } else if (Objects.equals(tag, MqTagEnum.EXAM_AUDIO.name())) {//考试语音
+            JSONObject jsonObject = JSONObject.parseObject(String.valueOf(mqDto.getBody()));
+            TEAudio teAudio = JSONObject.toJavaObject(jsonObject, TEAudio.class);
+            Long examId = Long.parseLong(String.valueOf(mqDto.getObjId()));
+            if (Objects.equals(SystemConstant.DELETE, oper)) {
+                quartzService.deleteJob(teAudio.getId() + "-" + teAudio.getActivityId() + "-" + examId, QuartzTaskEnum.EXAM_AUDIO_JOB_GROUP_NAME.name());
+            } else {
+                Long execTime = (Long) tranMap.get(SystemConstant.EXEC_TIME);
+                Long realExecTime = (Long) tranMap.get(SystemConstant.REAL_EXEC_TIME);
+                this.setCron(execTime, teAudio.getId() + "-" + teAudio.getActivityId() + "-" + examId + "-" + realExecTime, ExamAudioJob.class, QuartzTaskEnum.EXAM_AUDIO_JOB_GROUP_NAME);
+            }
         }
         }
         tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
         tmRocketMessageService.saveMqMessageSuccess(mqDto, key);
     }
     }

+ 44 - 0
themis-task/src/main/java/com/qmth/themis/task/quartz/ExamAudioJob.java

@@ -0,0 +1,44 @@
+package com.qmth.themis.task.quartz;
+
+import com.qmth.themis.task.quartz.service.QuartzLogicService;
+import org.quartz.JobDetail;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.Objects;
+
+/**
+ * @Description: examAudio job,一次性延时任务
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2020/9/23
+ */
+@Component
+public class ExamAudioJob extends QuartzJobBean {
+    private final static Logger log = LoggerFactory.getLogger(ExamAudioJob.class);
+
+    @Resource
+    QuartzLogicService quartzLogicService;
+
+    /**
+     * 考试语音一次性延时任务
+     *
+     * @param context
+     * @throws JobExecutionException
+     */
+    @Override
+    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
+        log.info("exam_audio_job进来了,context:{}", context);
+        JobDetail jobDetail = context.getJobDetail();
+        String key = String.valueOf(jobDetail.getKey());
+        if (Objects.nonNull(key)) {
+            quartzLogicService.execExamAudioJobLogic(key);
+        }
+    }
+}

+ 7 - 0
themis-task/src/main/java/com/qmth/themis/task/quartz/service/QuartzLogicService.java

@@ -22,4 +22,11 @@ public interface QuartzLogicService {
      * @param key
      * @param key
      */
      */
     public void execExamStudentJobLogic(String key);
     public void execExamStudentJobLogic(String key);
+
+    /**
+     * 考试语音quartz逻辑
+     *
+     * @param key
+     */
+    public void execExamAudioJobLogic(String key);
 }
 }

+ 26 - 2
themis-task/src/main/java/com/qmth/themis/task/quartz/service/impl/QuartzLogicServiceImpl.java

@@ -6,10 +6,13 @@ import com.qmth.themis.business.cache.bean.ExamActivityCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.constant.SystemConstant;
+import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.entity.TOeExamRecord;
 import com.qmth.themis.business.entity.TOeExamRecord;
 import com.qmth.themis.business.enums.ExamRecordStatusEnum;
 import com.qmth.themis.business.enums.ExamRecordStatusEnum;
 import com.qmth.themis.business.enums.FinishTypeEnum;
 import com.qmth.themis.business.enums.FinishTypeEnum;
+import com.qmth.themis.business.enums.MqTagEnum;
 import com.qmth.themis.business.service.*;
 import com.qmth.themis.business.service.*;
+import com.qmth.themis.business.util.MqUtil;
 import com.qmth.themis.task.quartz.service.QuartzLogicService;
 import com.qmth.themis.task.quartz.service.QuartzLogicService;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
@@ -18,8 +21,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.CollectionUtils;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
 
 
 /**
 /**
  * @Description: quartz逻辑 impl
  * @Description: quartz逻辑 impl
@@ -47,6 +49,12 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
     @Resource
     @Resource
     CommonService commonService;
     CommonService commonService;
 
 
+    @Resource
+    MqUtil mqUtil;
+
+    @Resource
+    MqDtoService mqDtoService;
+
     /**
     /**
      * 考试场次quartz逻辑
      * 考试场次quartz逻辑
      *
      *
@@ -154,4 +162,20 @@ public class QuartzLogicServiceImpl implements QuartzLogicService {
             }
             }
         }
         }
     }
     }
+
+    /**
+     * 考试语音quartz逻辑
+     *
+     * @param key
+     */
+    @Override
+    public void execExamAudioJobLogic(String key) {
+        log.info("execExamAudioJobLogic key:{}", key);
+        String[] strings = key.split("\\.");
+        String[] exams = strings[1].split("-");
+        Map<String, Object> mapParameter = new HashMap<>();
+        mapParameter.put(SystemConstant.CONTENT, Arrays.asList(exams));
+        MqDto mqDto = new MqDto(mqUtil.getMqGroupDomain().getTopic(), MqTagEnum.EXAM_AUDIO_MOBILE.name(), Long.parseLong(exams[2]), MqTagEnum.EXAM_AUDIO_MOBILE, exams[2], mapParameter, exams[2]);
+        mqDtoService.assembleSendOneOrderMsg(mqDto);
+    }
 }
 }

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

@@ -99,7 +99,7 @@ public class StartRunning implements CommandLineRunner {
         /**
         /**
          * quartz mq start
          * quartz mq start
          */
          */
-        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.QUARTZ_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name() + "||" + MqTagEnum.EXAM_STUDENT.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(QuartzOrderlyImpl.class));
+        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.QUARTZ_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.EXAM_ACTIVITY.name() + "||" + MqTagEnum.EXAM_STUDENT.name() + "||" + MqTagEnum.EXAM_AUDIO.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(QuartzOrderlyImpl.class));
         //计算客观分
         //计算客观分
 //        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.CALCULATE_OBJECTIVE_SCORE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.CALCULATE_OBJECTIVE_SCORE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(CalculateObjectiveScoreConcurrentlyImpl.class));
 //        rocketMessageConsumer.setRocketMQConsumer(nameServer, dictionaryConfig.mqConfigDomain().getMap().get(MqGroupEnum.CALCULATE_OBJECTIVE_SCORE_GROUP.name()), dictionaryConfig.mqConfigDomain().getTopic(), MqTagEnum.CALCULATE_OBJECTIVE_SCORE.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(CalculateObjectiveScoreConcurrentlyImpl.class));
         //重新算分
         //重新算分