NotaryDomainImpl.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. package me.zhengjie.domain.notary.impl;
  2. import com.arcsoft.face.*;
  3. import com.arcsoft.face.enums.DetectMode;
  4. import com.arcsoft.face.enums.DetectOrient;
  5. import com.arcsoft.face.enums.ErrorInfo;
  6. import com.arcsoft.face.toolkit.ImageInfo;
  7. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  8. import lombok.RequiredArgsConstructor;
  9. import lombok.extern.slf4j.Slf4j;
  10. import me.zhengjie.base.ResultCode;
  11. import me.zhengjie.base.file.FaceMinioFileHandle;
  12. import me.zhengjie.base.file.FileHandleVo;
  13. import me.zhengjie.base.file.MinioFileHandle;
  14. import me.zhengjie.base.util.JuheServiceUtil;
  15. import me.zhengjie.base.util.tencent.utils.Img2Base64Util;
  16. import me.zhengjie.dao.mybatis.ThirdPartyInterfaceRepository;
  17. import me.zhengjie.dao.mybatis.entity.*;
  18. import me.zhengjie.dao.mybatis.mapper.ContractOrderMapper;
  19. import me.zhengjie.dao.mybatis.mapper.FileInfoMapper;
  20. import me.zhengjie.dao.mybatis.mapper.SysUserMapper;
  21. import me.zhengjie.dao.mybatis.mapper.UserAXQInfoMapper;
  22. import me.zhengjie.domain.img.CompareImageDomain;
  23. import me.zhengjie.domain.notary.NotaryDomain;
  24. import me.zhengjie.utils.RedisUtils;
  25. import me.zhengjie.utils.StringUtils;
  26. import org.springframework.stereotype.Component;
  27. import org.springframework.util.ObjectUtils;
  28. import java.io.File;
  29. import java.io.IOException;
  30. import java.util.ArrayList;
  31. import java.util.List;
  32. import java.util.concurrent.TimeUnit;
  33. import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;
  34. @Component
  35. @RequiredArgsConstructor
  36. @Slf4j
  37. public class NotaryDomainImpl implements NotaryDomain {
  38. private final SysUserMapper userMapper;
  39. private final UserAXQInfoMapper userAXQInfoMapper;
  40. private final ContractOrderMapper contractOrderMapper;
  41. private final FaceMinioFileHandle minioFileHandle;
  42. private final FileInfoMapper fileInfoMapper;
  43. private final RedisUtils redis;
  44. private final ThirdPartyInterfaceRepository thirdPartyInterfaceRepository;
  45. //以下为测试部署环境
  46. private static final String APPID = "6F5JVsCCeSEbBSLSXWVwPki71yK5Y4Jf7oUjA4Y3mLtu";
  47. private static final String SDKKEY = "5qKM4a9oNSXNhXdwd7Ycrvnxdw2JXjcyeccYmb4zND7S";
  48. private static final String LIBPATH = "/home/tom/nt-test/lib/so";
  49. //以下为本地测试
  50. /* private static final String APPID = "H6Er8ksqAcKc7Dk4Yum9Rkz4g9Gm77ZXAEMgvenjkTQQ";
  51. private static final String SDKKEY = "Abd9D8xZQUqG8vDtU2a1tEkdfThkK1tZppjXzydGwEd6";
  52. private static final String LIBPATH = "D:\\arcsoft_lib";*/
  53. /**
  54. * 获取base64取消文件头
  55. * @param base64
  56. * @return
  57. */
  58. public String getBase64(String base64){
  59. String[] base64s = base64.split("base64");
  60. if (base64s!=null && base64s.length>1){
  61. base64 = base64s[1];
  62. }
  63. return base64;
  64. }
  65. /**
  66. * app端的人脸核身
  67. * @param compareImageDomain
  68. * @return
  69. */
  70. public ResultCode appCompareFace(CompareImageDomain compareImageDomain){
  71. String base64 = compareImageDomain.getBase64();
  72. if (base64==null){
  73. return ResultCode.PARAM_IS_BLANK;
  74. }
  75. base64 = getBase64(base64);
  76. String idCard = compareImageDomain.getIdCard();
  77. String nickName = compareImageDomain.getName();
  78. //当事人的人脸核身
  79. QueryWrapper<UserAXQInfoEntity> userAXQInfoEntityQueryWrapper = new QueryWrapper<>();
  80. userAXQInfoEntityQueryWrapper.eq("id_card",idCard).eq("nick_name",nickName);
  81. UserAXQInfoEntity userAXQInfoEntity = userAXQInfoMapper.selectOne(userAXQInfoEntityQueryWrapper);
  82. if (ObjectUtils.isEmpty(userAXQInfoEntity)){
  83. return ResultCode.PARAM_IS_INVALID;
  84. }
  85. //做过安心签的用户 直接人脸核身 保存图片
  86. ThirdPartyInterfaceEntity thirdPartyInterfaceEntity = JuheServiceUtil.URLPost(idCard, nickName, base64);
  87. File base = null;
  88. try {
  89. base = File.createTempFile("compare", ".jpeg");
  90. base.deleteOnExit();
  91. } catch (IOException e) {
  92. throw new RuntimeException(e);
  93. }
  94. if (!Img2Base64Util.generateImage(base64, base.getPath())) {
  95. log.info("base64转图片异常");
  96. return ResultCode.FACEAUTH_FAIL;
  97. }
  98. FileInfoEntity fileInfo = saveCompareImage(base);
  99. fileInfoMapper.insert(fileInfo);
  100. thirdPartyInterfaceEntity.setFileId(fileInfo.getId()+"");
  101. thirdPartyInterfaceEntity.setBusinessNo(compareImageDomain.getBusinessNo());
  102. if (StringUtils.isNotBlank(thirdPartyInterfaceEntity.getMessage())){
  103. //没有message说明人脸核身成功
  104. UserAXQInfoEntity userAxq = new UserAXQInfoEntity();
  105. userAxq.setId(userAXQInfoEntity.getId());
  106. userAxq.setCompareImgId(fileInfo.getId());
  107. userAXQInfoMapper.updateById(userAxq);
  108. log.info("当事人人脸核身通过");
  109. thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity);
  110. return ResultCode.SUCCESS;
  111. }
  112. thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity);
  113. return ResultCode.LIVE_VIDEO_INVALID;
  114. }
  115. /**
  116. * 照片比对
  117. *
  118. * @param compareImageDomain
  119. * @return
  120. */
  121. public ResultCode compareFace(CompareImageDomain compareImageDomain) {
  122. String base64 = compareImageDomain.getBase64();
  123. if (base64==null){
  124. return ResultCode.PARAM_IS_BLANK;
  125. }
  126. base64 = getBase64(base64);
  127. //先判断是银行客户经理还是当事人
  128. String roleId = compareImageDomain.getRoleId();
  129. SysUserEntity sysUserEntity = null;
  130. UserAXQInfoEntity userAXQInfoEntity = null;
  131. String idCard = compareImageDomain.getIdCard();
  132. String nickName = compareImageDomain.getName();
  133. boolean flag = "-1".equals(roleId);
  134. if (flag) {
  135. //说明是银行客户经理
  136. QueryWrapper<ContractOrderEntity> contractOrderEntityQueryWrapper = new QueryWrapper<>();
  137. contractOrderEntityQueryWrapper.eq("business_no",compareImageDomain.getBusinessNo()).eq("customer_name",compareImageDomain.getName());
  138. ContractOrderEntity contractOrderEntity = contractOrderMapper.selectOne(contractOrderEntityQueryWrapper);
  139. if (ObjectUtils.isEmpty(contractOrderEntity)){
  140. return ResultCode.ACCOUNT_MANAGER_NO_ASSIGNED;
  141. }
  142. QueryWrapper<SysUserEntity> sysUserEntityQueryWrapper = new QueryWrapper<>();
  143. sysUserEntityQueryWrapper.eq("id_card", idCard).eq("nick_name", nickName);
  144. sysUserEntity = userMapper.selectOne(sysUserEntityQueryWrapper);
  145. } else {
  146. //说明是当事人
  147. QueryWrapper<UserAXQInfoEntity> userAXQInfoEntityQueryWrapper = new QueryWrapper<>();
  148. userAXQInfoEntityQueryWrapper.eq("id_card", idCard).eq("user_name", nickName);
  149. userAXQInfoEntity = userAXQInfoMapper.selectOne(userAXQInfoEntityQueryWrapper);
  150. }
  151. if (ObjectUtils.isEmpty(sysUserEntity) && ObjectUtils.isEmpty(userAXQInfoEntity)) {
  152. return ResultCode.PARAM_IS_INVALID;
  153. }
  154. //后面需要的三个参数 base64 身份证号 姓名
  155. String redisCount = "idCard:" + idCard + ":COUNT:";
  156. Integer count = null;
  157. if (redis.hasKey(redisCount)) {
  158. count = (Integer) redis.get(redisCount);
  159. System.err.println("redis存入次数" + count);
  160. }
  161. //将base64转成图片
  162. File base = null;
  163. try {
  164. base = File.createTempFile("compare", ".jpeg");
  165. base.deleteOnExit();
  166. } catch (IOException e) {
  167. throw new RuntimeException(e);
  168. }
  169. if (!Img2Base64Util.generateImage(base64, base.getPath())) {
  170. log.info("base64转图片异常");
  171. return ResultCode.FACEAUTH_FAIL;
  172. }
  173. FileInfoEntity fileInfo = saveCompareImage(base);
  174. fileInfoMapper.insert(fileInfo);
  175. boolean redisFlag = (count != null && count >= 2);
  176. if (flag) {
  177. //说明是客户经理
  178. if (sysUserEntity.getCompareImgId() == null || redisFlag) {
  179. //说明客户经理需要做人脸核身
  180. ThirdPartyInterfaceEntity thirdPartyInterfaceEntity = JuheServiceUtil.URLPost(idCard, nickName, base64);
  181. thirdPartyInterfaceEntity.setFileId(fileInfo.getId()+"");
  182. thirdPartyInterfaceEntity.setBusinessNo(compareImageDomain.getBusinessNo());
  183. if (StringUtils.isNotBlank(thirdPartyInterfaceEntity.getMessage())){
  184. //上传图片到minio FileInfo
  185. SysUserEntity bank = new SysUserEntity();
  186. bank.setUserId(sysUserEntity.getUserId());
  187. bank.setCompareImgId(fileInfo.getId());
  188. userMapper.updateById(bank);
  189. log.info("银行客户经理人脸核身通过");
  190. redis.del(redisCount);
  191. thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity);
  192. return ResultCode.SUCCESS;
  193. }
  194. log.info("客户经理人脸核身失败");
  195. thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity);
  196. return ResultCode.LIVE_VIDEO_INVALID;
  197. }
  198. } else {
  199. //说明是当事人
  200. if (userAXQInfoEntity.getCompareImgId() == null || redisFlag) {
  201. //说明当事人需要做人脸核身
  202. ThirdPartyInterfaceEntity thirdPartyInterfaceEntity = JuheServiceUtil.URLPost(idCard, nickName, base64);
  203. thirdPartyInterfaceEntity.setFileId(fileInfo.getId()+"");
  204. thirdPartyInterfaceEntity.setBusinessNo(compareImageDomain.getBusinessNo());
  205. if (thirdPartyInterfaceEntity.getResult()==1){
  206. //上传图片到minio FileInfo
  207. UserAXQInfoEntity userAxq = new UserAXQInfoEntity();
  208. userAxq.setId(userAXQInfoEntity.getId());
  209. userAxq.setCompareImgId(fileInfo.getId());
  210. userAXQInfoMapper.updateById(userAxq);
  211. log.info("当事人人脸核身通过");
  212. redis.del(redisCount);
  213. thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity);
  214. return ResultCode.SUCCESS;
  215. }
  216. log.info("当事人人脸核身失败");
  217. thirdPartyInterfaceRepository.insert(thirdPartyInterfaceEntity);
  218. return ResultCode.LIVE_VIDEO_INVALID;
  219. }
  220. }
  221. //如果不用做人脸核身 那么就去做照片比对
  222. //获取比较图片的id
  223. Integer id = null;
  224. if (!ObjectUtils.isEmpty(sysUserEntity)) {
  225. id = sysUserEntity.getCompareImgId();
  226. }
  227. if (!ObjectUtils.isEmpty(userAXQInfoEntity)) {
  228. id = userAXQInfoEntity.getCompareImgId();
  229. }
  230. if (! compareImage(base, id,redisCount,count)) {
  231. return ResultCode.LIVE_VIDEO_INVALID;
  232. }
  233. if (count != null) {
  234. redis.del(redisCount);
  235. }
  236. return ResultCode.SUCCESS;
  237. }
  238. /**
  239. * 虹软的人脸照片比对
  240. * @param base 照片
  241. * @param id 文件库中照片的id
  242. * @param redisCount 数据库中的键
  243. * @param count redis当中的次数
  244. * @return
  245. */
  246. public boolean compareImage(File base, Integer id,String redisCount,Integer count) {
  247. //从官网获取
  248. FaceEngine faceEngine = new FaceEngine(LIBPATH);
  249. //激活引擎
  250. int errorCode = faceEngine.activeOnline(APPID, SDKKEY);
  251. if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
  252. throw new RuntimeException("引擎激活失败");
  253. }
  254. ActiveFileInfo activeFileInfo = new ActiveFileInfo();
  255. errorCode = faceEngine.getActiveFileInfo(activeFileInfo);
  256. if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
  257. throw new RuntimeException("获取激活文件信息失败");
  258. }
  259. //引擎配置
  260. EngineConfiguration engineConfiguration = new EngineConfiguration();
  261. engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
  262. engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
  263. engineConfiguration.setDetectFaceMaxNum(10);
  264. engineConfiguration.setDetectFaceScaleVal(16);
  265. //功能配置
  266. FunctionConfiguration functionConfiguration = new FunctionConfiguration();
  267. functionConfiguration.setSupportAge(true);
  268. functionConfiguration.setSupportFace3dAngle(true);
  269. functionConfiguration.setSupportFaceDetect(true);
  270. functionConfiguration.setSupportFaceRecognition(true);
  271. functionConfiguration.setSupportGender(true);
  272. functionConfiguration.setSupportLiveness(true);
  273. functionConfiguration.setSupportIRLiveness(true);
  274. engineConfiguration.setFunctionConfiguration(functionConfiguration);
  275. //初始化引擎
  276. errorCode = faceEngine.init(engineConfiguration);
  277. if (errorCode != ErrorInfo.MOK.getValue()) {
  278. throw new RuntimeException("初始化引擎失败");
  279. }
  280. //人脸检测
  281. ImageInfo imageInfo = getRGBData(base);
  282. List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
  283. errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
  284. System.out.println(faceInfoList);
  285. //人脸属性检测
  286. FunctionConfiguration configuration = new FunctionConfiguration();
  287. configuration.setSupportFace3dAngle(true);
  288. errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, configuration);
  289. //3D信息检测
  290. List<Face3DAngle> face3DAngleList = new ArrayList<Face3DAngle>();
  291. errorCode = faceEngine.getFace3DAngle(face3DAngleList);
  292. //俯仰角
  293. float pitch = Math.abs(face3DAngleList.get(0).getPitch());
  294. //偏向角
  295. float yaw = Math.abs(face3DAngleList.get(0).getYaw());
  296. if (pitch > 10 || yaw > 10) {
  297. //照片不符合标准
  298. log.info("图片不符合标准");
  299. return false;
  300. }
  301. //特征提取
  302. FaceFeature faceFeature = new FaceFeature();
  303. errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature);
  304. //根据id 查找文件
  305. QueryWrapper<FileInfoEntity> fileInfoQw = new QueryWrapper<>();
  306. fileInfoQw.eq("id", id);
  307. FileInfoEntity fileInfoEntity = fileInfoMapper.selectOne(fileInfoQw);
  308. String filePath = fileInfoEntity.getPath();
  309. File file = null;
  310. try {
  311. file = minioFileHandle.getFileWithPath(filePath);
  312. } catch (Exception e) {
  313. throw new RuntimeException(e);
  314. }
  315. //人脸检测2
  316. ImageInfo imageInfo2 = getRGBData(file);
  317. List<FaceInfo> faceInfoList2 = new ArrayList<FaceInfo>();
  318. errorCode = faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), faceInfoList2);
  319. //特征提取2
  320. FaceFeature faceFeature2 = new FaceFeature();
  321. errorCode = faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), faceInfoList2.get(0), faceFeature2);
  322. //特征比对
  323. FaceFeature targetFaceFeature = new FaceFeature();
  324. targetFaceFeature.setFeatureData(faceFeature.getFeatureData());
  325. FaceFeature sourceFaceFeature = new FaceFeature();
  326. sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());
  327. FaceSimilar faceSimilar = new FaceSimilar();
  328. errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
  329. //如果通过 上传文件 修改用户绑定id 如果没通过 返回null证明失败了
  330. if (faceSimilar.getScore() > 0.8) {
  331. log.info("人脸照片比对通过");
  332. return true;
  333. }
  334. if (count == null) {
  335. redis.set(redisCount, 1, 30, TimeUnit.MINUTES);
  336. } else {
  337. redis.set(redisCount, count + 1, 30, TimeUnit.MINUTES);
  338. }
  339. log.info("人脸照片比对未通过");;
  340. return false;
  341. }
  342. private FileInfoEntity saveCompareImage(File base) {
  343. FileHandleVo fileHandleVo = new FileHandleVo();
  344. fileHandleVo.setFilePath(base.getPath());
  345. fileHandleVo.setSourceFilePath("/face/" + base.getName());
  346. fileHandleVo.setContentType("image/jpeg");
  347. try {
  348. minioFileHandle.uploadfilePath(fileHandleVo);
  349. } catch (Exception e) {
  350. throw new RuntimeException("照片保存到minio异常");
  351. }
  352. FileInfoEntity fileInfo = new FileInfoEntity();
  353. fileInfo.setLoanNo("face");
  354. fileInfo.setFileName(base.getName());
  355. fileInfo.setPath(fileInfo.getLoanNo() + "/" + base.getName());
  356. return fileInfo;
  357. }
  358. }