Browse Source

照片抓拍

lideyin 5 years ago
parent
commit
9849823a58

+ 172 - 0
examcloud-core-oe-task-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/task/controller/ExamCaptureController.java

@@ -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());
+    }
+}

+ 72 - 0
examcloud-core-oe-task-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/task/controller/bean/GetExamCaptureResultDomain.java

@@ -0,0 +1,72 @@
+package cn.com.qmth.examcloud.core.oe.task.controller.bean;
+
+import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
+
+public class GetExamCaptureResultDomain implements JsonSerializable {
+	
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -7258224010169602773L;
+	
+	/**
+	 * 是否处理完成
+	 */
+	private Boolean isCompleted;
+
+	private Long examRecordDataId;
+	
+	/**
+	 * 是否通过
+	 */
+	private Boolean isPass;
+	
+	/**
+	 * 是否有陌生人
+	 */
+	private Boolean isStranger;
+	
+	private String fileName;
+	
+	public Long getExamRecordDataId() {
+		return examRecordDataId;
+	}
+
+	public void setExamRecordDataId(Long examRecordDataId) {
+		this.examRecordDataId = examRecordDataId;
+	}
+
+	public Boolean getIsPass() {
+		return isPass;
+	}
+
+	public void setIsPass(Boolean isPass) {
+		this.isPass = isPass;
+	}
+
+	public Boolean getIsStranger() {
+		return isStranger;
+	}
+
+	public void setIsStranger(Boolean isStranger) {
+		this.isStranger = isStranger;
+	}
+
+	public String getFileName() {
+		return fileName;
+	}
+
+	public void setFileName(String fileName) {
+		this.fileName = fileName;
+	}
+
+	public Boolean getIsCompleted() {
+		return isCompleted;
+	}
+
+	public void setIsCompleted(Boolean isCompleted) {
+		this.isCompleted = isCompleted;
+	}
+
+}

+ 30 - 0
examcloud-core-oe-task-service/src/main/java/cn/com/qmth/examcloud/core/oe/task/service/ExamingSessionService.java

@@ -0,0 +1,30 @@
+package cn.com.qmth.examcloud.core.oe.task.service;
+
+import cn.com.qmth.examcloud.support.examing.ExamingSession;
+
+/**
+ * @author chenken
+ *
+ */
+public interface ExamingSessionService {
+
+    /**
+     * 保存考试会话
+     * @param studentId
+     * @param examingSession
+     */
+    public void saveExamingSession(Long studentId, ExamingSession examingSession);
+
+    /**
+     * 获取
+     * @param studentId
+     * @return
+     */
+    public ExamingSession getExamingSession(Long studentId);
+
+    /**
+     * 删除
+     * @param studentId
+     */
+    public void deleteExamingSession(Long studentId);
+}

+ 39 - 0
examcloud-core-oe-task-service/src/main/java/cn/com/qmth/examcloud/core/oe/task/service/impl/ExamingSessionServiceImpl.java

@@ -0,0 +1,39 @@
+package cn.com.qmth.examcloud.core.oe.task.service.impl;
+
+import cn.com.qmth.examcloud.core.oe.task.service.ExamingSessionService;
+import cn.com.qmth.examcloud.support.examing.ExamingSession;
+import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
+import cn.com.qmth.examcloud.web.redis.RedisClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author chenken
+ * @date 2018/8/15 9:24
+ * @company QMTH
+ * @description 考试会话服务实现
+ */
+@Service("examingSessionService")
+public class ExamingSessionServiceImpl implements ExamingSessionService {
+
+    @Autowired
+    private RedisClient redisClient;
+
+    @Override
+    public void saveExamingSession(Long studentId, ExamingSession examingSession) {
+        String key = RedisKeyHelper.getBuilder().examingSessionKey(studentId);
+        redisClient.set(key,examingSession,-1);
+    }
+
+    @Override
+    public ExamingSession getExamingSession(Long studentId) {
+        String key = RedisKeyHelper.getBuilder().examingSessionKey(studentId);
+        return redisClient.get(key+studentId,ExamingSession.class);
+    }
+
+    @Override
+    public void deleteExamingSession(Long studentId) {
+        String key = RedisKeyHelper.getBuilder().examingSessionKey(studentId);
+        redisClient.delete(key+studentId);
+    }
+}