Преглед на файлове

Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	themis-mq/src/main/java/com/qmth/themis/mq/enums/MqTagEnum.java
wangliang преди 4 години
родител
ревизия
0b566231ca
променени са 15 файла, в които са добавени 621 реда и са изтрити 83 реда
  1. 26 0
      themis-business/src/main/java/com/qmth/themis/business/bean/exam/FaceVerifyBean.java
  2. 26 0
      themis-business/src/main/java/com/qmth/themis/business/bean/exam/LivenessVerifyBean.java
  3. 33 0
      themis-business/src/main/java/com/qmth/themis/business/cache/RedisKeyHelper.java
  4. 143 0
      themis-business/src/main/java/com/qmth/themis/business/cache/bean/FaceVerifyCacheBean.java
  5. 94 67
      themis-business/src/main/java/com/qmth/themis/business/entity/TOeFaceVerifyHistory.java
  6. 25 0
      themis-business/src/main/java/com/qmth/themis/business/enums/FaceVerifyExceptionEnum.java
  7. 6 0
      themis-business/src/main/java/com/qmth/themis/business/service/TOeFaceVerifyHistoryService.java
  8. 55 1
      themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeFaceVerifyHistoryServiceImpl.java
  9. 4 2
      themis-business/src/main/resources/db/init.sql
  10. 76 0
      themis-exam/src/main/java/com/qmth/themis/exam/api/TEFaceController.java
  11. 6 0
      themis-exam/src/main/java/com/qmth/themis/exam/start/StartRunning.java
  12. 6 0
      themis-mq/src/main/java/com/qmth/themis/mq/service/MqLogicService.java
  13. 28 0
      themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java
  14. 11 13
      themis-mq/src/main/java/com/qmth/themis/mq/templete/impl/CalculateObjectiveScoreConcurrentlyImpl.java
  15. 82 0
      themis-mq/src/main/java/com/qmth/themis/mq/templete/impl/FaceVerifyConcurrentlyImpl.java

+ 26 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/exam/FaceVerifyBean.java

@@ -0,0 +1,26 @@
+package com.qmth.themis.business.bean.exam;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel("人脸验证返回信息")
+public class FaceVerifyBean {
+	@ApiModelProperty("id")
+	private Long id;
+	@ApiModelProperty("updateTime")
+	private Long updateTime;
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public Long getUpdateTime() {
+		return updateTime;
+	}
+	public void setUpdateTime(Long updateTime) {
+		this.updateTime = updateTime;
+	}
+
+	
+}

+ 26 - 0
themis-business/src/main/java/com/qmth/themis/business/bean/exam/LivenessVerifyBean.java

@@ -0,0 +1,26 @@
+package com.qmth.themis.business.bean.exam;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel("活体验证返回信息")
+public class LivenessVerifyBean {
+	@ApiModelProperty("id")
+	private Long id;
+	@ApiModelProperty("updateTime")
+	private Long updateTime;
+	public Long getId() {
+		return id;
+	}
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public Long getUpdateTime() {
+		return updateTime;
+	}
+	public void setUpdateTime(Long updateTime) {
+		this.updateTime = updateTime;
+	}
+
+	
+}

+ 33 - 0
themis-business/src/main/java/com/qmth/themis/business/cache/RedisKeyHelper.java

@@ -3,12 +3,35 @@ package com.qmth.themis.business.cache;
 public class RedisKeyHelper {
 	private static String underLine = "_";
 
+	/**
+	 * 场次
+	 */
 	private static String examActivityKeyPrefix = "exam_activity::";
+	/**
+	 * 考生
+	 */
 	private static String examStudentKeyPrefix = "exam_student::";
+	/**
+	 * 考试记录
+	 */
 	private static String examRecordKeyPrefix = "exam_record::";
+	/**
+	 * 考生试卷结构
+	 */
 	private static String studentPaperStructKeyPrefix = "student_paper_struct::";
+	/**
+	 * 考生作答
+	 */
 	private static String studentAnswerKeyPrefix = "student_answer::";
+	/**
+	 * 剩余音频播放次数
+	 */
 	private static String audioLeftPlayCountKeyPrefix = "audio_left_play_count::";
+	
+	/**
+	 * 人脸验证
+	 */
+	private static String faceVerifyKeyPrefix = "face_verify::";
 
 	/**
 	 * 场次
@@ -85,5 +108,15 @@ public class RedisKeyHelper {
 	public static String audioLeftPlayCountKey(Long examRecordId) {
 		return audioLeftPlayCountKeyPrefix + examRecordId;
 	}
+	
+	/**
+	 * 人脸验证
+	 * 
+	 * @param id
+	 * @return
+	 */
+	public static String faceVerifyCacheKey(Long id) {
+		return faceVerifyKeyPrefix + id;
+	}
 
 }

