Quellcode durchsuchen

重新整理Source和Platform的对应关系,修改过期时间判断;修改移动端接口source参数的错误;优化二维码生成与移动端扫描登陆的执行逻辑

luoshi vor 4 Jahren
Ursprung
Commit
0caacfd082

+ 11 - 11
themis-backend/src/main/java/com/qmth/themis/backend/api/TBUserController.java

@@ -8,6 +8,7 @@ import com.qmth.themis.business.annotation.ApiJsonObject;
 import com.qmth.themis.business.annotation.ApiJsonProperty;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.AuthDto;
+import com.qmth.themis.business.dto.ExpireTimeDTO;
 import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.dto.response.TBUserDto;
 import com.qmth.themis.business.entity.TBOrg;
@@ -197,24 +198,23 @@ public class TBUserController {
         String token = RandomStringUtils.randomAlphanumeric(32);
         //添加用户缓存
         redisUtil.setUser(user.getId(), user);
-        String source = null;
-        if (Objects.equals(platform.name(), Platform.WIN.name()) || Objects.equals(platform.name(), Platform.MAC.name())
-                || Objects.equals(platform.name(), Platform.IOS.name()) || Objects
-                .equals(platform.name(), Platform.ANDROID.name())) {
-            source = platform.getSource().split(",")[0];
+        Source source = null;
+        if (Platform.WIN == platform || Platform.MAC == platform) {
+            source = Source.ADMIN_CLIENT;
+        } else if (Platform.WEB == platform) {
+            source = Source.ADMIN_WEB;
         } else {
-            source = platform.getSource();
+            throw new BusinessException(ExceptionResultEnum.PLATFORM_INVALID);
         }
         //添加用户会话缓存
         String sessionId = SessionUtil
                 .digest(user.getId(), Math.abs(authDto.getRoleCodes().toString().hashCode()), source);
 
-        Map<String, Object> expireMap = SystemConstant.getExpireTime(platform);
-        Date expire = (Date) expireMap.get("date");
-        Long redisExpire = Long.parseLong(String.valueOf(expireMap.get("redisExpire")));
+        ExpireTimeDTO expireTime = SystemConstant.getExpireTime(source, platform);
         TBSession tbSession = new TBSession(sessionId, String.valueOf(user.getId()), authDto.getRoleCodes().toString(),
-                source, platform.name(), deviceId, ServletUtil.getRequest().getLocalAddr(), token, expire.getTime());
-        redisUtil.setUserSession(sessionId, tbSession, redisExpire);
+                source.name(), platform.name(), deviceId, ServletUtil.getRequest().getLocalAddr(), token,
+                expireTime.getDate().getTime());
+        redisUtil.setUserSession(sessionId, tbSession, expireTime.getExpireSeconds());
         //mq发送消息start
         MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), platform.name(), tbSession,
                 MqTagEnum.valueOf(platform.name()), tbSession.getId(), user.getLoginName());

+ 60 - 29
themis-backend/src/main/java/com/qmth/themis/backend/api/TIeInvigilateCallMobileController.java

