|
@@ -1,11 +1,17 @@
|
|
|
package cn.com.qmth.examcloud.core.oe.student.api.controller.client;
|
|
|
|
|
|
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.JsonUtil;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.base.utils.Check;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.bean.*;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordQuestionsService;
|
|
|
-import cn.com.qmth.examcloud.support.examing.ExamQuestion;
|
|
|
-import cn.com.qmth.examcloud.support.examing.ExamRecordPaperStruct;
|
|
|
+import cn.com.qmth.examcloud.core.oe.student.service.*;
|
|
|
+import cn.com.qmth.examcloud.support.Constants;
|
|
|
+import cn.com.qmth.examcloud.support.enums.HandInExamType;
|
|
|
+import cn.com.qmth.examcloud.support.examing.*;
|
|
|
+import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
|
|
|
+import cn.com.qmth.examcloud.web.helpers.SequenceLockHelper;
|
|
|
+import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
|
import cn.com.qmth.examcloud.web.support.ControllerSupport;
|
|
|
import io.swagger.annotations.Api;
|
|
|
import io.swagger.annotations.ApiOperation;
|
|
@@ -24,52 +30,143 @@ public class ExamProcessController extends ControllerSupport {
|
|
|
@Autowired
|
|
|
private ExamRecordQuestionsService examRecordQuestionsService;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private ExamRecordPaperStructService examRecordPaperStructService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamControlService examControlService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamingSessionService examingSessionService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamRecordDataService examRecordDataService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisClient redisClient;
|
|
|
+
|
|
|
@ApiOperation(value = "开始考试")
|
|
|
@PostMapping("/startExam")
|
|
|
public StartExamInfo startExam(@RequestParam Long examStudentId) {
|
|
|
- return new StartExamInfo();
|
|
|
+ User user = getAccessUser();
|
|
|
+ String sequenceLockKey = Constants.EXAM_CONTROL_LOCK_PREFIX + user.getUserId();
|
|
|
+ StartExamInfo startExamInfo;
|
|
|
+ // 开始考试上锁,分布式锁,系统在请求结束后会,自动释放锁,无需手动解锁
|
|
|
+ SequenceLockHelper.getLock(sequenceLockKey);
|
|
|
+ Check.isNull(examStudentId, "examStudentId不能为空");
|
|
|
+
|
|
|
+ startExamInfo = examControlService.startExam(examStudentId, user, getIp(getRequest()));
|
|
|
+ return startExamInfo;
|
|
|
}
|
|
|
|
|
|
@ApiOperation(value = "开始答题")
|
|
|
@PostMapping("/startAnswer")
|
|
|
public StartAnswerInfo startAnswer(@RequestParam @ApiParam(value = "考试记录ID") Long examRecordDataId) {
|
|
|
- return new StartAnswerInfo();
|
|
|
+ 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 = "断点续考:检查正在进行中的考试")
|
|
|
@PostMapping("/checkExamInProgress")
|
|
|
public ExamProcessResultInfo checkExamInProgress() {
|
|
|
- return new ExamProcessResultInfo();
|
|
|
+ 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(), getIp(getRequest()));
|
|
|
+ res.setCode(Constants.COMMON_SUCCESS_CODE);
|
|
|
+ res.setData(info);
|
|
|
+ return res;
|
|
|
+ } catch (StatusException e) {
|
|
|
+ if (e.getCode().equals(Constants.EXAM_RECORD_NOT_END_STATUS_CODE)) {
|
|
|
+ res.setCode(Constants.PROCESSING_EXAM_RECORD_CODE);
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@ApiOperation(value = "考试心跳")
|
|
|
@PostMapping("/examHeartbeat")
|
|
|
public Long examHeartbeat(HttpServletRequest request) {
|
|
|
- return null;
|
|
|
+ User user = getAccessUser();
|
|
|
+ return examControlService.examHeartbeat(user, getIp(request));
|
|
|
}
|
|
|
|
|
|
@ApiOperation(value = "结束考试:交卷")
|
|
|
@PostMapping("/endExam")
|
|
|
public void endExam(HttpServletRequest request) {
|
|
|
-
|
|
|
+ User user = getAccessUser();
|
|
|
+ Long studentId = user.getUserId();
|
|
|
+ String sequenceLockKey = Constants.EXAM_CONTROL_LOCK_PREFIX + user.getUserId();
|
|
|
+ //系统在请求结束后会,自动释放锁,无需手动解锁
|
|
|
+ SequenceLockHelper.getLock(sequenceLockKey);
|
|
|
+
|
|
|
+ long st = System.currentTimeMillis();
|
|
|
+ long startTime = System.currentTimeMillis();
|
|
|
+
|
|
|
+ ExamingSession examingSession = examingSessionService.getExamingSession(studentId);
|
|
|
+
|
|
|
+ if (examingSession == null) {
|
|
|
+ throw new StatusException("8010", "无效的会话,请离开考试");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (LOGGER.isDebugEnabled()) {
|
|
|
+ LOGGER.debug("0 [END_EXAM] 交卷前处理耗时:" + (System.currentTimeMillis() - startTime) + " ms");
|
|
|
+ }
|
|
|
+ examControlService.handInExam(examingSession.getExamRecordDataId(), HandInExamType.MANUAL, getIp(request));
|
|
|
+ if (LOGGER.isDebugEnabled()) {
|
|
|
+ LOGGER.debug("1 [END_EXAM]合计 耗时:" + (System.currentTimeMillis() - st) + " ms");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@ApiOperation(value = "获取考试记录信息")
|
|
|
@PostMapping("/getEndExamInfo")
|
|
|
public EndExamInfo getEndExamInfo(@RequestParam Long examRecordDataId) {
|
|
|
- return new EndExamInfo();
|
|
|
+ return examControlService.getEndExamInfo(examRecordDataId);
|
|
|
}
|
|
|
|
|
|
@ApiOperation(value = "获取考试记录试卷结构")
|
|
|
@PostMapping("/getExamRecordPaperStruct")
|
|
|
public ExamRecordPaperStruct getExamRecordPaperStruct(@RequestParam Long examRecordDataId) {
|
|
|
- return null;
|
|
|
+ Check.isNull(examRecordDataId, "examRecordDataId不能为空");
|
|
|
+ return examRecordPaperStructService.getExamRecordPaperStruct(examRecordDataId);
|
|
|
}
|
|
|
|
|
|
@ApiOperation(value = "考试过程中-获取试题列表")
|
|
|
@PostMapping("/findExamQuestionList")
|
|
|
public List<ExamQuestion> findExamQuestionList() {
|
|
|
- return null;
|
|
|
+ User user = getAccessUser();
|
|
|
+ ExamingSession examSessionInfo = examingSessionService.getExamingSession(user.getUserId());
|
|
|
+ if (examSessionInfo == null
|
|
|
+ || examSessionInfo.getExamingStatus().equals(ExamingStatus.INFORMAL)) {
|
|
|
+ throw new StatusException("1001", "考试会话已过期,请重新开考");
|
|
|
+ }
|
|
|
+
|
|
|
+ String examingHeartbeatKey = RedisKeyHelper.getBuilder().examingHeartbeatKey(examSessionInfo.getExamRecordDataId());
|
|
|
+ ExamingHeartbeat examingHeartbeat = redisClient.get(examingHeartbeatKey, ExamingHeartbeat.class);
|
|
|
+
|
|
|
+ if (null != examingHeartbeat
|
|
|
+ && examingHeartbeat.getCost() >= examSessionInfo.getExamDuration()) {
|
|
|
+ throw new StatusException("1001", "考试会话已过期,请重新开考");
|
|
|
+ }
|
|
|
+
|
|
|
+ ExamRecordQuestions qers = examRecordQuestionsService.getExamRecordQuestions(examSessionInfo.getExamRecordDataId());
|
|
|
+ List<ExamQuestion> examQuestionList = qers.getExamQuestions();
|
|
|
+ for (ExamQuestion examQuestion : examQuestionList) {
|
|
|
+ examQuestion.setCorrectAnswer(null);
|
|
|
+ examQuestion.setStudentScore(null);
|
|
|
+ }
|
|
|
+ return examQuestionList;
|
|
|
}
|
|
|
|
|
|
@ApiOperation(value = "考试过程中-获取试题内容")
|
|
@@ -84,6 +181,21 @@ public class ExamProcessController extends ControllerSupport {
|
|
|
@PostMapping("/submitQuestionAnswer")
|
|
|
public void submitQuestionAnswer(@RequestBody List<ExamStudentQuestionInfo> examQuestionInfos,
|
|
|
HttpServletRequest request) {
|
|
|
+ if (LOGGER.isDebugEnabled()) {
|
|
|
+ String strJosn = JsonUtil.toJson(examQuestionInfos);
|
|
|
+ LOGGER.debug("ExamQuestionController--submitQuestionAnswer参数信息:" + strJosn);
|
|
|
+ }
|
|
|
+ User user = getAccessUser();
|
|
|
+ if (examQuestionInfos != null && examQuestionInfos.size() > 0) {
|
|
|
+ for (ExamStudentQuestionInfo examStudentQuestionInfo : examQuestionInfos) {
|
|
|
+ if (examStudentQuestionInfo.getOrder() == null) {
|
|
|
+ throw new StatusException("2001", "illegal params");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String referer = request.getHeader("REFERER");
|
|
|
+ String agent = request.getHeader("USER-AGENT");
|
|
|
+ examRecordQuestionsService.submitQuestionAnswer(user.getUserId(), examQuestionInfos, referer, agent);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@ApiOperation(value = "保存活体检测结果")
|
|
@@ -95,7 +207,7 @@ public class ExamProcessController extends ControllerSupport {
|
|
|
@ApiOperation(value = "获取课程名称")
|
|
|
@PostMapping("/courseName/{id}")
|
|
|
public String courseName(@PathVariable Long id) {
|
|
|
- return null;
|
|
|
+ return examRecordDataService.findCourseNameById(id);
|
|
|
}
|
|
|
|
|
|
}
|