+ 143 - 0
themis-business/src/main/java/com/qmth/themis/business/cache/bean/FaceVerifyCacheBean.java

@@ -0,0 +1,143 @@
+package com.qmth.themis.business.cache.bean;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import com.qmth.themis.business.enums.ExamTypeEnum;
+import com.qmth.themis.business.enums.FaceVerifyExceptionEnum;
+
+/**人脸验证记录
+ * @Description: 
+ * @Author: xiatian
+ * @Date: 2020-07-31
+ */
+public class FaceVerifyCacheBean implements Serializable {
+
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = -3424843813633012427L;
+
+	//主键
+    private Long id;
+
+    //考试记录ID
+    private Long examRecordId;
+
+    //相似度分数
+    private Double similarity;
+
+    //真实性验证结果
+    private Double realness;
+
+    //创建时间
+    private Date createTime;
+
+    //更新时间
+    private Date updateTime;
+
+    //first:初次开考,recover:恢复开考,process:过程中
+    private ExamTypeEnum type;
+
+    //图片保存路径
+    private String photoUrl;
+    
+    //人脸数量
+    private Integer faceCount;
+
+    //异常类型
+    private FaceVerifyExceptionEnum exception;
+    
+    //验证时间戳
+    private Long time;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getExamRecordId() {
+		return examRecordId;
+	}
+
+	public void setExamRecordId(Long examRecordId) {
+		this.examRecordId = examRecordId;
+	}
+
+	public Double getSimilarity() {
+		return similarity;
+	}
+
+	public void setSimilarity(Double similarity) {
+		this.similarity = similarity;
+	}
+
+	public Double getRealness() {
+		return realness;
+	}
+
+	public void setRealness(Double realness) {
+		this.realness = realness;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+	public Date getUpdateTime() {
+		return updateTime;
+	}
+
+	public void setUpdateTime(Date updateTime) {
+		this.updateTime = updateTime;
+	}
+
+	public ExamTypeEnum getType() {
+		return type;
+	}
+
+	public void setType(ExamTypeEnum type) {
+		this.type = type;
+	}
+
+	public String getPhotoUrl() {
+		return photoUrl;
+	}
+
+	public void setPhotoUrl(String photoUrl) {
+		this.photoUrl = photoUrl;
+	}
+
+	public Integer getFaceCount() {
+		return faceCount;
+	}
+
+	public void setFaceCount(Integer faceCount) {
+		this.faceCount = faceCount;
+	}
+
+	public FaceVerifyExceptionEnum getException() {
+		return exception;
+	}
+
+	public void setException(FaceVerifyExceptionEnum exception) {
+		this.exception = exception;
+	}
+
+	public Long getTime() {
+		return time;
+	}
+
+	public void setTime(Long time) {
+		this.time = time;
+	}
+
+
+}

+ 94 - 67
themis-business/src/main/java/com/qmth/themis/business/entity/TOeFaceVerifyHistory.java

@@ -1,16 +1,17 @@
 package com.qmth.themis.business.entity;
 
+import java.io.Serializable;
+import java.util.Date;
+
 import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.qmth.themis.business.enums.ExamTypeEnum;
-import com.qmth.themis.business.enums.RealnessEnum;
+import com.qmth.themis.business.enums.FaceVerifyExceptionEnum;
+
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 
-import java.io.Serializable;
-import java.util.Date;
-
 /**
  * @Description: 人脸验证记录
  * @Param:
@@ -20,9 +21,13 @@ import java.util.Date;
  */
 @ApiModel(value = "t_oe_face_verify_history", description = "人脸验证记录")
 public class TOeFaceVerifyHistory implements Serializable {
-    private static final long serialVersionUID = 1L;
 
-    @ApiModelProperty(value = "主键")
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = 5187591142938085509L;
+
+	@ApiModelProperty(value = "主键")
     @TableId(value = "id")
     private Long id;
 
@@ -30,13 +35,17 @@ public class TOeFaceVerifyHistory implements Serializable {
     @TableField(value = "exam_record_id")
     private Long examRecordId;
 
+    @ApiModelProperty(value = "人脸数量")
+    @TableField(value = "face_count")
+    private Integer faceCount;
+    
     @ApiModelProperty(value = "相似度分数")
     @TableField(value = "similarity")
     private Double similarity;
 
     @ApiModelProperty(value = "真实性验证结果")
     @TableField(value = "realness")
-    private RealnessEnum realness;
+    private Double realness;
 
     @ApiModelProperty(value = "创建时间")
     @TableField(value = "create_time", fill = FieldFill.INSERT)
@@ -49,88 +58,106 @@ public class TOeFaceVerifyHistory implements Serializable {
     @ApiModelProperty(value = "first:初次开考,recover:恢复开考,process:过程中")
     @TableField(value = "type")
     private ExamTypeEnum type;
+    
+    @ApiModelProperty(value = "异常类型")
+    @TableField(value = "exception")
+    private FaceVerifyExceptionEnum exception;
 
     @ApiModelProperty(value = "图片保存路径")
     @TableField(value = "photo_url")
     private String photoUrl;
+    
+    @ApiModelProperty(value = "验证时间戳")
+    @TableField(value = "time")
+    private Long time;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getExamRecordId() {
+		return examRecordId;
+	}
+
+	public void setExamRecordId(Long examRecordId) {
+		this.examRecordId = examRecordId;
+	}
 
-    @ApiModelProperty(value = "本地验证是否通过,0:不通过,1:通过")
-    @TableField(value = "pass")
-    private Integer pass;
+	public Integer getFaceCount() {
+		return faceCount;
+	}
 
-    public static long getSerialVersionUID() {
-        return serialVersionUID;
-    }
+	public void setFaceCount(Integer faceCount) {
+		this.faceCount = faceCount;
+	}
 
-    public Long getId() {
-        return id;
-    }
+	public Double getSimilarity() {
+		return similarity;
+	}
 
-    public void setId(Long id) {
-        this.id = id;
-    }
+	public void setSimilarity(Double similarity) {
+		this.similarity = similarity;
+	}
 
-    public Long getExamRecordId() {
-        return examRecordId;
-    }
+	public Double getRealness() {
+		return realness;
+	}
 
-    public void setExamRecordId(Long examRecordId) {
-        this.examRecordId = examRecordId;
-    }
+	public void setRealness(Double realness) {
+		this.realness = realness;
+	}
 
-    public Double getSimilarity() {
-        return similarity;
-    }
+	public Date getCreateTime() {
+		return createTime;
+	}
 
-    public void setSimilarity(Double similarity) {
-        this.similarity = similarity;
-    }
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
 
-    public RealnessEnum getRealness() {
-        return realness;
-    }
+	public Date getUpdateTime() {
+		return updateTime;
+	}
 
-    public void setRealness(RealnessEnum realness) {
-        this.realness = realness;
-    }
+	public void setUpdateTime(Date updateTime) {
+		this.updateTime = updateTime;
+	}
 
-    public Date getCreateTime() {
-        return createTime;
-    }
+	public ExamTypeEnum getType() {
+		return type;
+	}
 
-    public void setCreateTime(Date createTime) {
-        this.createTime = createTime;
-    }
+	public void setType(ExamTypeEnum type) {
+		this.type = type;
+	}
 
-    public Date getUpdateTime() {
-        return updateTime;
-    }
+	public FaceVerifyExceptionEnum getException() {
+		return exception;
+	}
 
-    public void setUpdateTime(Date updateTime) {
-        this.updateTime = updateTime;
-    }
+	public void setException(FaceVerifyExceptionEnum exception) {
+		this.exception = exception;
+	}
 
-    public ExamTypeEnum getType() {
-        return type;
-    }
+	public String getPhotoUrl() {
+		return photoUrl;
+	}
 
-    public void setType(ExamTypeEnum type) {
-        this.type = type;
-    }
+	public void setPhotoUrl(String photoUrl) {
+		this.photoUrl = photoUrl;
+	}
 
-    public String getPhotoUrl() {
-        return photoUrl;
-    }
+	public Long getTime() {
+		return time;
+	}
 
-    public void setPhotoUrl(String photoUrl) {
-        this.photoUrl = photoUrl;
-    }
+	public void setTime(Long time) {
+		this.time = time;
+	}
 
-    public Integer getPass() {
-        return pass;
-    }
 
-    public void setPass(Integer pass) {
-        this.pass = pass;
-    }
 }

+ 25 - 0
themis-business/src/main/java/com/qmth/themis/business/enums/FaceVerifyExceptionEnum.java

@@ -0,0 +1,25 @@
+package com.qmth.themis.business.enums;
+
+/**
+ * 人脸验证异常
+ * 
+ * @Description:
+ * @Author: xiatian
+ * @Date: 2020-07-31
+ */
+public enum FaceVerifyExceptionEnum {
+
+	NONE("无异常"),
+
+	FACE_COUNT_ERROR("人脸数量异常"), FACE_COMPARE_ERROR("人脸比对异常"), EYE_CLOSE_ERROR("闭眼检测异常"), ACE_COUNT_ERROR("恢复开考");
+
+	private String title;
+
+	private FaceVerifyExceptionEnum(String title) {
+		this.title = title;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+}

+ 6 - 0
themis-business/src/main/java/com/qmth/themis/business/service/TOeFaceVerifyHistoryService.java

@@ -1,6 +1,7 @@
 package com.qmth.themis.business.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.themis.business.bean.exam.FaceVerifyBean;
 import com.qmth.themis.business.entity.TOeFaceVerifyHistory;
 
 /**
@@ -12,4 +13,9 @@ import com.qmth.themis.business.entity.TOeFaceVerifyHistory;
  */
 public interface TOeFaceVerifyHistoryService extends IService<TOeFaceVerifyHistory> {
 
+	FaceVerifyBean verify(Long recordId, String type, String photoUrl, Integer faceCount, Double similarity, Double realness,
+			Long time, String exception);
+	void save(Long id,Long recordId, String type, String photoUrl, Integer faceCount, Double similarity, Double realness,
+			Long time, String exception);
+
 }

+ 55 - 1
themis-business/src/main/java/com/qmth/themis/business/service/impl/TOeFaceVerifyHistoryServiceImpl.java

@@ -1,10 +1,23 @@
 package com.qmth.themis.business.service.impl;
 
+import java.util.Date;
+
+import javax.annotation.Resource;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.themis.business.bean.exam.FaceVerifyBean;
+import com.qmth.themis.business.cache.RedisKeyHelper;
+import com.qmth.themis.business.cache.bean.FaceVerifyCacheBean;
 import com.qmth.themis.business.dao.TOeFaceVerifyHistoryMapper;
 import com.qmth.themis.business.entity.TOeFaceVerifyHistory;
+import com.qmth.themis.business.enums.ExamTypeEnum;
+import com.qmth.themis.business.enums.FaceVerifyExceptionEnum;
 import com.qmth.themis.business.service.TOeFaceVerifyHistoryService;
-import org.springframework.stereotype.Service;
+import com.qmth.themis.business.util.RedisUtil;
+import com.qmth.themis.common.contanst.Constants;
 
 /**
  * @Description: 人脸验证记录 服务实现类
@@ -16,4 +29,45 @@ import org.springframework.stereotype.Service;
 @Service
 public class TOeFaceVerifyHistoryServiceImpl extends ServiceImpl<TOeFaceVerifyHistoryMapper, TOeFaceVerifyHistory> implements TOeFaceVerifyHistoryService {
 
+	
+	@Resource
+	RedisUtil redisUtil;
+	
+	@Override
+	public FaceVerifyBean verify(Long recordId, String type, String photoUrl, Integer faceCount, Double similarity,
+			Double realness, Long time, String exception) {
+		FaceVerifyCacheBean cache=new FaceVerifyCacheBean();
+		cache.setId(Constants.idGen.next());
+		cache.setExamRecordId(recordId);
+		cache.setFaceCount(faceCount);
+		cache.setException(FaceVerifyExceptionEnum.valueOf(exception));
+		cache.setPhotoUrl(photoUrl);
+		cache.setRealness(realness);
+		cache.setSimilarity(similarity);
+		cache.setType(ExamTypeEnum.valueOf(type));
+		cache.setTime(time);
+		redisUtil.set(RedisKeyHelper.faceVerifyCacheKey(cache.getId()), cache);
+		FaceVerifyBean ret=new FaceVerifyBean();
+		ret.setId(cache.getId());
+		ret.setUpdateTime(new Date().getTime());
+		return ret;
+	}
+
+	@Transactional
+	@Override
+	public void save(Long id, Long recordId, String type, String photoUrl, Integer faceCount, Double similarity,
+			Double realness, Long time, String exception) {
+		TOeFaceVerifyHistory entity=new TOeFaceVerifyHistory();
+		entity.setId(id);
+		entity.setExamRecordId(recordId);
+		entity.setFaceCount(faceCount);
+		entity.setException(FaceVerifyExceptionEnum.valueOf(exception));
+		entity.setPhotoUrl(photoUrl);
+		entity.setRealness(realness);
+		entity.setSimilarity(similarity);
+		entity.setType(ExamTypeEnum.valueOf(type));
+		entity.setTime(time);
+		saveOrUpdate(entity);
+	}
+
 }

+ 4 - 2
themis-business/src/main/resources/db/init.sql

@@ -1165,13 +1165,15 @@ DROP TABLE IF EXISTS `t_oe_face_verify_history`;
 CREATE TABLE `t_oe_face_verify_history` (
   `id` bigint NOT NULL COMMENT '主键',
   `exam_record_id` bigint NOT NULL COMMENT '考试记录ID',
+  `face_count` int DEFAULT NULL COMMENT '人脸数量',
   `similarity` double DEFAULT NULL COMMENT '相似度分数',
-  `realness` varchar(30) DEFAULT NULL COMMENT '真实性验证结果',
+  `realness` double DEFAULT NULL COMMENT '真实性验证结果',
   `create_time` datetime DEFAULT NULL COMMENT '创建时间',
   `update_time` datetime DEFAULT NULL COMMENT '更新时间',
   `type` varchar(30) DEFAULT NULL COMMENT 'first:初次开考,recover:恢复开考,process:过程中',
+  `exception` varchar(30) DEFAULT NULL COMMENT '异常类型',
   `photo_url` varchar(100) DEFAULT NULL COMMENT '图片保存路径',
-  `pass` tinyint DEFAULT NULL COMMENT '本地验证是否通过,0:不通过,1:通过',
+  `time` bigint DEFAULT NULL COMMENT '验证时间戳',
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='人脸验证记录';
 

+ 76 - 0
themis-exam/src/main/java/com/qmth/themis/exam/api/TEFaceController.java

@@ -0,0 +1,76 @@
+package com.qmth.themis.exam.api;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Resource;
+
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.qmth.themis.business.bean.exam.FaceVerifyBean;
+import com.qmth.themis.business.enums.MqEnum;
+import com.qmth.themis.business.service.TEStudentService;
+import com.qmth.themis.business.service.TOeFaceVerifyHistoryService;
+import com.qmth.themis.mq.dto.MqDto;
+import com.qmth.themis.mq.enums.MqTagEnum;
+import com.qmth.themis.mq.enums.MqTopicEnum;
+import com.qmth.themis.mq.service.MqDtoService;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * 人脸验证
+ * 
+ * @Description:
+ * @Author: xiatian
+ * @Date: 2020-07-31
+ */
+@Api(tags = "人脸验证")
+@RestController
+@RequestMapping("/${prefix.url.exam}/face")
+public class TEFaceController {
+
+	@Resource
+	TOeFaceVerifyHistoryService faceVerifyHistoryService;
+	
+	@Resource
+	MqDtoService mqDtoService;
+
+	@ApiOperation(value = "人脸验证结果")
+	@RequestMapping(value = "/verify", method = RequestMethod.POST)
+	@ApiResponses({ @ApiResponse(code = 200, message = "人脸验证信息") })
+	@Transactional
+	public FaceVerifyBean verify(@ApiParam(value = "考试记录ID", required = true) @RequestParam Long recordId,
+			@ApiParam(value = "first_start:首次开考, resume_start:断点恢复, in_process:过程中", required = true) @RequestParam String type,
+			@ApiParam(value = "照片文件URL", required = true) @RequestParam String photoUrl,
+			@ApiParam(value = "人脸数量", required = true) @RequestParam Integer faceCount,
+			@ApiParam(value = "相似度分数", required = true) @RequestParam Double similarity,
+			@ApiParam(value = "真实性结果", required = true) @RequestParam Double realness,
+			@ApiParam(value = "验证时间", required = true) @RequestParam Long time,
+			@ApiParam(value = "none: 无异常 face_count_error: 人脸数量异常 face_compare_error: 人脸比对异常 eye_close_error: 闭眼检测异常", required = true) @RequestParam String exception) {
+		FaceVerifyBean ret=faceVerifyHistoryService.verify(recordId,type,photoUrl,faceCount,similarity,realness,time,exception);
+		Map<String, Object> transMap = new HashMap<String, Object>();
+		transMap.put("id", ret.getId());
+		transMap.put("recordId", recordId);
+		transMap.put("type", type);
+        transMap.put("photoUrl", photoUrl);
+        transMap.put("faceCount", faceCount);
+        transMap.put("similarity", similarity);
+        transMap.put("realness", realness);
+        transMap.put("time", time);
+        transMap.put("exception", exception);
+        //mq发送消息start
+        MqDto mqDto = new MqDto(MqTopicEnum.themisTopic.getCode(), MqTagEnum.faceVerifySave.name(), transMap, MqEnum.EXAM, null, null);
+        mqDtoService.assembleSendOneWayMsg(mqDto);
+		return ret;
+	}
+
+}

+ 6 - 0
themis-exam/src/main/java/com/qmth/themis/exam/start/StartRunning.java

@@ -17,6 +17,7 @@ import com.qmth.themis.mq.enums.MqTagEnum;
 import com.qmth.themis.mq.enums.MqTopicEnum;
 import com.qmth.themis.mq.listener.RocketMessageConsumer;
 import com.qmth.themis.mq.templete.impl.CalculateObjectiveScoreConcurrentlyImpl;
+import com.qmth.themis.mq.templete.impl.FaceVerifyConcurrentlyImpl;
 import com.qmth.themis.mq.templete.impl.SessionConcurrentlyImpl;
 import com.qmth.themis.mq.templete.impl.TaskConcurrentlyImpl;
 import com.qmth.themis.mq.templete.impl.UserLogConcurrentlyImpl;
@@ -85,6 +86,11 @@ public class StartRunning implements CommandLineRunner {
          */
         //计算客观分
         rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.normalGroup.getCode(), MqTopicEnum.themisTopic.getCode(), MqTagEnum.calculateObjectiveScore.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(CalculateObjectiveScoreConcurrentlyImpl.class));
+        
+        //人脸验证保存
+        rocketMessageConsumer.setRocketMQConsumer(nameServer, MqGroupEnum.normalGroup.getCode(), MqTopicEnum.themisTopic.getCode(), MqTagEnum.faceVerifySave.name(), MessageModel.CLUSTERING, SpringContextHolder.getBean(FaceVerifyConcurrentlyImpl.class));
+        
+        
         SystemConstant.initTempFiles();
         log.info("服务器启动时执行 end");
     }

+ 6 - 0
themis-mq/src/main/java/com/qmth/themis/mq/service/MqLogicService.java

@@ -58,4 +58,10 @@ public interface MqLogicService {
      * @param key
      */
     public void execMqCalculateObjectiveScoreLogic(MqDto mqDto, String key);
+
+	/**人脸验证保存
+	 * @param mqDto
+	 * @param key
+	 */
+	public void execMqFaceVerifySaveLogic(MqDto mqDto, String key);
 }

+ 28 - 0
themis-mq/src/main/java/com/qmth/themis/mq/service/impl/MqLogicServiceImpl.java

@@ -66,6 +66,9 @@ public class MqLogicServiceImpl implements MqLogicService {
 
     @Resource
     TOeExamRecordService examRecordService;
+    
+    @Resource
+	TOeFaceVerifyHistoryService faceVerifyHistoryService;
 
     /**
      * mq最大重试次数逻辑
@@ -240,4 +243,29 @@ public class MqLogicServiceImpl implements MqLogicService {
         tmRocketMessageService.saveOrUpdate(tmRocketMessage);
         redisUtil.delete(key, mqDto.getId());
     }
+
+	/**
+	 *人脸验证保存
+	 */
+	@Override
+	@Transactional
+	public void execMqFaceVerifySaveLogic(MqDto mqDto, String key) {
+		Gson gson = new Gson();
+        Map<String, Object> param = (Map<String, Object>) mqDto.getBody();
+        Long id=(Long)param.get("id");
+        Long recordId=(Long)param.get("recordId");
+        String type=(String)param.get("type");
+        String photoUrl=(String)param.get("photoUrl");
+        Integer faceCount=(Integer)param.get("faceCount");
+        Double similarity=(Double)param.get("similarity");
+        Double realness=(Double)param.get("realness");
+        Long time=(Long)param.get("time");
+        String exception=(String)param.get("exception");
+        faceVerifyHistoryService.save(id, recordId, type, photoUrl, faceCount, similarity, realness, time, exception);
+        mqDto.setAck(SystemConstant.STANDARD_ACK_TYPE);
+        TMRocketMessage tmRocketMessage = gson.fromJson(gson.toJson(mqDto), TMRocketMessage.class);
+        tmRocketMessage.setBody(JacksonUtil.parseJson(tmRocketMessage.getBody()));
+        tmRocketMessageService.saveOrUpdate(tmRocketMessage);
+        redisUtil.delete(key, mqDto.getId());
+	}
 }

+ 11 - 13
themis-mq/src/main/java/com/qmth/themis/mq/templete/impl/CalculateObjectiveScoreConcurrentlyImpl.java

@@ -1,25 +1,23 @@
 package com.qmth.themis.mq.templete.impl;
 
-import com.google.gson.Gson;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
 import com.qmth.themis.business.constant.SpringContextHolder;
 import com.qmth.themis.business.constant.SystemConstant;
-import com.qmth.themis.business.service.TMRocketMessageService;
-import com.qmth.themis.business.service.TOeExamRecordService;
 import com.qmth.themis.business.util.JacksonUtil;
 import com.qmth.themis.business.util.RedisUtil;
 import com.qmth.themis.common.contanst.Constants;
 import com.qmth.themis.mq.dto.MqDto;
 import com.qmth.themis.mq.service.MqLogicService;
 import com.qmth.themis.mq.templete.Concurrently;
-import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
-import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
-import org.apache.rocketmq.common.message.MessageExt;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.Objects;
 
 /**
  * 计算客观分
@@ -65,7 +63,7 @@ public class CalculateObjectiveScoreConcurrentlyImpl implements Concurrently {
                 }
             }
         } catch (Exception e) {
-            e.printStackTrace();
+        	log.error("计算客观分,消息消费出错",e);
             return ConsumeConcurrentlyStatus.RECONSUME_LATER;//重试
         } finally {
             if (Objects.nonNull(mqDto)) {

+ 82 - 0
themis-mq/src/main/java/com/qmth/themis/mq/templete/impl/FaceVerifyConcurrentlyImpl.java

@@ -0,0 +1,82 @@
+package com.qmth.themis.mq.templete.impl;
+
+import java.util.List;
+import java.util.Objects;
+
+import javax.annotation.Resource;
+
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import com.qmth.themis.business.constant.SpringContextHolder;
+import com.qmth.themis.business.constant.SystemConstant;
+import com.qmth.themis.business.service.TOeFaceVerifyHistoryService;
+import com.qmth.themis.business.util.JacksonUtil;
+import com.qmth.themis.business.util.RedisUtil;
+import com.qmth.themis.common.contanst.Constants;
+import com.qmth.themis.mq.dto.MqDto;
+import com.qmth.themis.mq.service.MqDtoService;
+import com.qmth.themis.mq.service.MqLogicService;
+import com.qmth.themis.mq.templete.Concurrently;
+
+/**
+ * 人脸验证保存
+ *
+ * @Description:
+ * @Author: xiatian
+ * @Date: 2020-07-30
+ */
+@Service
+public class FaceVerifyConcurrentlyImpl implements Concurrently {
+    private final static Logger log = LoggerFactory.getLogger(FaceVerifyConcurrentlyImpl.class);
+    
+	@Resource
+	RedisUtil redisUtil;
+	@Resource
+	MqLogicService mqLogicService;
+
+    @Override
+    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
+                                                    ConsumeConcurrentlyContext consumeConcurrentlyContext) {
+        MqDto mqDto = null;
+        try {
+            long threadId = Thread.currentThread().getId();
+            String threadName = Thread.currentThread().getName();
+            for (MessageExt messageExt : msgs) {
+                log.debug(":{}-:{} CalculateObjectiveScore 重试次数:{}", threadId, threadName,
+                        messageExt.getReconsumeTimes());
+                mqDto = JacksonUtil.readJson(new String(messageExt.getBody(), Constants.CHARSET), MqDto.class);
+                log.debug(":{}-:{} CalculateObjectiveScore 接收到的消息:{}", threadId, threadName,
+                        JacksonUtil.parseJson(mqDto));
+                int reconsumeTime = messageExt.getReconsumeTimes();
+                if (reconsumeTime >= SystemConstant.MAXRECONSUMETIMES) {
+                    mqLogicService.execMqWebsocketUnNormalLogic(mqDto, SystemConstant.MQ_TOPIC_BUFFER_LIST);
+                } else {
+                    if (Objects.nonNull(mqDto.getAck()) && mqDto.getAck().intValue() != SystemConstant.STANDARD_ACK_TYPE
+                            && Objects.nonNull(redisUtil.get(SystemConstant.MQ_TOPIC_BUFFER_LIST, mqDto.getId()))
+                            && redisUtil.lock(SystemConstant.REDIS_LOCK_MQ_PREFIX + mqDto.getId(),
+                            SystemConstant.REDIS_LOCK_MQ_TIME_OUT)) {
+                        log.debug(":{}-:{} 更新db", threadId, threadName);
+                        mqLogicService.execMqFaceVerifySaveLogic(mqDto, SystemConstant.MQ_TOPIC_BUFFER_LIST);
+                        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+                    } else {
+                        log.debug(":{}-:{} 消息ack未确认,重发", threadId, threadName);
+                        return ConsumeConcurrentlyStatus.RECONSUME_LATER;// 重试
+                    }
+                }
+            }
+        } catch (Exception e) {
+        	log.error("人脸验证保存,消息消费出错",e);
+            return ConsumeConcurrentlyStatus.RECONSUME_LATER;//重试
+        } finally {
+            if (Objects.nonNull(mqDto)) {
+                redisUtil.releaseLock(SystemConstant.REDIS_LOCK_MQ_PREFIX + mqDto.getId());
+            }
+        }
+        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;// 成功
+    }
+}