@@ -50,6 +50,7 @@ import java.util.Objects;
 @RestController
 @RequestMapping("/${prefix.url.admin}/monitor")
 public class TIeInvigilateCallMobileController {
+
     private final static Logger log = LoggerFactory.getLogger(TIeInvigilateCallMobileController.class);
 
     @Resource
@@ -81,8 +82,11 @@ public class TIeInvigilateCallMobileController {
 
     @ApiOperation(value = "监考监控通话查询接口")
     @RequestMapping(value = "/call/list", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考监控信息", response = TIeExamInvigilateCallDto.class)})
-    public Result callList(@ApiParam(value = "考试批次id", required = true) @RequestParam(required = true) Long examId, @ApiParam(value = "通话状态", required = false) @RequestParam(required = false) String callStatus, @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber, @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考监控信息", response = TIeExamInvigilateCallDto.class) })
+    public Result callList(@ApiParam(value = "考试批次id", required = true) @RequestParam(required = true) Long examId,
+            @ApiParam(value = "通话状态", required = false) @RequestParam(required = false) String callStatus,
+            @ApiParam(value = "分页页码", required = true) @RequestParam int pageNumber,
+            @ApiParam(value = "分页数", required = true) @RequestParam int pageSize) {
         if (Objects.isNull(examId) || Objects.equals(examId, "")) {
             throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
         }
@@ -97,9 +101,12 @@ public class TIeInvigilateCallMobileController {
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
             userId = tbUser.getId();
         }
-        IPage<TIeExamInvigilateCallDto> tIeExamInvigilateCallIPage = tIeExamInvigilateCallService.examInvigilateCallQuery(new Page<>(pageNumber, pageSize), examId, userId, tbUser.getOrgId(), MonitorStatusSourceEnum.START.name(), callStatus);
+        IPage<TIeExamInvigilateCallDto> tIeExamInvigilateCallIPage = tIeExamInvigilateCallService
+                .examInvigilateCallQuery(new Page<>(pageNumber, pageSize), examId, userId, tbUser.getOrgId(),
+                        MonitorStatusSourceEnum.START.name(), callStatus);
         tIeExamInvigilateCallIPage.getRecords().forEach(s -> {
-            s.setBasePhotoPath(ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + s.getBasePhotoPath());
+            s.setBasePhotoPath(
+                    ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + s.getBasePhotoPath());
             try {
                 s.setSourceUserId(this.getSourceUserId(s.getExamRecordId()));
             } catch (NoSuchAlgorithmException e) {
@@ -111,8 +118,9 @@ public class TIeInvigilateCallMobileController {
 
     @ApiOperation(value = "监考监控通话提醒接口")
     @RequestMapping(value = "/call/count", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考监控信息", response = Integer.class)})
-    public Result callCount(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId, @ApiParam(value = "通话状态", required = false) @RequestParam(required = false) String callStatus) {
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考监控信息", response = Integer.class) })
+    public Result callCount(@ApiParam(value = "考试批次id", required = true) @RequestParam Long examId,
+            @ApiParam(value = "通话状态", required = false) @RequestParam(required = false) String callStatus) {
         if (Objects.isNull(examId) || Objects.equals(examId, "")) {
             throw new BusinessException(ExceptionResultEnum.EXAM_ID_IS_NULL);
         }
@@ -127,13 +135,15 @@ public class TIeInvigilateCallMobileController {
         if (authDto.getRoleCodes().toString().contains(RoleEnum.INVIGILATE.name())) {
             userId = tbUser.getId();
         }
-        int count = tIeExamInvigilateCallService.examInvigilateCallQueryCount(examId, userId, tbUser.getOrgId(), MonitorStatusSourceEnum.START.name(), callStatus);
+        int count = tIeExamInvigilateCallService
+                .examInvigilateCallQueryCount(examId, userId, tbUser.getOrgId(), MonitorStatusSourceEnum.START.name(),
+                        callStatus);
         return ResultUtil.ok(Collections.singletonMap("count", count));
     }
 
     @ApiOperation(value = "监考监控通话查询来源接口")
     @RequestMapping(value = "/call/query", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "监考监控信息", response = TIeExamInvigilateCall.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "监考监控信息", response = TIeExamInvigilateCall.class) })
     public Result callQuery(@ApiParam(value = "考试记录id", required = true) @RequestParam(required = true) Long recordId) {
         QueryWrapper<TIeExamInvigilateCall> tIeExamInvigilateCallQueryWrapper = new QueryWrapper<>();
         tIeExamInvigilateCallQueryWrapper.lambda().eq(TIeExamInvigilateCall::getExamRecordId, recordId);
@@ -142,12 +152,11 @@ public class TIeInvigilateCallMobileController {
 
     @ApiOperation(value = "通话中接口")
     @RequestMapping(value = "/call/calling", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class) })
     @Transactional
     public Result callCalling(@ApiJsonObject(name = "callCallingBackendMobile", value = {
             @ApiJsonProperty(key = "recordId", type = "long", example = "1", description = "考试记录id", required = true),
-            @ApiJsonProperty(key = "source", description = "监考视频源", required = true)
-    }) @ApiParam(value = "监控信息", required = true) @RequestBody Map<String, Object> mapParameter) {
+            @ApiJsonProperty(key = "source", description = "监考视频源", required = true) }) @ApiParam(value = "监控信息", required = true) @RequestBody Map<String, Object> mapParameter) {
         if (Objects.isNull(mapParameter.get("recordId")) || Objects.equals(mapParameter.get("recordId"), "")) {
             throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
         }
@@ -164,9 +173,12 @@ public class TIeInvigilateCallMobileController {
         ExamRecordCacheUtil.setMonitorCallStatus(recordId, source, MonitorCallStatusSourceEnum.CALLING);
         String monitorKey = ExamRecordCacheUtil.getMonitorKey(recordId);
         MonitorStatusSourceEnum status = ExamRecordCacheUtil.getMonitorStatus(recordId, source);
-        TIeExamInvigilateCallLog tIeExamInvigilateCallLog = new TIeExamInvigilateCallLog(recordId, source, liveUrl, status, monitorKey, MonitorCallStatusSourceEnum.CALLING);
+        TIeExamInvigilateCallLog tIeExamInvigilateCallLog = new TIeExamInvigilateCallLog(recordId, source, liveUrl,
+                status, monitorKey, MonitorCallStatusSourceEnum.CALLING);
         //监考监控通话信息 发送mq start
-        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.MONITOR_LOG.name(), tIeExamInvigilateCallLog, MqTagEnum.MONITOR_LOG, String.valueOf(tIeExamInvigilateCallLog.getId()), source.name());
+        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.MONITOR_LOG.name(),
+                tIeExamInvigilateCallLog, MqTagEnum.MONITOR_LOG, String.valueOf(tIeExamInvigilateCallLog.getId()),
+                source.name());
         mqDtoService.assembleSendOneWayMsg(mqDto);
         //监考监控通话信息 发送mq end
         return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
@@ -174,12 +186,11 @@ public class TIeInvigilateCallMobileController {
 
     @ApiOperation(value = "撤销通话申请接口")
     @RequestMapping(value = "/call/cancel", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class) })
     @Transactional
     public Result callCancel(@ApiJsonObject(name = "callCancelBackendMobile", value = {
             @ApiJsonProperty(key = "recordId", type = "long", example = "1", description = "考试记录id", required = true),
-            @ApiJsonProperty(key = "source", description = "监考视频源", required = true)
-    }) @ApiParam(value = "监控信息", required = true) @RequestBody Map<String, Object> mapParameter) {
+            @ApiJsonProperty(key = "source", description = "监考视频源", required = true) }) @ApiParam(value = "监控信息", required = true) @RequestBody Map<String, Object> mapParameter) {
         if (Objects.isNull(mapParameter.get("recordId")) || Objects.equals(mapParameter.get("recordId"), "")) {
             throw new BusinessException(ExceptionResultEnum.RECORD_ID_IS_NULL);
         }
@@ -191,7 +202,8 @@ public class TIeInvigilateCallMobileController {
         //获取考试记录缓存
         String liveUrl = null;
         ExamRecordStatusEnum statusEnum = ExamRecordCacheUtil.getStatus(recordId);
-        if (Objects.isNull(statusEnum) || Objects.equals(statusEnum, ExamRecordStatusEnum.FINISHED) || Objects.equals(statusEnum, ExamRecordStatusEnum.PERSISTED)) {
+        if (Objects.isNull(statusEnum) || Objects.equals(statusEnum, ExamRecordStatusEnum.FINISHED) || Objects
+                .equals(statusEnum, ExamRecordStatusEnum.PERSISTED)) {
             return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
         } else if (Objects.isNull(ExamRecordCacheUtil.getMonitorStatus(recordId, source))) {
             throw new BusinessException("推流状态为空");
@@ -199,10 +211,13 @@ public class TIeInvigilateCallMobileController {
         ExamRecordCacheUtil.setMonitorCallStatus(recordId, source, MonitorCallStatusSourceEnum.STOP);
         String monitorKey = ExamRecordCacheUtil.getMonitorKey(recordId);
         MonitorStatusSourceEnum status = ExamRecordCacheUtil.getMonitorStatus(recordId, source);
-        TIeExamInvigilateCallLog tIeExamInvigilateCallLog = new TIeExamInvigilateCallLog(recordId, source, liveUrl, status, monitorKey, MonitorCallStatusSourceEnum.STOP);
+        TIeExamInvigilateCallLog tIeExamInvigilateCallLog = new TIeExamInvigilateCallLog(recordId, source, liveUrl,
+                status, monitorKey, MonitorCallStatusSourceEnum.STOP);
         tIeExamInvigilateCallLog.setEndTime(System.currentTimeMillis());
         //监考监控通话信息 发送mq start
-        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.MONITOR_LOG.name(), tIeExamInvigilateCallLog, MqTagEnum.MONITOR_LOG, String.valueOf(tIeExamInvigilateCallLog.getId()), source.name());
+        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.MONITOR_LOG.name(),
+                tIeExamInvigilateCallLog, MqTagEnum.MONITOR_LOG, String.valueOf(tIeExamInvigilateCallLog.getId()),
+                source.name());
         mqDtoService.assembleSendOneWayMsg(mqDto);
         //监考监控通话信息 发送mq end
         return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
@@ -210,8 +225,10 @@ public class TIeInvigilateCallMobileController {
 
     @ApiOperation(value = "监考获取monitorKey接口")
     @RequestMapping(value = "/getMonitorKey", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "获取监考monitorKey", response = MobileAuthorizationMonitorBean.class)})
-    public Result getMonitorKey(@ApiParam(value = "考试记录id", required = true) @RequestParam Long recordId) throws NoSuchAlgorithmException {
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "获取监考monitorKey", response = MobileAuthorizationMonitorBean.class) })
+    public Result getMonitorKey(@ApiParam(value = "考试记录id", required = true) @RequestParam Long recordId)
+            throws NoSuchAlgorithmException {
         TBSession tbSession = (TBSession) ServletUtil.getRequestSession();
         String monitorKey = ExamRecordCacheUtil.getMonitorKey(recordId);
         String monitorUserId = null;
@@ -249,13 +266,20 @@ public class TIeInvigilateCallMobileController {
         if (Objects.nonNull(ec.getMonitorAudioEnable())) {
             if (ec.getMonitorAudioEnable()) {
                 for (Source s : Source.values()) {
-                    String sessionId = SessionUtil.digest(examStudentCacheBean.getIdentity(), Math.abs(Sets.newHashSet(RoleEnum.STUDENT.name()).toString().hashCode()), s.name());
+                    String sessionId = SessionUtil.digest(examStudentCacheBean.getIdentity(),
+                            Math.abs(Sets.newHashSet(RoleEnum.STUDENT.name()).toString().hashCode()), s.name());
                     TBSession tbSessionClient = (TBSession) redisUtil.getUserSession(sessionId);
-                    if (Objects.nonNull(tbSessionClient) && tbSessionClient.getExpireTime() > System.currentTimeMillis() && (Objects.equals(tbSessionClient.getSource(), Source.OE_CLIENT.name()) || Objects.equals(tbSessionClient.getSource(), Source.ADMIN_CLIENT.name())) && (Objects.equals(tbSessionClient.getPlatform(), Platform.WIN.name()) || Objects.equals(tbSessionClient.getPlatform(), Platform.MAC.name()))) {
-                        if (Objects.nonNull(ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.CLIENT_CAMERA))) {
+                    if (Objects.nonNull(tbSessionClient) && tbSessionClient.getExpireTime() > System.currentTimeMillis()
+                            && (Objects.equals(tbSessionClient.getSource(), Source.OE_CLIENT.name()) || Objects
+                            .equals(tbSessionClient.getSource(), Source.ADMIN_CLIENT.name())) && (
+                            Objects.equals(tbSessionClient.getPlatform(), Platform.WIN.name()) || Objects
+                                    .equals(tbSessionClient.getPlatform(), Platform.MAC.name()))) {
+                        if (Objects.nonNull(
+                                ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.CLIENT_CAMERA))) {
                             sourceUserId = "s_" + tbSessionClient.getId();
                             break;
-                        } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.CLIENT_SCREEN))) {
+                        } else if (Objects.nonNull(
+                                ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.CLIENT_SCREEN))) {
                             sourceUserId = "s_" + tbSessionClient.getId();
                             break;
                         }
@@ -263,13 +287,20 @@ public class TIeInvigilateCallMobileController {
                 }
             } else {
                 for (Source s : Source.values()) {
-                    String sessionId = SessionUtil.digest(examStudentCacheBean.getIdentity(), Math.abs(Sets.newHashSet(RoleEnum.STUDENT.name()).toString().hashCode()), s.name());
+                    String sessionId = SessionUtil.digest(examStudentCacheBean.getIdentity(),
+                            Math.abs(Sets.newHashSet(RoleEnum.STUDENT.name()).toString().hashCode()), s.name());
                     TBSession tbSessionPhone = (TBSession) redisUtil.getUserSession(sessionId);
-                    if (Objects.nonNull(tbSessionPhone) && tbSessionPhone.getExpireTime() > System.currentTimeMillis() && (Objects.equals(tbSessionPhone.getSource(), Source.MOBILE_FIRST.name()) || Objects.equals(tbSessionPhone.getSource(), Source.MOBILE_SECOND.name())) && (Objects.equals(tbSessionPhone.getPlatform(), Platform.ANDROID.name()) || Objects.equals(tbSessionPhone.getPlatform(), Platform.IOS.name()))) {
-                        if (Objects.nonNull(ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.MOBILE_FIRST))) {
+                    if (Objects.nonNull(tbSessionPhone) && tbSessionPhone.getExpireTime() > System.currentTimeMillis()
+                            && (Objects.equals(tbSessionPhone.getSource(), Source.MOBILE_MONITOR_FIRST.name())
+                            || Objects.equals(tbSessionPhone.getSource(), Source.MOBILE_MONITOR_SECOND.name())) && (
+                            Objects.equals(tbSessionPhone.getPlatform(), Platform.ANDROID.name()) || Objects
+                                    .equals(tbSessionPhone.getPlatform(), Platform.IOS.name()))) {
+                        if (Objects.nonNull(
+                                ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.MOBILE_FIRST))) {
                             sourceUserId = "s_" + tbSessionPhone.getId();
                             break;
-                        } else if (Objects.nonNull(ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.MOBILE_SECOND))) {
+                        } else if (Objects.nonNull(
+                                ExamRecordCacheUtil.getMonitorStatus(recordId, MonitorVideoSourceEnum.MOBILE_SECOND))) {
                             sourceUserId = "s_" + tbSessionPhone.getId();
                             break;
                         }

+ 18 - 22
themis-business/src/main/java/com/qmth/themis/business/bean/exam/QrMobileMonitorParamBean.java

@@ -2,38 +2,34 @@ package com.qmth.themis.business.bean.exam;
 
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import com.qmth.themis.common.enums.Source;
-
+import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 @ApiModel("获取移动端监考二维码参数信息")
 public class QrMobileMonitorParamBean {
 
-	
-	@ApiModelProperty("监考源")
-	private Source source;
-
-	@JsonSerialize(using = ToStringSerializer.class)
-	@ApiModelProperty("考试记录ID")
-	private Long recordId;
+    @ApiModelProperty("监考源")
+    private MonitorVideoSourceEnum source;
 
-	public Source getSource() {
-		return source;
-	}
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty("考试记录ID")
+    private Long recordId;
 
-	public void setSource(Source source) {
-		this.source = source;
-	}
+    public MonitorVideoSourceEnum getSource() {
+        return source;
+    }
 
-	public Long getRecordId() {
-		return recordId;
-	}
+    public void setSource(MonitorVideoSourceEnum source) {
+        this.source = source;
+    }
 
-	public void setRecordId(Long recordId) {
-		this.recordId = recordId;
-	}
+    public Long getRecordId() {
+        return recordId;
+    }
 
-	
+    public void setRecordId(Long recordId) {
+        this.recordId = recordId;
+    }
 
 }

+ 55 - 57
themis-business/src/main/java/com/qmth/themis/business/bean/mobile/MobileAuthorizationBean.java

@@ -3,67 +3,65 @@ package com.qmth.themis.business.bean.mobile;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import com.qmth.themis.business.enums.MobileModeEnum;
-
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 @ApiModel("登录返回信息")
 public class MobileAuthorizationBean {
 
-	@ApiModelProperty("功能模式")
-	private MobileModeEnum mode;
-	
-	@ApiModelProperty("时间戳")
-	private Long time;
-	
-	@ApiModelProperty("sessionId")
-	private String sessionId;
-
-	@JsonSerialize(using = ToStringSerializer.class)
-	@ApiModelProperty("考试记录id")
-	private Long recordId;
-	
-	private String accessToken;
-
-	public MobileModeEnum getMode() {
-		return mode;
-	}
-
-	public void setMode(MobileModeEnum mode) {
-		this.mode = mode;
-	}
-
-	public Long getTime() {
-		return time;
-	}
-
-	public void setTime(Long time) {
-		this.time = time;
-	}
-
-	public String getSessionId() {
-		return sessionId;
-	}
-
-	public void setSessionId(String sessionId) {
-		this.sessionId = sessionId;
-	}
-
-	public Long getRecordId() {
-		return recordId;
-	}
-
-	public void setRecordId(Long recordId) {
-		this.recordId = recordId;
-	}
-
-	public String getAccessToken() {
-		return accessToken;
-	}
-
-	public void setAccessToken(String accessToken) {
-		this.accessToken = accessToken;
-	}
-
-	
+    @ApiModelProperty("功能模式")
+    private MobileModeEnum mode;
+
+    @ApiModelProperty("时间戳")
+    private Long time;
+
+    @ApiModelProperty("sessionId")
+    private String sessionId;
+
+    @JsonSerialize(using = ToStringSerializer.class)
+    @ApiModelProperty("考试记录id")
+    private Long recordId;
+
+    private String accessToken;
+
+    public MobileModeEnum getMode() {
+        return mode;
+    }
+
+    public void setMode(MobileModeEnum mode) {
+        this.mode = mode;
+    }
+
+    public Long getTime() {
+        return time;
+    }
+
+    public void setTime(Long time) {
+        this.time = time;
+    }
+
+    public String getSessionId() {
+        return sessionId;
+    }
+
+    public void setSessionId(String sessionId) {
+        this.sessionId = sessionId;
+    }
+
+    public Long getRecordId() {
+        return recordId;
+    }
+
+    public void setRecordId(Long recordId) {
+        this.recordId = recordId;
+    }
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
 }

+ 52 - 54
themis-business/src/main/java/com/qmth/themis/business/bean/mobile/MobileAuthorizationMonitorBean.java

@@ -1,78 +1,76 @@
 package com.qmth.themis.business.bean.mobile;
 
-import com.qmth.themis.common.enums.Source;
-
+import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
 @ApiModel("登录返回信息")
-public class MobileAuthorizationMonitorBean  extends MobileAuthorizationBean{
+public class MobileAuthorizationMonitorBean extends MobileAuthorizationBean {
+
+    @ApiModelProperty("监控线路标识")
+    private String monitorKey;
+
+    @ApiModelProperty("当前设备代表的视频源: mobile_first|mobile_second")
+    private MonitorVideoSourceEnum monitorVideoSource;
 
-	
-	@ApiModelProperty("监控线路标识")
-	private String monitorKey;
-	
-	@ApiModelProperty("当前设备代表的视频源: mobile_first|mobile_second")
-	private Source monitorVideoSource;
+    @ApiModelProperty("是否启用当前设备的音频播放与麦克风采集")
+    private Boolean monitorAudioEnable;
 
-	@ApiModelProperty("是否启用当前设备的音频播放与麦克风采集")
-	private Boolean monitorAudioEnable;
+    @ApiModelProperty("加入房间用户ID")
+    private String monitorUserId;
 
-	@ApiModelProperty("加入房间用户ID")
-	private String monitorUserId;
+    @ApiModelProperty("用户认证签名")
+    private String monitorUserSig;
 
-	@ApiModelProperty("用户认证签名")
-	private String monitorUserSig;
+    @ApiModelProperty("腾讯云SDK APP ID")
+    private String monitorAppId;
 
-	@ApiModelProperty("腾讯云SDK APP ID")
-	private String monitorAppId;
+    public String getMonitorAppId() {
+        return monitorAppId;
+    }
 
-	public String getMonitorAppId() {
-		return monitorAppId;
-	}
+    public void setMonitorAppId(String monitorAppId) {
+        this.monitorAppId = monitorAppId;
+    }
 
-	public void setMonitorAppId(String monitorAppId) {
-		this.monitorAppId = monitorAppId;
-	}
+    public String getMonitorUserId() {
+        return monitorUserId;
+    }
 
-	public String getMonitorUserId() {
-		return monitorUserId;
-	}
+    public void setMonitorUserId(String monitorUserId) {
+        this.monitorUserId = monitorUserId;
+    }
 
-	public void setMonitorUserId(String monitorUserId) {
-		this.monitorUserId = monitorUserId;
-	}
+    public String getMonitorUserSig() {
+        return monitorUserSig;
+    }
 
-	public String getMonitorUserSig() {
-		return monitorUserSig;
-	}
+    public void setMonitorUserSig(String monitorUserSig) {
+        this.monitorUserSig = monitorUserSig;
+    }
 
-	public void setMonitorUserSig(String monitorUserSig) {
-		this.monitorUserSig = monitorUserSig;
-	}
+    public String getMonitorKey() {
+        return monitorKey;
+    }
 
-	public String getMonitorKey() {
-		return monitorKey;
-	}
+    public void setMonitorKey(String monitorKey) {
+        this.monitorKey = monitorKey;
+    }
 
-	public void setMonitorKey(String monitorKey) {
-		this.monitorKey = monitorKey;
-	}
+    public MonitorVideoSourceEnum getMonitorVideoSource() {
+        return monitorVideoSource;
+    }
 
-	public Source getMonitorVideoSource() {
-		return monitorVideoSource;
-	}
+    public void setMonitorVideoSource(MonitorVideoSourceEnum monitorVideoSource) {
+        this.monitorVideoSource = monitorVideoSource;
+    }
 
-	public void setMonitorVideoSource(Source monitorVideoSource) {
-		this.monitorVideoSource = monitorVideoSource;
-	}
+    public Boolean getMonitorAudioEnable() {
+        return monitorAudioEnable;
+    }
 
-	public Boolean getMonitorAudioEnable() {
-		return monitorAudioEnable;
-	}
+    public void setMonitorAudioEnable(Boolean monitorAudioEnable) {
+        this.monitorAudioEnable = monitorAudioEnable;
+    }
 
-	public void setMonitorAudioEnable(Boolean monitorAudioEnable) {
-		this.monitorAudioEnable = monitorAudioEnable;
-	}
-	
 }

+ 8 - 45
themis-business/src/main/java/com/qmth/themis/business/cache/MobileAuthCacheUtil.java

@@ -2,8 +2,8 @@ package com.qmth.themis.business.cache;
 
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.enums.MobileModeEnum;
+import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
 import com.qmth.themis.business.util.RedisUtil;
-import com.qmth.themis.common.enums.Source;
 
 /**
  * 移动端临时认证
@@ -13,20 +13,13 @@ import com.qmth.themis.common.enums.Source;
  * @Date: 2020-08-14
  */
 public class MobileAuthCacheUtil {
-    private static RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
 
-    public static void setSessionId(MobileModeEnum mode, String code, String sessionId) {
-        redisUtil.set(RedisKeyHelper.mobileAuthCacheKey(mode, code), "sessionId", sessionId);
-    }
+    private static RedisUtil redisUtil = SpringContextHolder.getBean(RedisUtil.class);
 
     public static void setUserType(MobileModeEnum mode, String code, String userType) {
         redisUtil.set(RedisKeyHelper.mobileAuthCacheKey(mode, code), "userType", userType);
     }
 
-    public static void setSource(MobileModeEnum mode, String code, Source source) {
-        redisUtil.set(RedisKeyHelper.mobileAuthCacheKey(mode, code), "source", source);
-    }
-
     public static void setMode(MobileModeEnum mode, String code) {
         redisUtil.set(RedisKeyHelper.mobileAuthCacheKey(mode, code), "mode", mode);
     }
@@ -75,50 +68,20 @@ public class MobileAuthCacheUtil {
         return (Integer) redisUtil.get(RedisKeyHelper.mobileAuthCacheKey(mode, code), "subIndex");
     }
 
-    public static void setMonitorKey(MobileModeEnum mode, String code, String monitorKey) {
-        redisUtil.set(RedisKeyHelper.mobileAuthCacheKey(mode, code), "monitorKey", monitorKey);
-    }
-
-    public static String getMonitorKey(MobileModeEnum mode, String code) {
-        return (String) redisUtil.get(RedisKeyHelper.mobileAuthCacheKey(mode, code), "monitorKey");
-    }
-
-    public static void setMonitorVideoSource(MobileModeEnum mode, String code, Source monitorVideoSource) {
+    public static void setMonitorVideoSource(MobileModeEnum mode, String code,
+            MonitorVideoSourceEnum monitorVideoSource) {
         redisUtil.set(RedisKeyHelper.mobileAuthCacheKey(mode, code), "monitorVideoSource", monitorVideoSource);
     }
 
-    public static Source getMonitorVideoSource(MobileModeEnum mode, String code) {
-        return (Source) redisUtil.get(RedisKeyHelper.mobileAuthCacheKey(mode, code), "monitorVideoSource");
-    }
-
-    public static void setMonitorAudioEnable(MobileModeEnum mode, String code, Boolean monitorAudioEnable) {
-        redisUtil.set(RedisKeyHelper.mobileAuthCacheKey(mode, code), "monitorAudioEnable", monitorAudioEnable);
-    }
-
-    public static Boolean getMonitorAudioEnable(MobileModeEnum mode, String code) {
-        return (Boolean) redisUtil.get(RedisKeyHelper.mobileAuthCacheKey(mode, code), "monitorAudioEnable");
-    }
-
-    public static Source getSource(MobileModeEnum mode, String code) {
-        return (Source) redisUtil.get(RedisKeyHelper.mobileAuthCacheKey(mode, code), "source");
-    }
-
-    public static String getSessionId(MobileModeEnum mode, String code) {
-        return (String) redisUtil.get(RedisKeyHelper.mobileAuthCacheKey(mode, code), "sessionId");
-    }
-
-    public static String getPlatformSource(MobileModeEnum mode, String code) {
-        return (String) redisUtil.get(RedisKeyHelper.mobileAuthCacheKey(mode, code), "platformSource");
-    }
-
-    public static void setPlatformSource(MobileModeEnum mode, String code, String source) {
-        redisUtil.set(RedisKeyHelper.mobileAuthCacheKey(mode, code), "platformSource", source);
+    public static MonitorVideoSourceEnum getMonitorVideoSource(MobileModeEnum mode, String code) {
+        return (MonitorVideoSourceEnum) redisUtil
+                .get(RedisKeyHelper.mobileAuthCacheKey(mode, code), "monitorVideoSource");
     }
 
     public static String getUserType(MobileModeEnum mode, String code) {
         return (String) redisUtil.get(RedisKeyHelper.mobileAuthCacheKey(mode, code), "userType");
     }
-    
+
     public static void setQuestionNumber(MobileModeEnum mode, String code, String questionNumber) {
         redisUtil.set(RedisKeyHelper.mobileAuthCacheKey(mode, code), "questionNumber", questionNumber);
     }

+ 165 - 59
themis-business/src/main/java/com/qmth/themis/business/constant/SystemConstant.java

@@ -1,5 +1,6 @@
 package com.qmth.themis.business.constant;
 
+import com.qmth.themis.business.dto.ExpireTimeDTO;
 import com.qmth.themis.common.contanst.Constants;
 import com.qmth.themis.common.enums.Platform;
 import com.qmth.themis.common.enums.Source;
@@ -15,110 +16,185 @@ import java.util.*;
  * @Date: 2019/10/11
  */
 public class SystemConstant {
+
     /**
      * 鉴权
      */
     public static final String ACCESS_TOKEN = "accessToken";
+
     public static final String SESSION_ID = "sessionId";
+
     public static final String ORG_INFO = "orgInfo";
+
     /**
      * 阿里云oss
      */
     public static final String END_POINT = "endpoint";
+
     public static final String ACCESS_KEY_ID = "accessKeyId";
+
     public static final String ACCESS_KEY_SECRET = "accessKeySecret";
+
     public static final String BUCKET = "bucket";
+
     public static final String URL = "url";
+
     /**
      * 腾讯云
      */
     public static final String TENCENT_APPID = "appId";
+
     public static final String TENCENT_KEY = "key";
+
     public static final long TENCENT_EXPIRE_TIME = 24 * 3600 * 30;
+
     /**
      * 系统相关
      */
     public static final String IMPORT_INIT = "准备开始处理导入数据";
+
     public static final String EXPORT_INIT = "准备开始处理导出数据";
+
     public static final String RECORD_ID = "recordId";
+
     public static final String MESSAGE = "message";
+
     public static final String ADMIN = "ADMIN";
+
     public static final String BREACH_STATUS = "breachStatus";
+
     public static final String USER = "user:";
+
     public static final String STUDENT = "student:";
+
     public static final String SESSION = "session:";
+
     public static final String ORG = "org:cache:";
+
     public static final String ROLE = "role:cache";
+
     public static final String LINK = "LINK";
+
     public static final String SYSADMIN = "系统管理员";
+
     public static final String ALL_PATH = "/**";
+
     public static final String ADMIN_ALL_PATH = "/api/admin/**";
+
     public static final String THIRD_ALL_PATH = "/api/open/**";
+
     public static final String ACCOUNT = "account";
+
     public static final String STUDENT_ACCOUNT = "student";
+
     public static final String COUNT = "count";
+
     public static final String ERROR = "/error";
+
     public static final String MQ_TOPIC_BUFFER_LIST = "mq:topic:buffer:list";
+
     public static final String MQ_DELAY_TOPIC_BUFFER_LIST = "mq:delay:topic:buffer:list";
+
     public static final String TYPE = "type";
+
     public static final String LOCAL = "local";
+
     public static final String OSS = "oss";
+
     public static final String PATH = "path";
+
     public static final String ID = "id";
+
     public static final String NAME = "name";
+
     public static final String TASK_ID = "taskId";
+
     public static final String SUCCESS = "success";
+
     public static final String MD5 = "md5";
+
     public static final String ATTACHMENT_TYPE = "attachmentType";
+
     public static final String UPLOAD_TYPE = "uploadType";
+
     public static final String DEFAULT_PASSWORD = "1jdzWuniG6UMtoa3T6uNLA==";
+
     public static final String USER_DIR = "user.dir";
+
     public static final int MAX_IMPORT_SIZE = 500;
+
     public static final int MAX_EXPORT_SIZE = 500;
+
     public static final String EXCEL_PREFIX = ".xlsx";
+
     public static final String TXT_PREFIX = ".txt";
+
     public static final String GLOBAL = "global";
+
     public static final String OK = "ok";
+
     public static String FILES_DIR;
+
     public static String TEMP_FILES_DIR;
+
     public static final String MONITOR_LIVE_URL_ = "monitorLiveUrl_";
+
     public static final String MONITOR_STATUS_ = "monitorStatus_";
+
     public static final String MONITOR_CALL_STATUS_ = "monitorCallStatus_";
+
     public final static String REDIS_MONITOR_SEQUENCE = "redis:seq:monitor";
+
     public final static String REDIS_ACTIVITY_CODE_SEQUENCE = "redis:seq:activity:code:";
 
     /**
      * session过期时间
      */
-    public static final int WEB_SESSION_EXPIRE = 1;//过期时间1天
-    public static final int WIN_SESSION_EXPIRE = 1;//过期时间1天
-    public static final int MAC_SESSION_EXPIRE = 1;//过期时间1天
-    public static final int WXAPP_SESSION_EXPIRE = 30;//过期时间30天
-    public static final int IOS_SESSION_EXPIRE = 30;//过期时间30天
-    public static final int ANDROID_SESSION_EXPIRE = 30;//过期时间30天
+    public static final int ADMIN_WEB_SESSION_EXPIRE = 1;//过期时间1天
+
+    public static final int ADMIN_CLIENT_SESSION_EXPIRE = 1;//过期时间1天
+
+    public static final int OE_CLIENT_SESSION_EXPIRE = 1;//过期时间1天
+
+    public static final int MOBILE_SESSION_EXPIRE = 30;//过期时间30天
+
     //二维码过期时间(秒)
-//    private final static int qrExpireTime = 120;
+    //    private final static int qrExpireTime = 120;
     public final static Long QR_EXPIRE_TIME = 86400L;
+
     /**
      * redis分布式锁
      */
     public static final String REDIS_LOCK_MQ_PREFIX = "lock:mq:";
+
     public static final String REDIS_LOCK_WEBSOCKET_PREFIX = "lock:websocket:";
+
     public static final String REDIS_LOCK_REEXAM_AUDITING_PREFIX = "lock:reexam:";
+
     public static final String REDIS_LOCK_EXAM_BREAK_LOGIC_PREFIX = "lock:exam:break:logic:";
+
     public static final String REDIS_LOCK_EXAM_BREAK_PREFIX = "lock:exam:break:";
+
     public static final long REDIS_LOCK_MQ_TIME_OUT = 60L;
+
     public static final long REDIS_LOCK_WEBSOCKET_TIME_OUT = 30L;
+
     public static final long REDIS_LOCK_REEXAM_TIME_OUT = 30L;
+
     public static final long REDIS_LOCK_REEXAM_EXAM_STUDENT_TIME_OUT = 30L;
+
     public static final long REDIS_CACHE_TIME_OUT = 30L;
+
     public static final long REDIS_LOCK_EXAM_BREAK_LOGIC_TIME_OUT = 60L;
+
     public static final long REDIS_LOCK_EXAM_BREAK_TIME_OUT = 60L;
 
     //学生锁
     public static final String REDIS_LOCK_STUDENT_PREFIX = "lock:student:student_id_";
+
     //考生锁
     public static final String REDIS_LOCK_EXAM_STUDENT_PREFIX = "lock:student:student_id_";
+
     //计算客观分总分锁
     public static final String REDIS_LOCK_TOTAL_OBJECTIVE_SCORE_PREFIX = "lock:total_objective_score:record_id_";
 
@@ -136,59 +212,91 @@ public class SystemConstant {
 
     //交卷锁
     public static final String REDIS_LOCK_FINISH_EXXAM_PREFIX = "lock:finish_exxam:record_id_";
+
     /**
      * redis过期时间
      */
     public static final long REDIS_EXPIRE_TIME = 60L * 1440L;//过期时间24小时
+
+    public static final long REDIS_CLIENT_EXPIRE_TIME = 60L * 43200L;//过期时间30天
+
     public static final long REDIS_PHONE_EXPIRE_TIME = 60L * 43200L;//过期时间30天
+
     public static final long REDIS_OAUTH_EXPIRE_TIME = 2 * 60L * 60L;
+
     public static final long REDIS_DEFAULT_EXPIRE_TIME = 1 * 60L * 60L;
+
     /**
      * rocket mq
      */
     public static final String MQDTO_OBJ = "mqDtoObj";
+
     public static final int CONSUME_MESSAGE_BATCH_MAX_SIZE = 10;
+
     public static final int MAXRECONSUMETIMES = 3;
+
     //    public static final String MQDTO_OBJ = "mqDtoObj";
     public static final long MESSAGE_TIMEOUT = 3000L;
+
     public static List<String> mqDelayLevelList = null;
+
     public static final String delayLevel = "1s,5s,10s,30s,1m,2m,3m,4m,5m,6m,7m,8m,9m,10m,20m,30m,1h,2h";
+
     public static Map<String, Integer> mqDelayLevel = null;
 
     public static final int DELIVERED_ACK_TYPE = 0;//消息"已发出",但尚未处理结束
+
     public static final int POSION_ACK_TYPE = 1;//消息"错误",通常表示"抛弃"此消息,比如消息重发多次后,都无法正确处理时,消息将会被删除或者DLQ(死信队列)
+
     public static final int STANDARD_ACK_TYPE = 2;//"标准"类型,通常表示为消息"处理成功",broker端可以删除消息了
+
     public static final int REDELIVERED_ACK_TYPE = 3;//消息需"重发",比如consumer处理消息时抛出了异常,broker稍后会重新发送此消息
+
     public static final int INDIVIDUAL_ACK_TYPE = 4;//表示只确认"单条消息",无论在任何ACK_MODE下
+
     public static final int UNMATCHED_ACK_TYPE = 5;//BROKER间转发消息时,接收端"拒绝"消息
+
     public static final int UNSEND_ACK_TYPE = 6;//消息未发出
+
     /**
      * 线程池配置
      */
     public static final String THREAD_POOL_NAME = "arbitrateThreadPool";
+
     public static final int THREAD_POOL_CORE_POOL_SIZE = 20;
+
     public static final int THREAD_POOL_MAX_POOL_SIZE = 40;
+
     public static final int THREAD_POOL_KEEP_ALIVE_SECONDS = 60;
+
     public static final int THREAD_POOL_QUEUE_CAPACITY = 100;
+
     /**
      * websocket
      */
     public static final String WEBSOCKET_OE_ONLINE_COUNT = "websocket:oe:online:count";
+
     public static final String WEBSOCKET_ADMIN_ONLINE_COUNT = "websocket:admin:online:count";
+
     public static final String GET = "get";
+
     public static final long WEBSOCKET_MAX_TIME_OUT = 1 * 60 * 1000;
+
     public static final String ACK_MESSAGE = "ackMessage";
+
     /**
      * 缓存配置
      */
     public static final String userOauth = "user:oauth:cache";
+
     public static final String studentOauth = "student:oauth:cache";
+
     public static final String configCache = "config:cache";
-//    /**
-//     * ehcache配置
-//     */
-//    public static final String orgCodeCache = "org_code_cache";
-//    public static final String roleCache = "role_cache";
+    //    /**
+    //     * ehcache配置
+    //     */
+    //    public static final String orgCodeCache = "org_code_cache";
+    //    public static final String roleCache = "role_cache";
 
     static {
         String[] strs = delayLevel.split(",");
@@ -205,35 +313,33 @@ public class SystemConstant {
      * @param platform
      * @return
      */
-    public static Map<String, Object> getExpireTime(Platform platform) {
-        Map<String, Object> map = new HashMap<>();
+    public static ExpireTimeDTO getExpireTime(Source source, Platform platform) {
+        ExpireTimeDTO dto = new ExpireTimeDTO();
         Date now = new Date();
         Calendar calendar = Calendar.getInstance();
         calendar.setTime(now);
-        Long redisExpire = REDIS_EXPIRE_TIME;
-        if (platform.getSource().contains(Source.ADMIN_WEB.name())) {
-            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.WEB_SESSION_EXPIRE);
-        } else if (Objects.equals(platform.name(), Platform.WIN.name()) &&
-                (platform.getSource().contains(Source.ADMIN_CLIENT.name()) || platform.getSource().contains(Source.OE_CLIENT.name()))) {
-            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.WIN_SESSION_EXPIRE);
-        } else if (Objects.equals(platform.name(), Platform.MAC.name()) &&
-                (platform.getSource().contains(Source.ADMIN_CLIENT.name()) || platform.getSource().contains(Source.OE_CLIENT.name()))) {
-            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.MAC_SESSION_EXPIRE);
-        } else if (platform.getSource().contains(Source.OE_ANSWER.name())) {
-            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.WXAPP_SESSION_EXPIRE);
-            redisExpire = REDIS_PHONE_EXPIRE_TIME;
-        } else if (Objects.equals(platform.name(), Platform.IOS.name()) &&
-                (platform.getSource().contains(Source.OE_ANSWER.name()) || platform.getSource().contains(Source.MOBILE_FIRST.name()) || platform.getSource().contains(Source.MOBILE_SECOND.name()))) {
-            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.IOS_SESSION_EXPIRE);
-            redisExpire = REDIS_PHONE_EXPIRE_TIME;
-        } else if (Objects.equals(platform.name(), Platform.ANDROID.name()) &&
-                (platform.getSource().contains(Source.OE_ANSWER.name()) || platform.getSource().contains(Source.MOBILE_FIRST.name()) || platform.getSource().contains(Source.MOBILE_SECOND.name()))) {
-            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.ANDROID_SESSION_EXPIRE);
+        long redisExpire = REDIS_EXPIRE_TIME;
+        switch (source) {
+        case ADMIN_WEB:
+            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.ADMIN_WEB_SESSION_EXPIRE);
+            break;
+        case ADMIN_CLIENT:
+            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.ADMIN_CLIENT_SESSION_EXPIRE);
+            break;
+        case OE_CLIENT:
+            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.OE_CLIENT_SESSION_EXPIRE);
+            redisExpire = REDIS_CLIENT_EXPIRE_TIME;
+            break;
+        case OE_ANSWER:
+        case MOBILE_MONITOR_FIRST:
+        case MOBILE_MONITOR_SECOND:
+            calendar.add(Calendar.DAY_OF_YEAR, SystemConstant.MOBILE_SESSION_EXPIRE);
             redisExpire = REDIS_PHONE_EXPIRE_TIME;
+            break;
         }
-        map.put("date", calendar.getTime());
-        map.put("redisExpire", redisExpire);
-        return map;
+        dto.setDate(calendar.getTime());
+        dto.setExpireSeconds(redisExpire);
+        return dto;
     }
 
     /**
@@ -247,34 +353,33 @@ public class SystemConstant {
         return diff < -1 * Constants.SIGNATURE_AHEAD_SECONDS || diff > Constants.SIGNATURE_EXPIRE_SECONDS;
     }
 
-//    /**
-//     * 毫秒时间转换
-//     *
-//     * @param map
-//     * @return
-//     */
-//    public static Map timeTransform(Map map) {
-//        if (Objects.nonNull(map) && Objects.nonNull(map.get("createTime")) && map.get("createTime") instanceof Long) {
-//            map.put("createTime", new Date((Long) map.get("createTime")));
-//        }
-//        if (Objects.nonNull(map) && Objects.nonNull(map.get("startTime")) && map.get("startTime") instanceof Long) {
-//            map.put("startTime", new Date((Long) map.get("startTime")));
-//        }
-//        if (Objects.nonNull(map) && Objects.nonNull(map.get("finishTime")) && map.get("finishTime") instanceof Long) {
-//            map.put("finishTime", new Date((Long) map.get("finishTime")));
-//        }
-//        if (Objects.nonNull(map) && Objects.nonNull(map.get("updateTime")) && map.get("updateTime") instanceof Long) {
-//            map.put("updateTime", new Date((Long) map.get("updateTime")));
-//        }
-//        return map;
-//    }
+    //    /**
+    //     * 毫秒时间转换
+    //     *
+    //     * @param map
+    //     * @return
+    //     */
+    //    public static Map timeTransform(Map map) {
+    //        if (Objects.nonNull(map) && Objects.nonNull(map.get("createTime")) && map.get("createTime") instanceof Long) {
+    //            map.put("createTime", new Date((Long) map.get("createTime")));
+    //        }
+    //        if (Objects.nonNull(map) && Objects.nonNull(map.get("startTime")) && map.get("startTime") instanceof Long) {
+    //            map.put("startTime", new Date((Long) map.get("startTime")));
+    //        }
+    //        if (Objects.nonNull(map) && Objects.nonNull(map.get("finishTime")) && map.get("finishTime") instanceof Long) {
+    //            map.put("finishTime", new Date((Long) map.get("finishTime")));
+    //        }
+    //        if (Objects.nonNull(map) && Objects.nonNull(map.get("updateTime")) && map.get("updateTime") instanceof Long) {
+    //            map.put("updateTime", new Date((Long) map.get("updateTime")));
+    //        }
+    //        return map;
+    //    }
 
     /**
      * 初始化附件文件路径
      */
     public static void initTempFiles() {
-        StringJoiner localPath = new StringJoiner("").add(
-                System.getProperty(SystemConstant.USER_DIR));
+        StringJoiner localPath = new StringJoiner("").add(System.getProperty(SystemConstant.USER_DIR));
         String mkdir = localPath.toString().substring(0, localPath.toString().lastIndexOf(File.separator));
         File dir = new File(mkdir + File.separator + "themis-files");
         if (!dir.exists()) {
@@ -305,4 +410,5 @@ public class SystemConstant {
         sec = (diff / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
         return String.format("%02d", hour) + ":" + String.format("%02d", min) + ":" + String.format("%02d", sec);
     }
+
 }

+ 26 - 0
themis-business/src/main/java/com/qmth/themis/business/dto/ExpireTimeDTO.java

@@ -0,0 +1,26 @@
+package com.qmth.themis.business.dto;
+
+import java.util.Date;
+
+public class ExpireTimeDTO {
+
+    private Date date;
+
+    private long expireSeconds;
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public long getExpireSeconds() {
+        return expireSeconds;
+    }
+
+    public void setExpireSeconds(long expireSeconds) {
+        this.expireSeconds = expireSeconds;
+    }
+}

+ 75 - 54
themis-business/src/main/java/com/qmth/themis/business/service/impl/TEMobileServiceImpl.java

@@ -8,14 +8,17 @@ import com.qmth.themis.business.bean.mobile.MobileAuthorizationUploadBean;
 import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.MobileAuthCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
+import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentAnswerCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.AuthDto;
+import com.qmth.themis.business.dto.ExpireTimeDTO;
 import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.entity.TBSession;
 import com.qmth.themis.business.enums.*;
 import com.qmth.themis.business.service.MqDtoService;
+import com.qmth.themis.business.service.TEExamService;
 import com.qmth.themis.business.service.TEExamStudentService;
 import com.qmth.themis.business.service.TEMobileService;
 import com.qmth.themis.business.util.RedisUtil;
@@ -31,8 +34,6 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.security.NoSuchAlgorithmException;
-import java.util.Date;
-import java.util.Map;
 import java.util.Objects;
 
 @Service
@@ -41,6 +42,9 @@ public class TEMobileServiceImpl implements TEMobileService {
     @Resource
     RedisUtil redisUtil;
 
+    @Resource
+    TEExamService examService;
+
     @Resource
     TEExamStudentService examStudentService;
 
@@ -55,10 +59,15 @@ public class TEMobileServiceImpl implements TEMobileService {
         MobileModeEnum mode = MobileModeEnum.valueOf(param.getMode().toUpperCase());
         String code = param.getCode();
         MobileAuthorizationBean ret = null;
+        Source source = null;
         if (MobileModeEnum.MOBILE_MONITOR.equals(mode)) {
-            ret = monitorAuthorization(mode, code);
+            MobileAuthorizationMonitorBean mb = new MobileAuthorizationMonitorBean();
+            ret = mb;
+            source = monitorAuthorization(mode, code, mb);
         } else if (MobileModeEnum.PHOTO_UPLOAD.equals(mode) || MobileModeEnum.AUDIO_UPLOAD.equals(mode)) {
-            ret = answerUploadAuthorization(mode, code);
+            MobileAuthorizationUploadBean ub = new MobileAuthorizationUploadBean();
+            ret = ub;
+            source = answerUploadAuthorization(mode, code, ub);
         }
         if (ExamRecordCacheUtil.getId(ret.getRecordId()) == null) {
             throw new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD);
@@ -77,69 +86,60 @@ public class TEMobileServiceImpl implements TEMobileService {
         AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.studentOauth + "::" + es.getStudentId());
         // 生成token
         String token = RandomStringUtils.randomAlphanumeric(32);
-        String source = MobileAuthCacheUtil.getPlatformSource(mode, code);
-        String sessionId = MobileAuthCacheUtil.getSessionId(mode, code);
-        Map<String, Object> expireMap = SystemConstant.getExpireTime(platform);
-        Date expire = (Date) expireMap.get("date");
-        Long redisExpire = Long.parseLong(String.valueOf(expireMap.get("redisExpire")));
+        String sessionId = ret.getSessionId();
+        ExpireTimeDTO expireBean = SystemConstant.getExpireTime(source, platform);
         TBSession tbSession = new TBSession(sessionId, String.valueOf(es.getStudentId()),
-                authDto.getRoleCodes().toString(), source, platform.name(), deviceId,
-                ServletUtil.getRequest().getLocalAddr(), token, expire.getTime());
-        redisUtil.setUserSession(sessionId, tbSession, redisExpire);
-        ret.setSessionId(sessionId);
+                authDto.getRoleCodes().toString(), source.name(), platform.name(), deviceId,
+                ServletUtil.getRequest().getLocalAddr(), token, expireBean.getDate().getTime());
+        redisUtil.setUserSession(sessionId, tbSession, expireBean.getExpireSeconds());
+        ret.setAccessToken(token);
         ret.setTime(System.currentTimeMillis());
         ret.setMode(mode);
         //mq发送消息start
-        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), platform.name(), tbSession, MqTagEnum.valueOf(platform.name()), tbSession.getId(), es.getIdentity());
+        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), platform.name(), tbSession,
+                MqTagEnum.valueOf(platform.name()), tbSession.getId(), es.getIdentity());
         mqDtoService.assembleSendOneWayMsg(mqDto);
-        MqDto mqDtoLog = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.STUDENT.name(), SystemOperationEnum.LOGIN, MqTagEnum.STUDENT, String.valueOf(es.getStudentId()), es.getIdentity());
+        MqDto mqDtoLog = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.STUDENT.name(),
+                SystemOperationEnum.LOGIN, MqTagEnum.STUDENT, String.valueOf(es.getStudentId()), es.getIdentity());
         mqDtoService.assembleSendOneWayMsg(mqDtoLog);
         //mq发送消息end
         //测试
-//        String test = SignatureInfo.build(SignatureType.TOKEN, sessionId, token);
-//        ret.setAccessToken(test);
-        ret.setAccessToken(token);
+        //        String test = SignatureInfo.build(SignatureType.TOKEN, sessionId, token);
+        //        ret.setAccessToken(test);
         return ret;
     }
 
-    private MobileAuthorizationBean monitorAuthorization(MobileModeEnum mode, String code) throws NoSuchAlgorithmException {
+    private Source monitorAuthorization(MobileModeEnum mode, String code, MobileAuthorizationMonitorBean ret)
+            throws NoSuchAlgorithmException {
         Long recordId = MobileAuthCacheUtil.getRecordId(mode, code);
-        String monitorKey = MobileAuthCacheUtil.getMonitorKey(mode, code);
-        Source monitorVideoSource = MobileAuthCacheUtil.getMonitorVideoSource(mode, code);
-        Boolean monitorAudioEnable = MobileAuthCacheUtil.getMonitorAudioEnable(mode, code);
+        MonitorVideoSourceEnum monitorVideoSource = MobileAuthCacheUtil.getMonitorVideoSource(mode, code);
         if (MobileAuthCacheUtil.getMode(mode, code) == null) {
             throw new BusinessException(ExceptionResultEnum.QR_CODE_EXPIRE);
         }
-        MobileAuthorizationMonitorBean ret = new MobileAuthorizationMonitorBean();
         ret.setRecordId(recordId);
         ret.setMonitorAppId(tencentYunUtil.getTencentYunDomain().getAppId());
-        ret.setMonitorKey(monitorKey);
+        ret.setMonitorKey(ExamRecordCacheUtil.getMonitorKey(recordId));
         ret.setMonitorVideoSource(monitorVideoSource);
-        ret.setMonitorAudioEnable(monitorAudioEnable);
+        ret.setMonitorAudioEnable(getMonitorAudioEnable(recordId, monitorVideoSource));
+        Source sourceEnum = getSource(monitorVideoSource);
         ExamStudentCacheBean es = examStudentService
                 .getExamStudentCacheBean(ExamRecordCacheUtil.getExamStudentId(ret.getRecordId()));
-        String source = null;
-        if (mode.equals(MobileModeEnum.MOBILE_MONITOR)) {
-            Source sourceEnum = MobileAuthCacheUtil.getSource(mode, code);
-            source = sourceEnum.name();
-        } else if (mode.equals(MobileModeEnum.PHOTO_UPLOAD) || mode.equals(MobileModeEnum.AUDIO_UPLOAD)) {
-            source = Source.OE_ANSWER.name();
-        }
         String userType = MobileAuthCacheUtil.getUserType(mode, code);
         AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.studentOauth + "::" + es.getStudentId());
-        String sessionId = SessionUtil.digest(es.getIdentity(), Math.abs(authDto.getRoleCodes().toString().hashCode()), source);
-        MobileAuthCacheUtil.setSessionId(mode, code, sessionId);
-        MobileAuthCacheUtil.setPlatformSource(mode, code, source);
+        String sessionId = SessionUtil
+                .digest(es.getStudentId(), Math.abs(authDto.getRoleCodes().toString().hashCode()), sourceEnum);
         if (Objects.nonNull(userType) && userType.contains(RoleEnum.STUDENT.name())) {
             ret.setMonitorUserId("s_" + sessionId);
         } else {
             ret.setMonitorUserId("m_" + sessionId);
         }
+        ret.setSessionId(sessionId);
         ret.setMonitorUserSig(tencentYunUtil.getSign(ret.getMonitorUserId(), SystemConstant.TENCENT_EXPIRE_TIME));
-        return ret;
+        return sourceEnum;
     }
 
-    private MobileAuthorizationBean answerUploadAuthorization(MobileModeEnum mode, String code) throws NoSuchAlgorithmException {
+    private Source answerUploadAuthorization(MobileModeEnum mode, String code, MobileAuthorizationUploadBean ret)
+            throws NoSuchAlgorithmException {
         Long recordId = MobileAuthCacheUtil.getRecordId(mode, code);
         Integer mainNumber = MobileAuthCacheUtil.getMainNumber(mode, code);
         Integer subNumber = MobileAuthCacheUtil.getSubNumber(mode, code);
@@ -150,30 +150,23 @@ public class TEMobileServiceImpl implements TEMobileService {
         }
         ExamStudentCacheBean es = examStudentService
                 .getExamStudentCacheBean(ExamRecordCacheUtil.getExamStudentId(recordId));
-        String source = null;
-        if (mode.equals(MobileModeEnum.MOBILE_MONITOR)) {
-            Source sourceEnum = MobileAuthCacheUtil.getSource(mode, code);
-            source = sourceEnum.name();
-        } else if (mode.equals(MobileModeEnum.PHOTO_UPLOAD) || mode.equals(MobileModeEnum.AUDIO_UPLOAD)) {
-            source = Source.OE_ANSWER.name();
-        }
+        Source sourceEnum = Source.OE_ANSWER;
         AuthDto authDto = (AuthDto) redisUtil.get(SystemConstant.studentOauth + "::" + es.getStudentId());
-        String sessionId = SessionUtil.digest(es.getIdentity(), Math.abs(authDto.getRoleCodes().toString().hashCode()), source);
-        MobileAuthCacheUtil.setSessionId(mode, code, sessionId);
-        MobileAuthCacheUtil.setPlatformSource(mode, code, source);
-        MobileAuthorizationUploadBean ret = new MobileAuthorizationUploadBean();
+        String sessionId = SessionUtil
+                .digest(es.getStudentId(), Math.abs(authDto.getRoleCodes().toString().hashCode()), sourceEnum);
         ret.setRecordId(recordId);
         ret.setMainNumber(mainNumber);
         ret.setSubNumber(subNumber);
         ret.setSubIndex(subIndex);
         ret.setQuestionNumber(questionNumber);
         ret.setCourseName(es.getCourseName());
-        return ret;
+        ret.setSessionId(sessionId);
+        return sourceEnum;
     }
 
     @Override
-    public MobileAnswerSubmitReponseBean answerSubmit(Long studentId, Long recordId, Integer mainNumber, Integer subNumber, Integer subIndex,
-                                                      String answer) {
+    public MobileAnswerSubmitReponseBean answerSubmit(Long studentId, Long recordId, Integer mainNumber,
+            Integer subNumber, Integer subIndex, String answer) {
         // 校验当前登录用户和参数一致性
         if (ExamRecordCacheUtil.getId(recordId) == null) {
             throw new BusinessException(ExceptionResultEnum.NOT_FOUND_EXAM_RECORD);
@@ -191,9 +184,9 @@ public class TEMobileServiceImpl implements TEMobileService {
         if (ExamRecordStatusEnum.FINISHED.equals(sta) || ExamRecordStatusEnum.PERSISTED.equals(sta)) {
             throw new BusinessException(ExceptionResultEnum.EXAM_ALREADY_FINISHED);
         }
-        ExamStudentAnswerCacheBean answerCache = (ExamStudentAnswerCacheBean) redisUtil.get(
-                RedisKeyHelper.examAnswerKey(recordId),
-                RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex));
+        ExamStudentAnswerCacheBean answerCache = (ExamStudentAnswerCacheBean) redisUtil
+                .get(RedisKeyHelper.examAnswerKey(recordId),
+                        RedisKeyHelper.examAnswerHashKey(mainNumber, subNumber, subIndex));
         if (answerCache == null) {
             answerCache = new ExamStudentAnswerCacheBean();
             answerCache.setMainNumber(mainNumber);
@@ -208,4 +201,32 @@ public class TEMobileServiceImpl implements TEMobileService {
         ret.setUpdateTime(System.currentTimeMillis());
         return ret;
     }
+
+    private Boolean getMonitorAudioEnable(Long recordId, MonitorVideoSourceEnum videoSource) {
+        Long examId = ExamRecordCacheUtil.getExamId(recordId);
+        ExamCacheBean exam = examService.getExamCacheBean(examId);
+        String monitorVideoSource = exam.getMonitorVideoSource();
+        if (!monitorVideoSource.toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_SCREEN.name())
+                && !monitorVideoSource.toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_CAMERA.name())
+                && Source.MOBILE_MONITOR_FIRST.equals(videoSource)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * 根据监控视频源判断设备访问会话来源
+     *
+     * @param videoSource
+     * @return
+     */
+    private Source getSource(MonitorVideoSourceEnum videoSource) {
+        if (videoSource == MonitorVideoSourceEnum.MOBILE_FIRST) {
+            return Source.MOBILE_MONITOR_FIRST;
+        } else if (videoSource == MonitorVideoSourceEnum.MOBILE_SECOND) {
+            return Source.MOBILE_MONITOR_SECOND;
+        }
+        return null;
+    }
 }

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

@@ -3,19 +3,14 @@ package com.qmth.themis.business.service.impl;
 import com.qmth.themis.business.bean.exam.QrMobileMonitorParamBean;
 import com.qmth.themis.business.bean.exam.QrResponseBean;
 import com.qmth.themis.business.bean.exam.QrUploadParamBean;
-import com.qmth.themis.business.cache.ExamRecordCacheUtil;
 import com.qmth.themis.business.cache.MobileAuthCacheUtil;
 import com.qmth.themis.business.cache.RedisKeyHelper;
-import com.qmth.themis.business.cache.bean.ExamCacheBean;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.enums.MobileModeEnum;
-import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
 import com.qmth.themis.business.enums.RoleEnum;
-import com.qmth.themis.business.service.TEExamService;
 import com.qmth.themis.business.service.TEQrcodeService;
 import com.qmth.themis.business.util.RedisUtil;
 import com.qmth.themis.business.util.WxappUtil;
-import com.qmth.themis.common.enums.Source;
 import org.apache.commons.lang3.time.DateUtils;
 import org.springframework.stereotype.Service;
 
@@ -29,10 +24,9 @@ import java.util.UUID;
 @Service
 public class TEQrcodeServiceImpl implements TEQrcodeService {
 
-    @Resource
-    TEExamService examService;
     @Resource
     RedisUtil redisUtil;
+
     @Resource
     WxappUtil wxappUtil;
 
@@ -44,13 +38,10 @@ public class TEQrcodeServiceImpl implements TEQrcodeService {
         Set<String> roleCodes = new HashSet<>();
         roleCodes.add(RoleEnum.STUDENT.name());
         MobileAuthCacheUtil.setUserType(mode, code, roleCodes.toString());
-        MobileAuthCacheUtil.setSource(mode, code, param.getSource());
         MobileAuthCacheUtil.setMode(mode, code);
         MobileAuthCacheUtil.setCode(mode, code);
         MobileAuthCacheUtil.setRecordId(mode, code, param.getRecordId());
-        MobileAuthCacheUtil.setMonitorKey(mode, code, ExamRecordCacheUtil.getMonitorKey(param.getRecordId()));
         MobileAuthCacheUtil.setMonitorVideoSource(mode, code, param.getSource());
-        MobileAuthCacheUtil.setMonitorAudioEnable(mode, code, getMonitorAudioEnable(param));
         Long expireTime = DateUtils.addSeconds(new Date(), SystemConstant.QR_EXPIRE_TIME.intValue()).getTime();
         redisUtil.expire(RedisKeyHelper.mobileAuthCacheKey(mode, code), SystemConstant.QR_EXPIRE_TIME.intValue());
         QrResponseBean ret = new QrResponseBean();
@@ -59,19 +50,6 @@ public class TEQrcodeServiceImpl implements TEQrcodeService {
         return ret;
     }
 
-    private Boolean getMonitorAudioEnable(QrMobileMonitorParamBean param) {
-        Long examId = ExamRecordCacheUtil.getExamId(param.getRecordId());
-        ExamCacheBean exam = examService.getExamCacheBean(examId);
-        String monitorVideoSource = exam.getMonitorVideoSource();
-        if (!monitorVideoSource.toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_SCREEN.name())
-                && !monitorVideoSource.toUpperCase().contains(MonitorVideoSourceEnum.CLIENT_CAMERA.name())
-                && Source.MOBILE_FIRST.equals(param.getSource())) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
     private String uuid() {
         return UUID.randomUUID().toString().replaceAll("-", "");
     }

+ 1 - 16
themis-common/src/main/java/com/qmth/themis/common/enums/Platform.java

@@ -2,12 +2,7 @@ package com.qmth.themis.common.enums;
 
 public enum Platform {
 
-    WEB("ADMIN_WEB"),
-    WIN("ADMIN_CLIENT,OE_CLIENT"),
-    MAC("ADMIN_CLIENT,OE_CLIENT"),
-    WXAPP("OE_ANSWER"),
-    IOS("OE_ANSWER,MOBILE_FIRST,MOBILE_SECOND"),
-    ANDROID("OE_ANSWER,MOBILE_FIRST,MOBILE_SECOND");
+    WEB, WIN, MAC, WXAPP, IOS, ANDROID;
 
     public static Platform findByName(String name) {
         if (name == null) {
@@ -21,16 +16,6 @@ public enum Platform {
         return null;
     }
 
-    private String source;
-
-    Platform(String source) {
-        this.source = source;
-    }
-
-    public String getSource() {
-        return source;
-    }
-
     public boolean equals(String name) {
         return toString().equalsIgnoreCase(name);
     }

+ 1 - 1
themis-common/src/main/java/com/qmth/themis/common/enums/Source.java

@@ -2,7 +2,7 @@ package com.qmth.themis.common.enums;
 
 public enum Source {
 
-    ADMIN_WEB, ADMIN_CLIENT, OE_CLIENT, OE_ANSWER,MOBILE_FIRST,MOBILE_SECOND;
+    ADMIN_WEB, ADMIN_CLIENT, OE_CLIENT, OE_ANSWER, MOBILE_MONITOR_FIRST, MOBILE_MONITOR_SECOND;
 
     public static Source findByName(String name) {
         if (name == null) {

+ 43 - 56
themis-exam/src/main/java/com/qmth/themis/exam/api/TEQrcodeController.java

@@ -1,26 +1,18 @@
 package com.qmth.themis.exam.api;
 
-import javax.annotation.Resource;
-
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-
 import com.qmth.themis.business.bean.exam.QrMobileMonitorParamBean;
 import com.qmth.themis.business.bean.exam.QrUploadParamBean;
 import com.qmth.themis.business.enums.MobileModeEnum;
-import com.qmth.themis.business.service.MqDtoService;
+import com.qmth.themis.business.enums.MonitorVideoSourceEnum;
 import com.qmth.themis.business.service.TEQrcodeService;
-import com.qmth.themis.common.enums.Source;
 import com.qmth.themis.common.exception.BusinessException;
 import com.qmth.themis.common.util.Result;
 import com.qmth.themis.common.util.ResultUtil;
-
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.*;
 
+import javax.annotation.Resource;
 import java.security.NoSuchAlgorithmException;
 
 @Api(tags = "二维码接口")
@@ -28,49 +20,44 @@ import java.security.NoSuchAlgorithmException;
 @RequestMapping("/${prefix.url.exam}/qrcode")
 public class TEQrcodeController {
 
-	@Resource
-	MqDtoService mqDtoService;
-
-	@Resource
-	TEQrcodeService qrcodeService;
-	
-
-	@ApiOperation(value = "获取移动端监考二维码")
-	@RequestMapping(value = "/mobile_monitor", method = RequestMethod.POST)
-	public Result mobileMonitor(@RequestBody QrMobileMonitorParamBean param) throws NoSuchAlgorithmException {
-		if (param.getRecordId() == null) {
-			throw new BusinessException("recordId不能为空");
-		}
-		if (param.getSource() == null) {
-			throw new BusinessException("source不能为空");
-		}
-		if (!Source.MOBILE_FIRST.equals(param.getSource())
-				&& !Source.MOBILE_SECOND.equals(param.getSource())) {
-			throw new BusinessException("source 错误");
-		}
-		return ResultUtil.ok(qrcodeService.mobileMonitor(param));
-	}
-
-	@ApiOperation(value = "获取移动端拍照/录音上传二维码")
-	@RequestMapping(value = "/{uploadType}", method = RequestMethod.POST)
-	public Result upload(@PathVariable String uploadType,@RequestBody QrUploadParamBean param) {
-		if (param.getRecordId() == null) {
-			throw new BusinessException("recordId不能为空");
-		}
-		if (param.getMainNumber() == null) {
-			throw new BusinessException("MainNumber不能为空");
-		}
-		if (param.getSubNumber() == null) {
-			throw new BusinessException("SubNumber不能为空");
-		}
-		if (param.getQuestionNumber() == null) {
-			throw new BusinessException("QuestionNumber不能为空");
-		}
-		MobileModeEnum mode=MobileModeEnum.valueOf(uploadType.toUpperCase());
-		if (!MobileModeEnum.PHOTO_UPLOAD.equals(mode)
-				&& !MobileModeEnum.AUDIO_UPLOAD.equals(mode)) {
-			throw new BusinessException("uploadType 错误");
-		}
-		return ResultUtil.ok(qrcodeService.upload(param,mode));
-	}
+    @Resource
+    TEQrcodeService qrcodeService;
+
+    @ApiOperation(value = "获取移动端监考二维码")
+    @RequestMapping(value = "/mobile_monitor", method = RequestMethod.POST)
+    public Result mobileMonitor(@RequestBody QrMobileMonitorParamBean param) throws NoSuchAlgorithmException {
+        if (param.getRecordId() == null) {
+            throw new BusinessException("recordId不能为空");
+        }
+        if (param.getSource() == null) {
+            throw new BusinessException("source不能为空");
+        }
+        if (MonitorVideoSourceEnum.MOBILE_FIRST != param.getSource() && MonitorVideoSourceEnum.MOBILE_SECOND != param
+                .getSource()) {
+            throw new BusinessException("source 错误");
+        }
+        return ResultUtil.ok(qrcodeService.mobileMonitor(param));
+    }
+
+    @ApiOperation(value = "获取移动端拍照/录音上传二维码")
+    @RequestMapping(value = "/{uploadType}", method = RequestMethod.POST)
+    public Result upload(@PathVariable String uploadType, @RequestBody QrUploadParamBean param) {
+        if (param.getRecordId() == null) {
+            throw new BusinessException("recordId不能为空");
+        }
+        if (param.getMainNumber() == null) {
+            throw new BusinessException("MainNumber不能为空");
+        }
+        if (param.getSubNumber() == null) {
+            throw new BusinessException("SubNumber不能为空");
+        }
+        if (param.getQuestionNumber() == null) {
+            throw new BusinessException("QuestionNumber不能为空");
+        }
+        MobileModeEnum mode = MobileModeEnum.valueOf(uploadType.toUpperCase());
+        if (!MobileModeEnum.PHOTO_UPLOAD.equals(mode) && !MobileModeEnum.AUDIO_UPLOAD.equals(mode)) {
+            throw new BusinessException("uploadType 错误");
+        }
+        return ResultUtil.ok(qrcodeService.upload(param, mode));
+    }
 }

+ 64 - 47
themis-exam/src/main/java/com/qmth/themis/exam/api/TEStudentController.java

@@ -14,6 +14,7 @@ import com.qmth.themis.business.cache.bean.ExamCourseCacheBean;
 import com.qmth.themis.business.cache.bean.ExamStudentCacheBean;
 import com.qmth.themis.business.constant.SystemConstant;
 import com.qmth.themis.business.dto.AuthDto;
+import com.qmth.themis.business.dto.ExpireTimeDTO;
 import com.qmth.themis.business.dto.MqDto;
 import com.qmth.themis.business.dto.cache.TEStudentCacheDto;
 import com.qmth.themis.business.dto.response.TEExamActivityDto;
@@ -34,8 +35,6 @@ import com.qmth.themis.common.enums.ExceptionResultEnum;
 import com.qmth.themis.common.enums.Platform;
 import com.qmth.themis.common.enums.Source;
 import com.qmth.themis.common.exception.BusinessException;
-import com.qmth.themis.common.signature.SignatureInfo;
-import com.qmth.themis.common.signature.SignatureType;
 import com.qmth.themis.common.util.AesUtil;
 import com.qmth.themis.common.util.Result;
 import com.qmth.themis.common.util.ResultUtil;
@@ -103,13 +102,13 @@ public class TEStudentController {
 
     @ApiOperation(value = "学生登录接口")
     @RequestMapping(value = "/login", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "学生信息", response = TEExamResultDto.class)})
-    public Result login(@ApiJsonObject(name = "loginStudent", value = {
-            @ApiJsonProperty(key = "identity", description = "证件号"),
-            @ApiJsonProperty(key = "password", description = "密码"),
-            @ApiJsonProperty(key = "orgId", type = "long", example = "1", description = "机构id"),
-            @ApiJsonProperty(key = "examId", type = "long", example = "1", description = "批次id")
-    }) @ApiParam(value = "学生信息", required = true) @RequestBody Map<String, Object> mapParameter) throws NoSuchAlgorithmException {
+    @ApiResponses({ @ApiResponse(code = 200, message = "学生信息", response = TEExamResultDto.class) })
+    public Result login(
+            @ApiJsonObject(name = "loginStudent", value = { @ApiJsonProperty(key = "identity", description = "证件号"),
+                    @ApiJsonProperty(key = "password", description = "密码"),
+                    @ApiJsonProperty(key = "orgId", type = "long", example = "1", description = "机构id"),
+                    @ApiJsonProperty(key = "examId", type = "long", example = "1", description = "批次id") }) @ApiParam(value = "学生信息", required = true) @RequestBody Map<String, Object> mapParameter)
+            throws NoSuchAlgorithmException {
         if (Objects.isNull(mapParameter)) {
             throw new BusinessException(ExceptionResultEnum.STUDENT_IS_NULL);
         }
@@ -128,13 +127,17 @@ public class TEStudentController {
         if (Objects.nonNull(mapParameter.get("examId"))) {
             examId = Long.parseLong(String.valueOf(mapParameter.get("examId")));
             ExamCacheBean ec = teExamService.getExamCacheBean(examId);
-            tbOrg = Objects.isNull(redisUtil.getOrg(ec.getOrgId())) ? tbOrgService.getById(ec.getOrgId()) : (TBOrg) redisUtil.getOrg(ec.getOrgId());
+            tbOrg = Objects.isNull(redisUtil.getOrg(ec.getOrgId())) ?
+                    tbOrgService.getById(ec.getOrgId()) :
+                    (TBOrg) redisUtil.getOrg(ec.getOrgId());
         }
         if (Objects.isNull(orgId) && Objects.isNull(examId)) {
             throw new BusinessException(ExceptionResultEnum.ORG_ID_OR_EXAM_ID_NOT_CHOOSE);
         }
         if (Objects.nonNull(orgId)) {
-            tbOrg = Objects.isNull(redisUtil.getOrg(orgId)) ? tbOrgService.getById(orgId) : (TBOrg) redisUtil.getOrg(orgId);
+            tbOrg = Objects.isNull(redisUtil.getOrg(orgId)) ?
+                    tbOrgService.getById(orgId) :
+                    (TBOrg) redisUtil.getOrg(orgId);
         }
         if (Objects.isNull(tbOrg)) {
             throw new BusinessException(ExceptionResultEnum.ORG_NO);
@@ -153,7 +156,8 @@ public class TEStudentController {
             throw new BusinessException(ExceptionResultEnum.STUDENT_NO);
         }
         if (StringUtils.isNotBlank(user.getBasePhotoPath())) {
-            user.setBasePhotoPath(ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + user.getBasePhotoPath());
+            user.setBasePhotoPath(
+                    ossUtil.getAliYunOssPublicDomain().getPublicUrl() + File.separator + user.getBasePhotoPath());
         }
         String loginPassword = AesUtil.decryptCs7(password, Constants.AES_RULE);
         //密码错误
@@ -166,7 +170,8 @@ public class TEStudentController {
         if (unFinishedRecordId != null) {
             WebsocketStatusEnum sta = ExamRecordCacheUtil.getClientWebsocketStatus(unFinishedRecordId);
             ExamRecordStatusEnum status = ExamRecordCacheUtil.getStatus(unFinishedRecordId);
-            if (WebsocketStatusEnum.ON_LINE.equals(sta) && (Objects.nonNull(status) && !Objects.equals(status, ExamRecordStatusEnum.FIRST_PREPARE))) {
+            if (WebsocketStatusEnum.ON_LINE.equals(sta) && (Objects.nonNull(status) && !Objects
+                    .equals(status, ExamRecordStatusEnum.FIRST_PREPARE))) {
                 throw new BusinessException(ExceptionResultEnum.STUDENT_NOT_ALLOW_LOGIN);
             }
         }
@@ -200,30 +205,33 @@ public class TEStudentController {
         }
         //添加用户缓存
         redisUtil.setStudent(teStudent.getId(), teStudentCacheDto);
-        String source = null;
-        if (Objects.equals(platform.name(), Platform.WIN.name()) || Objects.equals(platform.name(), Platform.MAC.name())) {
-            source = platform.getSource().split(",")[1];
-        } else if (Objects.equals(platform.name(), Platform.WXAPP.name()) || Objects.equals(platform.name(), Platform.WEB.name())) {
-            source = platform.getSource();
-        } else if (Objects.equals(platform.name(), Platform.IOS.name()) || Objects.equals(platform.name(), Platform.ANDROID.name())) {
-            source = platform.getSource().split(",")[2];
+        //判断会话来源
+        Source source = null;
+        if (Platform.WIN == platform || Platform.MAC == platform) {
+            source = Source.OE_CLIENT;
+        } else {
+            throw new BusinessException(ExceptionResultEnum.PLATFORM_INVALID);
         }
         //添加用户会话缓存
-        String sessionId = SessionUtil.digest(teStudent.getIdentity(), Math.abs(authDto.getRoleCodes().toString().hashCode()), source);
+        String sessionId = SessionUtil
+                .digest(teStudent.getIdentity(), Math.abs(authDto.getRoleCodes().toString().hashCode()), source);
 
-        Map<String, Object> expireMap = SystemConstant.getExpireTime(platform);
-        Date expire = (Date) expireMap.get("date");
-        Long redisExpire = Long.parseLong(String.valueOf(expireMap.get("redisExpire")));
-        TBSession tbSession = new TBSession(sessionId, String.valueOf(teStudent.getId()), authDto.getRoleCodes().toString(), source, platform.name(), deviceId, ServletUtil.getRequest().getLocalAddr(), token, expire.getTime());
-        redisUtil.setUserSession(sessionId, tbSession, redisExpire);
+        ExpireTimeDTO expireTime = SystemConstant.getExpireTime(source, platform);
+        TBSession tbSession = new TBSession(sessionId, String.valueOf(teStudent.getId()),
+                authDto.getRoleCodes().toString(), source.name(), platform.name(), deviceId,
+                ServletUtil.getRequest().getLocalAddr(), token, expireTime.getDate().getTime());
+        redisUtil.setUserSession(sessionId, tbSession, expireTime.getExpireSeconds());
         //mq发送消息start
-        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), platform.name(), tbSession, MqTagEnum.valueOf(platform.name()), tbSession.getId(), teStudent.getIdentity());
+        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), platform.name(), tbSession,
+                MqTagEnum.valueOf(platform.name()), tbSession.getId(), teStudent.getIdentity());
         mqDtoService.assembleSendOneWayMsg(mqDto);
-        MqDto mqDtoLog = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.STUDENT.name(), SystemOperationEnum.LOGIN, MqTagEnum.STUDENT, String.valueOf(teStudent.getId()), teStudent.getIdentity());
+        MqDto mqDtoLog = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.STUDENT.name(),
+                SystemOperationEnum.LOGIN, MqTagEnum.STUDENT, String.valueOf(teStudent.getId()),
+                teStudent.getIdentity());
         mqDtoService.assembleSendOneWayMsg(mqDtoLog);
         //mq发送消息end
         //测试
-//        String test = SignatureInfo.build(SignatureType.TOKEN, sessionId, token);
+        //        String test = SignatureInfo.build(SignatureType.TOKEN, sessionId, token);
         Map<String, Object> map = new HashMap<>();
         //获取未完考试
         if (Objects.isNull(ExamingDataCacheUtil.getUnFinishedRecordId(teStudent.getId()))) {
@@ -243,10 +251,13 @@ public class TEStudentController {
             Long examStudentId = ExamRecordCacheUtil.getExamStudentId(recordId);
             Long examActivityId = ExamRecordCacheUtil.getExamActivityId(recordId);
             ExamCacheBean ec = teExamService.getExamCacheBean(ecExamId);//考试缓存
-            ExamActivityCacheBean examActivityCacheBean = teExamActivityService.getExamActivityCacheBean(examActivityId);//考试场次缓存
+            ExamActivityCacheBean examActivityCacheBean = teExamActivityService
+                    .getExamActivityCacheBean(examActivityId);//考试场次缓存
             ExamStudentCacheBean examStudentCacheBean = teExamStudentService.getExamStudentCacheBean(examStudentId);
             //如果断点时间大于整体断点时间,则强制交卷
-            if (Objects.equals(status, ExamRecordStatusEnum.ANSWERING) || Objects.equals(status, ExamRecordStatusEnum.BREAK_OFF) || Objects.equals(status, ExamRecordStatusEnum.RESUME_PREPARE)) {
+            if (Objects.equals(status, ExamRecordStatusEnum.ANSWERING) || Objects
+                    .equals(status, ExamRecordStatusEnum.BREAK_OFF) || Objects
+                    .equals(status, ExamRecordStatusEnum.RESUME_PREPARE)) {
                 //只有ANSWERING状态才生成断点
                 if (Objects.equals(status, ExamRecordStatusEnum.ANSWERING)) {
                     //先生成断点,再比较
@@ -257,7 +268,8 @@ public class TEStudentController {
                 if (finished) {
                     map = this.getWaitList(teStudent.getId(), examId, orgId, map);
                 } else {
-                    ExamUnFinishBean examUnFinishBean = this.unFinishCommon(recordId, ec, examStudentCacheBean, examActivityCacheBean, examStudentId);
+                    ExamUnFinishBean examUnFinishBean = this
+                            .unFinishCommon(recordId, ec, examStudentCacheBean, examActivityCacheBean, examStudentId);
                     map.put("unFinished", examUnFinishBean);
                 }
             } else {
@@ -268,7 +280,7 @@ public class TEStudentController {
         TEConfig teConfig = teConfigService.getGlobalConfig();
         map.put(SystemConstant.ACCESS_TOKEN, token);
         map.put(SystemConstant.GLOBAL, teConfig);
-//        map.put(SystemConstant.ACCESS_TOKEN, test);
+        //        map.put(SystemConstant.ACCESS_TOKEN, test);
         map.put(SystemConstant.STUDENT_ACCOUNT, teStudent);
         map.put(SystemConstant.SESSION_ID, sessionId);
         return ResultUtil.ok(map);
@@ -276,7 +288,7 @@ public class TEStudentController {
 
     @ApiOperation(value = "登出接口")
     @RequestMapping(value = "/logout", method = RequestMethod.POST)
-    @ApiResponses({@ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class)})
+    @ApiResponses({ @ApiResponse(code = 200, message = "{\"success\":true}", response = Result.class) })
     public Result logout() throws NoSuchAlgorithmException {
         TEStudentCacheDto teStudent = (TEStudentCacheDto) ServletUtil.getRequestStudentAccount();
         TBSession tbSession = (TBSession) ServletUtil.getRequestSession();
@@ -288,7 +300,8 @@ public class TEStudentController {
         //循环检查该用户下其他平台是否存在session,不存在则删除用户缓存和鉴权缓存
         boolean delete = true;
         for (Source s : Source.values()) {
-            String sessionId = SessionUtil.digest(teStudent.getIdentity(), Math.abs(authDto.getRoleCodes().toString().hashCode()), s.name());
+            String sessionId = SessionUtil
+                    .digest(teStudent.getIdentity(), Math.abs(authDto.getRoleCodes().toString().hashCode()), s.name());
             if (Objects.nonNull(redisUtil.getUserSession(sessionId))) {
                 delete = false;
                 break;
@@ -299,7 +312,9 @@ public class TEStudentController {
             cacheService.removeStudentCache(teStudent.getId());
         }
         //mq发送消息start
-        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.STUDENT.name(), SystemOperationEnum.LOGOUT, MqTagEnum.STUDENT, String.valueOf(teStudent.getId()), teStudent.getIdentity());
+        MqDto mqDto = new MqDto(MqTopicEnum.THEMIS_TOPIC.getCode(), MqTagEnum.STUDENT.name(),
+                SystemOperationEnum.LOGOUT, MqTagEnum.STUDENT, String.valueOf(teStudent.getId()),
+                teStudent.getIdentity());
         mqDtoService.assembleSendOneWayMsg(mqDto);
         //mq发送消息end
         return ResultUtil.ok(Collections.singletonMap(SystemConstant.SUCCESS, true));
@@ -315,19 +330,21 @@ public class TEStudentController {
      * @param examStudentId
      * @return
      */
-    private ExamUnFinishBean unFinishCommon(Long recordId, ExamCacheBean ec, ExamStudentCacheBean examStudentCacheBean, ExamActivityCacheBean examActivityCacheBean, Long examStudentId) {
-        ExamCourseCacheBean examCourseCacheBean = teExamCourseService.getExamCourseCacheBean(ec.getId(), examStudentCacheBean.getCourseCode());
-        TEExamActivityDto teExamActivityDto = new TEExamActivityDto(ec, examActivityCacheBean, examStudentCacheBean, examStudentId, examCourseCacheBean
-                , ExamRecordCacheUtil.getStartTime(recordId)
-                , ExamRecordCacheUtil.getEndTime(recordId)
-                , ExamRecordCacheUtil.getOpeningSeconds(recordId)
-                , ExamRecordCacheUtil.getMinDurationSeconds(recordId)
-                , ExamRecordCacheUtil.getMaxDurationSeconds(recordId)
-                , ExamRecordCacheUtil.getForceFinish(recordId));
+    private ExamUnFinishBean unFinishCommon(Long recordId, ExamCacheBean ec, ExamStudentCacheBean examStudentCacheBean,
+            ExamActivityCacheBean examActivityCacheBean, Long examStudentId) {
+        ExamCourseCacheBean examCourseCacheBean = teExamCourseService
+                .getExamCourseCacheBean(ec.getId(), examStudentCacheBean.getCourseCode());
+        TEExamActivityDto teExamActivityDto = new TEExamActivityDto(ec, examActivityCacheBean, examStudentCacheBean,
+                examStudentId, examCourseCacheBean, ExamRecordCacheUtil.getStartTime(recordId),
+                ExamRecordCacheUtil.getEndTime(recordId), ExamRecordCacheUtil.getOpeningSeconds(recordId),
+                ExamRecordCacheUtil.getMinDurationSeconds(recordId),
+                ExamRecordCacheUtil.getMaxDurationSeconds(recordId), ExamRecordCacheUtil.getForceFinish(recordId));
         Gson gson = new Gson();
-        ExamActivityUnFinishBean examActivityUnFinishBean = gson.fromJson(gson.toJson(teExamActivityDto), ExamActivityUnFinishBean.class);
+        ExamActivityUnFinishBean examActivityUnFinishBean = gson
+                .fromJson(gson.toJson(teExamActivityDto), ExamActivityUnFinishBean.class);
         examActivityUnFinishBean.setRecordId(recordId);
-        return new ExamUnFinishBean(ec.getId(), ec.getName(), ec.getPreNotice(), ec.getPreNoticeStaySeconds(), ec.getPostNotice(), examActivityUnFinishBean);
+        return new ExamUnFinishBean(ec.getId(), ec.getName(), ec.getPreNotice(), ec.getPreNoticeStaySeconds(),
+                ec.getPostNotice(), examActivityUnFinishBean);
     }
 
     /**