|
@@ -0,0 +1,172 @@
|
|
|
+package cn.com.qmth.examcloud.core.oe.task.controller;
|
|
|
+
|
|
|
+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.UrlUtil;
|
|
|
+import cn.com.qmth.examcloud.core.oe.task.controller.bean.GetExamCaptureResultDomain;
|
|
|
+import cn.com.qmth.examcloud.core.oe.task.dao.entity.ExamCaptureEntity;
|
|
|
+import cn.com.qmth.examcloud.core.oe.task.service.ExamCaptureQueueService;
|
|
|
+import cn.com.qmth.examcloud.core.oe.task.service.ExamCaptureService;
|
|
|
+import cn.com.qmth.examcloud.core.oe.task.service.ExamingSessionService;
|
|
|
+import cn.com.qmth.examcloud.core.oe.task.service.bean.CompareFaceSyncInfo;
|
|
|
+import cn.com.qmth.examcloud.core.oe.task.service.bean.SaveExamCaptureQueueInfo;
|
|
|
+import cn.com.qmth.examcloud.support.Constants;
|
|
|
+import cn.com.qmth.examcloud.support.cache.CacheHelper;
|
|
|
+import cn.com.qmth.examcloud.support.cache.bean.StudentCacheBean;
|
|
|
+import cn.com.qmth.examcloud.support.examing.ExamingSession;
|
|
|
+import cn.com.qmth.examcloud.support.examing.ExamingStatus;
|
|
|
+import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
|
+import cn.com.qmth.examcloud.web.support.ControllerSupport;
|
|
|
+import cn.com.qmth.examcloud.web.upyun.UpYunHttpRequest;
|
|
|
+import io.swagger.annotations.Api;
|
|
|
+import io.swagger.annotations.ApiOperation;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.json.JSONArray;
|
|
|
+import org.json.JSONException;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author chenken
|
|
|
+ * @date 2018年9月6日 上午10:14:23
|
|
|
+ * @company QMTH
|
|
|
+ * @description ExamCaptureController.java
|
|
|
+ */
|
|
|
+@Api(tags = "考试抓拍")
|
|
|
+@RestController
|
|
|
+@RequestMapping("${app.api.oe.student.face}/examCaptureQueue")
|
|
|
+public class ExamCaptureController extends ControllerSupport {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamCaptureService examCaptureService;
|
|
|
+ @Autowired
|
|
|
+ private ExamingSessionService examingSessionService;
|
|
|
+ @Autowired
|
|
|
+ private ExamCaptureQueueService examCaptureQueueService;
|
|
|
+ @Autowired
|
|
|
+ private RedisTemplate<String,Object> redisTemplate;
|
|
|
+ @Autowired
|
|
|
+ RedisClient redisClient;
|
|
|
+
|
|
|
+// private static AES aes = new AES();
|
|
|
+
|
|
|
+ @ApiOperation(value = "同步比较人脸:用于进入考试")
|
|
|
+ @PostMapping("/compareFaceSync")
|
|
|
+ public CompareFaceSyncInfo compareFaceSync(@RequestParam String fileUrl, @RequestParam(required = false) String signIdentifier) {
|
|
|
+ Long startTime = System.currentTimeMillis();
|
|
|
+ User user = getAccessUser();
|
|
|
+ if (StringUtils.isBlank(fileUrl)) {
|
|
|
+ throw new StatusException("301001", "文件Url不能为空");
|
|
|
+ }
|
|
|
+ validateUpyunSign(signIdentifier, fileUrl, user.getUserId());
|
|
|
+
|
|
|
+ StudentCacheBean studentCache = CacheHelper.getStudent(user.getUserId());
|
|
|
+ String baseFaceToken = studentCache.getFaceToken();
|
|
|
+ if (StringUtils.isBlank(baseFaceToken)) {
|
|
|
+ throw new StatusException("301002", "学生底照的faceToken为空");
|
|
|
+ }
|
|
|
+// fileUrl = aes.decrypt(fileUrl);
|
|
|
+ fileUrl = UrlUtil.decode(fileUrl);
|
|
|
+ CompareFaceSyncInfo compareFaceSyncInfo = examCaptureService.compareFaceSyncByFileUrl(user.getUserId(), baseFaceToken, fileUrl);
|
|
|
+
|
|
|
+ //将人脸同步比较的结果临时存储到redis中.开考后会清除
|
|
|
+ String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
|
|
|
+ compareFaceSyncInfo.setFileName(fileName);
|
|
|
+ compareFaceSyncInfo.setFileUrl(fileUrl);
|
|
|
+ compareFaceSyncInfo.setProcessTime(System.currentTimeMillis() - startTime);
|
|
|
+
|
|
|
+ redisClient.set(Constants.FACE_SYNC_COMPARE_RESULT_PREFIX + user.getUserId(), compareFaceSyncInfo, 5 * 60);
|
|
|
+ return compareFaceSyncInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验又拍云签名
|
|
|
+ *
|
|
|
+ * @param signIdentifier 签名标识
|
|
|
+ * @param fileUrl 文件路径
|
|
|
+ * @param userId 用户id
|
|
|
+ */
|
|
|
+ private void validateUpyunSign(String signIdentifier, String fileUrl, Long userId) {
|
|
|
+// if (StringUtils.isBlank(signIdentifier)){
|
|
|
+// throw new StatusException("300001", "签名标识不能为空");
|
|
|
+// }
|
|
|
+ if (!StringUtils.isBlank(signIdentifier)) {
|
|
|
+ String upyunSignRedisKey = Constants.EXAM_CAPTURE_PHOTO_UPYUN_SIGN_PREFIX + userId + "_" + signIdentifier;
|
|
|
+ UpYunHttpRequest upYunHttpRequest = redisClient.get(upyunSignRedisKey, UpYunHttpRequest.class);
|
|
|
+ if (upYunHttpRequest == null) {
|
|
|
+ throw new StatusException("301003", "无效的请求,请检查签名标识");
|
|
|
+ }
|
|
|
+ if (!upYunHttpRequest.getAccessUrl().equals(fileUrl)) {
|
|
|
+ throw new StatusException("301004", "文件路径格式不正确");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @ApiOperation(value = "获取抓拍结果")
|
|
|
+ @GetMapping("/getExamCaptureResult")
|
|
|
+ public GetExamCaptureResultDomain getExamCaptureResult(@RequestParam Long examRecordDataId, @RequestParam String fileName) {
|
|
|
+ if (null == examRecordDataId) {
|
|
|
+ throw new StatusException("301005", "examRecordDataId不能为空");
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(fileName)) {
|
|
|
+ throw new StatusException("301006", "fileName不能为空");
|
|
|
+ }
|
|
|
+ ExamCaptureEntity examCaptureEntity = examCaptureService.getExamCaptureResult(examRecordDataId, fileName);
|
|
|
+ GetExamCaptureResultDomain domain = new GetExamCaptureResultDomain();
|
|
|
+ if (examCaptureEntity == null) {
|
|
|
+ domain.setIsCompleted(false);
|
|
|
+ } else {
|
|
|
+ domain.setIsCompleted(true);
|
|
|
+ domain.setIsPass(examCaptureEntity.getIsPass());
|
|
|
+ domain.setIsStranger(examCaptureEntity.getIsStranger());
|
|
|
+ domain.setExamRecordDataId(examRecordDataId);
|
|
|
+ domain.setFileName(fileName);
|
|
|
+ }
|
|
|
+ return domain;
|
|
|
+ }
|
|
|
+
|
|
|
+ @ApiOperation(value = "保存考试抓拍照片队列")
|
|
|
+ @PostMapping("/uploadExamCapture")
|
|
|
+ public String uploadExamCapture(@RequestBody SaveExamCaptureQueueInfo saveExamCaptureQueueInfo) {
|
|
|
+ User user = getAccessUser();
|
|
|
+
|
|
|
+ ExamingSession examingSession = examingSessionService.getExamingSession(user.getUserId());
|
|
|
+ //不存在考试会话,直接返回
|
|
|
+ if (null == examingSession || examingSession.getExamingStatus() == ExamingStatus.INFORMAL) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ //参数校验
|
|
|
+ if (saveExamCaptureQueueInfo == null) {
|
|
|
+ throw new StatusException("ExamCaptureQueueController-uploadExamCapture-001", "对象不能为空");
|
|
|
+ }
|
|
|
+ if (saveExamCaptureQueueInfo.getExamRecordDataId() == null) {
|
|
|
+ throw new StatusException("ExamCaptureQueueController-uploadExamCapture-002", "examRecordDataId不能为空");
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(saveExamCaptureQueueInfo.getFileUrl())) {
|
|
|
+ throw new StatusException("ExamCaptureQueueController-uploadExamCapture-003", "fileUrl不能为空");
|
|
|
+ }
|
|
|
+ //校验虚拟摄像头格式,必须 是Json数组,如果格式不正确,则置为null
|
|
|
+ if (StringUtils.isNoneBlank(saveExamCaptureQueueInfo.getCameraInfos())) {
|
|
|
+ try {
|
|
|
+ JSONArray jsonArray = new JSONArray(saveExamCaptureQueueInfo.getCameraInfos());
|
|
|
+ if (jsonArray.length() == 0) {
|
|
|
+ saveExamCaptureQueueInfo.setCameraInfos(null);
|
|
|
+ }
|
|
|
+ } catch (JSONException e) {
|
|
|
+ saveExamCaptureQueueInfo.setCameraInfos(null);
|
|
|
+ log.error("ExamCaptureQueueController-uploadExamCapture-004:虚拟摄像头信息格式不正确", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ validateUpyunSign(saveExamCaptureQueueInfo.getSignIdentifier(), saveExamCaptureQueueInfo.getFileUrl(), user.getUserId());
|
|
|
+
|
|
|
+ //查看redis中是否存在锁(交卷时如果照片已经处理完后,就会上锁,此时不允许再向库中存照片)
|
|
|
+ if (redisTemplate.hasKey(Constants.EXAM_CAPTURE_PHOTO_LOCK_PREFIX + saveExamCaptureQueueInfo.getExamRecordDataId())) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return examCaptureQueueService.saveExamCaptureQueue(saveExamCaptureQueueInfo, user.getUserId());
|
|
|
+ }
|
|
|
+}
|