|
@@ -1,47 +1,10 @@
|
|
|
package cn.com.qmth.examcloud.core.oe.student.api.controller;
|
|
|
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.concurrent.TimeUnit;
|
|
|
-
|
|
|
-import javax.validation.Valid;
|
|
|
-
|
|
|
-import org.apache.commons.lang.math.RandomUtils;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.web.bind.annotation.GetMapping;
|
|
|
-import org.springframework.web.bind.annotation.ModelAttribute;
|
|
|
-import org.springframework.web.bind.annotation.PostMapping;
|
|
|
-import org.springframework.web.bind.annotation.RequestBody;
|
|
|
-import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
-import org.springframework.web.bind.annotation.RequestParam;
|
|
|
-import org.springframework.web.bind.annotation.RestController;
|
|
|
-
|
|
|
-import com.google.common.collect.Maps;
|
|
|
-import com.mysql.cj.util.StringUtils;
|
|
|
-
|
|
|
import cn.com.qmth.examcloud.api.commons.security.bean.User;
|
|
|
import cn.com.qmth.examcloud.commons.exception.StatusException;
|
|
|
import cn.com.qmth.examcloud.commons.util.Util;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.base.utils.Check;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.BatchGetUpyunSignDomain;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.BatchGetUpyunSignDomainQuery;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.CheckExamInProgressInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.CheckQrCodeInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.EndExamInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.ExamProcessResultInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.GetAliyunSignDomain;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.GetQrCodeReq;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.GetUploadedFileAcknowledgeStatusReq;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.GetUpyunSignDomain;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.GetUpyunSignDomainQuery;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.GetYunSignDomain;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.GetYunSignDomainQuery;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.GetYunSignatureReq;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.SaveUploadedFileAcknowledgeStatusReq;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.SaveUploadedFileReq;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.StartExamInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.UpyunSignatureInfo;
|
|
|
+import cn.com.qmth.examcloud.core.oe.student.bean.*;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.service.ExamControlService;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.service.ExamFileAnswerService;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordDataService;
|
|
@@ -64,8 +27,21 @@ import cn.com.qmth.examcloud.web.support.ControllerSupport;
|
|
|
import cn.com.qmth.examcloud.web.support.Naked;
|
|
|
import cn.com.qmth.examcloud.web.upyun.UpyunPathEnvironmentInfo;
|
|
|
import cn.com.qmth.examcloud.web.upyun.UpyunService;
|
|
|
+import com.google.common.collect.Maps;
|
|
|
+import com.mysql.cj.util.StringUtils;
|
|
|
import io.swagger.annotations.Api;
|
|
|
import io.swagger.annotations.ApiOperation;
|
|
|
+import io.swagger.annotations.ApiParam;
|
|
|
+import org.apache.commons.lang.math.RandomUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import javax.validation.Valid;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
@Api(tags = "在线考试控制")
|
|
|
@RestController
|
|
@@ -89,13 +65,13 @@ public class ExamControlController extends ControllerSupport {
|
|
|
private RedisClient redisClient;
|
|
|
@Autowired
|
|
|
private ExamRecordDataService examRecordDataService;
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* 开始考试
|
|
|
*/
|
|
|
@ApiOperation(value = "开始考试")
|
|
|
@GetMapping("/startExam")
|
|
|
- public StartExamInfo startExam(@RequestParam Long examStudentId) {
|
|
|
+ public StartExamInfo startExam(@RequestParam Long examStudentId, HttpServletRequest request) {
|
|
|
User user = getAccessUser();
|
|
|
String sequenceLockKey = Constants.EXAM_CONTROL_LOCK_PREFIX + user.getUserId();
|
|
|
StartExamInfo startExamInfo;
|
|
@@ -103,23 +79,39 @@ public class ExamControlController extends ControllerSupport {
|
|
|
SequenceLockHelper.getLock(sequenceLockKey);
|
|
|
Check.isNull(examStudentId, "examStudentId不能为空");
|
|
|
|
|
|
- startExamInfo = examControlService.startExam(examStudentId, user);
|
|
|
+ startExamInfo = examControlService.startExam(examStudentId, user, getIp(request));
|
|
|
return startExamInfo;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 开始答题
|
|
|
+ */
|
|
|
+ @ApiOperation(value = "开始答题")
|
|
|
+ @PostMapping("/startAnswer")
|
|
|
+ public StartAnswerInfo startAnswer(@RequestParam @ApiParam(value = "考试记录id") Long examRecordDataId) {
|
|
|
+ User user = getAccessUser();
|
|
|
+ String sequenceLockKey = Constants.EXAM_CONTROL_LOCK_PREFIX + user.getUserId();
|
|
|
+ // 开始考试上锁,分布式锁,系统在请求结束后会,自动释放锁,无需手动解锁
|
|
|
+ SequenceLockHelper.getLock(sequenceLockKey);
|
|
|
+ Check.isNull(examRecordDataId, "examRecordDataId不能为空");
|
|
|
+
|
|
|
+ return examControlService.startAnswer(examRecordDataId);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 断点续考:检查正在进行中的考试
|
|
|
*/
|
|
|
@ApiOperation(value = "断点续考:检查正在进行中的考试")
|
|
|
@GetMapping("/checkExamInProgress")
|
|
|
- public ExamProcessResultInfo checkExamInProgress() {
|
|
|
+ public ExamProcessResultInfo checkExamInProgress(HttpServletRequest request) {
|
|
|
User user = getAccessUser();
|
|
|
String sequenceLockKey = Constants.EXAM_CONTROL_LOCK_PREFIX + user.getUserId();
|
|
|
// 系统在请求结束后会,自动释放锁,无需手动解锁
|
|
|
SequenceLockHelper.getLock(sequenceLockKey);
|
|
|
ExamProcessResultInfo res = new ExamProcessResultInfo();
|
|
|
try {
|
|
|
- CheckExamInProgressInfo info = examControlService.checkExamInProgress(user.getUserId());
|
|
|
+ CheckExamInProgressInfo info = examControlService.checkExamInProgress(user.getUserId(),getIp(request));
|
|
|
res.setCode(Constants.COMMON_SUCCESS_CODE);
|
|
|
res.setData(info);
|
|
|
return res;
|
|
@@ -141,9 +133,9 @@ public class ExamControlController extends ControllerSupport {
|
|
|
*/
|
|
|
@ApiOperation(value = "考试心跳")
|
|
|
@GetMapping("/examHeartbeat")
|
|
|
- public Long examHeartbeat() {
|
|
|
+ public Long examHeartbeat(HttpServletRequest request) {
|
|
|
User user = getAccessUser();
|
|
|
- return examControlService.examHeartbeat(user);
|
|
|
+ return examControlService.examHeartbeat(user, getIp(request));
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -151,7 +143,7 @@ public class ExamControlController extends ControllerSupport {
|
|
|
*/
|
|
|
@ApiOperation(value = "结束考试:交卷")
|
|
|
@GetMapping("/endExam")
|
|
|
- public void endExam() {
|
|
|
+ public void endExam(HttpServletRequest request) {
|
|
|
User user = getAccessUser();
|
|
|
Long studentId = user.getUserId();
|
|
|
String sequenceLockKey = Constants.EXAM_CONTROL_LOCK_PREFIX + user.getUserId();
|
|
@@ -162,15 +154,15 @@ public class ExamControlController extends ControllerSupport {
|
|
|
long startTime = System.currentTimeMillis();
|
|
|
|
|
|
ExamingSession examingSession = examingSessionService.getExamingSession(studentId);
|
|
|
-
|
|
|
- if(examingSession==null) {
|
|
|
- throw new StatusException("8010", "无效的会话,请离开考试");
|
|
|
+
|
|
|
+ if (examingSession == null) {
|
|
|
+ throw new StatusException("8010", "无效的会话,请离开考试");
|
|
|
}
|
|
|
|
|
|
if (log.isDebugEnabled()) {
|
|
|
log.debug("0 [END_EXAM] 交卷前处理耗时:" + (System.currentTimeMillis() - startTime) + " ms");
|
|
|
}
|
|
|
- examControlService.handInExam(examingSession.getExamRecordDataId(), HandInExamType.MANUAL);
|
|
|
+ examControlService.handInExam(examingSession.getExamRecordDataId(), HandInExamType.MANUAL,getIp(request));
|
|
|
if (log.isDebugEnabled()) {
|
|
|
log.debug("1 [END_EXAM]合计 耗时:" + (System.currentTimeMillis() - st) + " ms");
|
|
|
}
|
|
@@ -196,35 +188,36 @@ public class ExamControlController extends ControllerSupport {
|
|
|
public UpyunSignatureInfo getUpyunSignature(@ModelAttribute @Valid GetYunSignatureReq req) {
|
|
|
return examControlService.getUpyunSignature(req);
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
* 获取云存储上传签名(微信小程序调用)
|
|
|
*/
|
|
|
@ApiOperation(value = "获取文件上传签名(微信小程序调用)")
|
|
|
@PostMapping("/yunSignature")
|
|
|
public GetYunSignDomain getYunSignature(@ModelAttribute @Valid GetYunSignatureReq req) {
|
|
|
-
|
|
|
- if(FileStorageType.UPYUN.equals(FileStorageUtil.getFileStorageType())) {
|
|
|
- GetUpyunSignDomain result = new GetUpyunSignDomain();
|
|
|
- Map<String, String> params = Maps.newHashMap();
|
|
|
- UpyunSignatureInfo info=examControlService.getUpyunSignature(req);
|
|
|
- String signIdentifier = String.valueOf(System.currentTimeMillis());
|
|
|
- params.put("authorization", info.getSignature());
|
|
|
- params.put("policy", info.getPolicy());
|
|
|
- result.setAccessUrl(FileStorageHelper.getUrl(info.getUpyunFileDomain(), info.getFilePath()));
|
|
|
+
|
|
|
+ if (FileStorageType.UPYUN.equals(FileStorageUtil.getFileStorageType())) {
|
|
|
+ GetUpyunSignDomain result = new GetUpyunSignDomain();
|
|
|
+ Map<String, String> params = Maps.newHashMap();
|
|
|
+ UpyunSignatureInfo info = examControlService.getUpyunSignature(req);
|
|
|
+ String signIdentifier = String.valueOf(System.currentTimeMillis());
|
|
|
+ params.put("authorization", info.getSignature());
|
|
|
+ params.put("policy", info.getPolicy());
|
|
|
+ result.setAccessUrl(FileStorageHelper.getUrl(info.getUpyunFileDomain(), info.getFilePath()));
|
|
|
result.setFormUrl(info.getUploadUrl());
|
|
|
result.setFormParams(params);
|
|
|
result.setSignIdentifier(signIdentifier);
|
|
|
- return result;
|
|
|
+ return result;
|
|
|
}
|
|
|
- if(FileStorageType.ALIYUN.equals(FileStorageUtil.getFileStorageType())) {
|
|
|
- String fileSuffix = req.getFileSuffix();
|
|
|
+ if (FileStorageType.ALIYUN.equals(FileStorageUtil.getFileStorageType())) {
|
|
|
+ String fileSuffix = req.getFileSuffix();
|
|
|
if (StringUtils.isNullOrEmpty(fileSuffix)) {
|
|
|
throw new StatusException("5002", "文件后缀名不允许为空");
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
ExamRecordData examRecordData = examRecordDataService.getExamRecordDataCache(req.getExamRecordDataId());
|
|
|
fileSuffix = fileSuffix.indexOf(".") == -1 ? "." + fileSuffix : fileSuffix;
|
|
|
-
|
|
|
+
|
|
|
StringBuffer filePath = new StringBuffer();
|
|
|
|
|
|
filePath.append(OE_ANSWER_FILE_PATH).append(SEPARATOR)
|
|
@@ -243,7 +236,7 @@ public class ExamControlController extends ControllerSupport {
|
|
|
String signIdentifier = String.valueOf(System.currentTimeMillis());
|
|
|
FileStoragePathEnvInfo env = new FileStoragePathEnvInfo();
|
|
|
env.setRelativePath(filePath.toString());
|
|
|
- YunHttpRequest aliYunHttpRequest = FileStorageUtil.getSignature(FileStorageType.ALIYUN,Constants.MINI_PROGRAM_ANWSER_SITEID, env, req.getFileMd5());
|
|
|
+ YunHttpRequest aliYunHttpRequest = FileStorageUtil.getSignature(FileStorageType.ALIYUN, Constants.MINI_PROGRAM_ANWSER_SITEID, env, req.getFileMd5());
|
|
|
result.setAccessUrl(aliYunHttpRequest.getAccessUrl());
|
|
|
result.setFormUrl(aliYunHttpRequest.getFormUrl());
|
|
|
result.setFormParams(aliYunHttpRequest.getFormParams());
|
|
@@ -284,7 +277,7 @@ public class ExamControlController extends ControllerSupport {
|
|
|
String fileUrl = "";
|
|
|
if (req.getFilePath().indexOf(",") > -1) {
|
|
|
for (String url : req.getFilePath().split(",")) {
|
|
|
- fileUrl += FileStorageUtil.realPath(url)+ ",";
|
|
|
+ fileUrl += FileStorageUtil.realPath(url) + ",";
|
|
|
}
|
|
|
fileUrl = fileUrl.substring(0, fileUrl.length() - 1);
|
|
|
} else {
|
|
@@ -336,10 +329,10 @@ public class ExamControlController extends ControllerSupport {
|
|
|
public GetUpyunSignDomain getCapturePhotoUpYunSign(GetYunSignDomainQuery query) {
|
|
|
return getUpYunSign(query);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//又拍云签名
|
|
|
private GetUpyunSignDomain getUpYunSign(GetYunSignDomainQuery query) {
|
|
|
- String fileSuffix = query.getFileSuffix();
|
|
|
+ String fileSuffix = query.getFileSuffix();
|
|
|
if (StringUtils.isNullOrEmpty(fileSuffix)) {
|
|
|
throw new StatusException("200001", "文件后缀名不允许为空");
|
|
|
}
|
|
@@ -363,22 +356,22 @@ public class ExamControlController extends ControllerSupport {
|
|
|
result.setSignIdentifier(signIdentifier);
|
|
|
return result;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
@ApiOperation(value = "获取抓拍照片的云存储签名")
|
|
|
@GetMapping("/getCapturePhotoYunSign")
|
|
|
public GetYunSignDomain getCapturePhotoYunSign(GetYunSignDomainQuery query) {
|
|
|
- if(FileStorageType.UPYUN.equals(FileStorageUtil.getFileStorageType())) {
|
|
|
- return getUpYunSign(query);
|
|
|
+ if (FileStorageType.UPYUN.equals(FileStorageUtil.getFileStorageType())) {
|
|
|
+ return getUpYunSign(query);
|
|
|
}
|
|
|
- if(FileStorageType.ALIYUN.equals(FileStorageUtil.getFileStorageType())) {
|
|
|
- return getAliYunSign(query);
|
|
|
+ if (FileStorageType.ALIYUN.equals(FileStorageUtil.getFileStorageType())) {
|
|
|
+ return getAliYunSign(query);
|
|
|
}
|
|
|
throw new StatusException("3002", "未配置正确云存储类型");
|
|
|
}
|
|
|
|
|
|
//阿里云签名
|
|
|
private GetAliyunSignDomain getAliYunSign(GetYunSignDomainQuery query) {
|
|
|
- String fileSuffix = query.getFileSuffix();
|
|
|
+ String fileSuffix = query.getFileSuffix();
|
|
|
if (StringUtils.isNullOrEmpty(fileSuffix)) {
|
|
|
throw new StatusException("4001", "文件后缀名不允许为空");
|
|
|
}
|
|
@@ -393,7 +386,7 @@ public class ExamControlController extends ControllerSupport {
|
|
|
env.setRootOrgId(accessUser.getRootOrgId().toString());
|
|
|
env.setUserId(accessUser.getUserId().toString());
|
|
|
env.setFileSuffix(fileSuffix);
|
|
|
- YunHttpRequest aliYunHttpRequest = FileStorageUtil.getSignature(FileStorageType.ALIYUN,Constants.CAPTURE_PHOTO_UPYUN_SITEID, env, query.getFileMd5());
|
|
|
+ YunHttpRequest aliYunHttpRequest = FileStorageUtil.getSignature(FileStorageType.ALIYUN, Constants.CAPTURE_PHOTO_UPYUN_SITEID, env, query.getFileMd5());
|
|
|
redisClient.set(aliyunSignRedisKey, aliYunHttpRequest, 60);
|
|
|
result.setAccessUrl(aliYunHttpRequest.getAccessUrl());
|
|
|
result.setFormUrl(aliYunHttpRequest.getFormUrl());
|
|
@@ -447,4 +440,19 @@ public class ExamControlController extends ControllerSupport {
|
|
|
public String getQrCode(@RequestBody GetQrCodeReq req) {
|
|
|
return examControlService.getQrCode(req, getAccessUser());
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 记录切换屏幕
|
|
|
+ */
|
|
|
+ @ApiOperation(value = "记录切换屏幕次数")
|
|
|
+ @PostMapping("/switchScreen")
|
|
|
+ public void switchScreen(@RequestParam @ApiParam(value = "考试记录id") Long examRecordDataId) {
|
|
|
+ User user = getAccessUser();
|
|
|
+ String sequenceLockKey = Constants.EXAM_CONTROL_LOCK_PREFIX + user.getUserId();
|
|
|
+ // 开始考试上锁,分布式锁,系统在请求结束后会,自动释放锁,无需手动解锁
|
|
|
+ SequenceLockHelper.getLock(sequenceLockKey);
|
|
|
+ Check.isNull(examRecordDataId, "examRecordDataId不能为空");
|
|
|
+
|
|
|
+ examControlService.switchScreen(examRecordDataId);
|
|
|
+ }
|
|
|
}
|