Parcourir la source

update face verify starter

deason il y a 2 ans
Parent
commit
cdd5b50fb4
24 fichiers modifiés avec 415 ajouts et 608 suppressions
  1. 5 0
      examcloud-starters/examcloud-face-verify-starter/pom.xml
  2. 0 6
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/FaceVerifyAutoConfiguration.java
  3. 68 31
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/FaceVerifyProperties.java
  4. 1 1
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/ApiLimitException.java
  5. 3 7
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/CommonUtils.java
  6. 1 1
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/HttpClientBuilder.java
  7. 4 13
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/IResult.java
  8. 1 1
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/JsonHelper.java
  9. 0 26
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/Constants.java
  10. 0 11
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/IModel.java
  11. 0 31
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/baidu/BaiduAccessToken.java
  12. 11 81
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/FaceVerifyService.java
  13. 136 0
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduApiHelper.java
  14. 3 7
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduFace.java
  15. 7 12
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduResponse.java
  16. 6 11
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduResult.java
  17. 3 7
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduSession.java
  18. 4 7
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduThresholds.java
  19. 94 0
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/faceplus/FacePlusApiHelper.java
  20. 3 7
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/faceplus/FacePlusFace.java
  21. 8 17
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/faceplus/FacePlusResponse.java
  22. 4 7
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/faceplus/FacePlusThresholds.java
  23. 21 324
      examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/impl/FaceVerifyServiceImpl.java
  24. 32 0
      examcloud-starters/examcloud-face-verify-starter/src/test/java/cn/com/qmth/examcloud/starters/face/verify/test/FaceVerifyTest.java

+ 5 - 0
examcloud-starters/examcloud-face-verify-starter/pom.xml

@@ -50,6 +50,11 @@
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
         </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

+ 0 - 6
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/FaceVerifyAutoConfiguration.java

@@ -4,18 +4,12 @@ import cn.com.qmth.examcloud.starters.face.verify.service.FaceVerifyService;
 import cn.com.qmth.examcloud.starters.face.verify.service.impl.FaceVerifyServiceImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
 @Configuration
 @EnableConfigurationProperties(FaceVerifyProperties.class)
-@ConditionalOnProperty(prefix = "examcloud.starters.face.verify", name = "active", havingValue = "true")
 public class FaceVerifyAutoConfiguration {
 
     private final static Logger log = LoggerFactory.getLogger(FaceVerifyAutoConfiguration.class);

+ 68 - 31
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/FaceVerifyProperties.java

@@ -5,21 +5,13 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
 import java.io.Serializable;
 
 /**
- * 人脸识别相关API配置信息
- *
- * @author: QMTH
- * @since: 2019/03/25
+ * 人脸识别相关配置信息
  */
 @ConfigurationProperties(prefix = "examcloud.starters.face.verify", ignoreUnknownFields = false)
 public class FaceVerifyProperties implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    /*
-     * 是否启用
-     */
-    private Boolean active;
-
     /*
      * Face++ API Key
      */
@@ -30,6 +22,21 @@ public class FaceVerifyProperties implements Serializable {
      */
     private String facePlusSecret;
 
+    /*
+     * Face++ 人脸检测接口
+     */
+    private String facePlusFaceDetectUrl = "https://api-cn.faceplusplus.com/facepp/v3/detect";
+
+    /*
+     * Face++ 人脸比对接口
+     */
+    private String facePlusFaceCompareUrl = "https://api-cn.faceplusplus.com/facepp/v3/compare";
+
+    /*
+     * 百度 是否启用AccessToken
+     */
+    private Boolean baiduAccessTokenEnabled = true;
+
     /*
      * 百度 API Key
      */
@@ -40,23 +47,21 @@ public class FaceVerifyProperties implements Serializable {
      */
     private String baiduSecret;
 
-    /**
-     * 短信预警手机号(多个逗号分隔)
+    /*
+     * 百度 认证接口
      */
-    private String noticePhones;
+    private String baiduTokenUrl = "https://aip.baidubce.com/oauth/2.0/token";
 
-    /**
-     * 预警短信模板
+    /*
+     * 百度 人脸检测接口
      */
-    private String smsTemplate;
+    private String baiduFaceDetectUrl = "https://aip.baidubce.com/rest/2.0/face/v3/faceverify";
+    // private String baiduFaceDetectUrl = "https://aip.baidubce.com/rest/2.0/face/v3/detect";
 
-    public Boolean getActive() {
-        return active;
-    }
-
-    public void setActive(Boolean active) {
-        this.active = active;
-    }
+    /*
+     * 百度 人脸比对接口
+     */
+    private String baiduFaceCompareUrl = "https://aip.baidubce.com/rest/2.0/face/v3/match";
 
     public String getFacePlusKey() {
         return facePlusKey;
@@ -74,6 +79,30 @@ public class FaceVerifyProperties implements Serializable {
         this.facePlusSecret = facePlusSecret;
     }
 
+    public String getFacePlusFaceDetectUrl() {
+        return facePlusFaceDetectUrl;
+    }
+
+    public void setFacePlusFaceDetectUrl(String facePlusFaceDetectUrl) {
+        this.facePlusFaceDetectUrl = facePlusFaceDetectUrl;
+    }
+
+    public String getFacePlusFaceCompareUrl() {
+        return facePlusFaceCompareUrl;
+    }
+
+    public void setFacePlusFaceCompareUrl(String facePlusFaceCompareUrl) {
+        this.facePlusFaceCompareUrl = facePlusFaceCompareUrl;
+    }
+
+    public Boolean getBaiduAccessTokenEnabled() {
+        return baiduAccessTokenEnabled;
+    }
+
+    public void setBaiduAccessTokenEnabled(Boolean baiduAccessTokenEnabled) {
+        this.baiduAccessTokenEnabled = baiduAccessTokenEnabled;
+    }
+
     public String getBaiduKey() {
         return baiduKey;
     }
@@ -90,20 +119,28 @@ public class FaceVerifyProperties implements Serializable {
         this.baiduSecret = baiduSecret;
     }
 
-    public String getNoticePhones() {
-        return noticePhones;
+    public String getBaiduTokenUrl() {
+        return baiduTokenUrl;
+    }
+
+    public void setBaiduTokenUrl(String baiduTokenUrl) {
+        this.baiduTokenUrl = baiduTokenUrl;
+    }
+
+    public String getBaiduFaceDetectUrl() {
+        return baiduFaceDetectUrl;
     }
 
-    public void setNoticePhones(String noticePhones) {
-        this.noticePhones = noticePhones;
+    public void setBaiduFaceDetectUrl(String baiduFaceDetectUrl) {
+        this.baiduFaceDetectUrl = baiduFaceDetectUrl;
     }
 
-    public String getSmsTemplate() {
-        return smsTemplate;
+    public String getBaiduFaceCompareUrl() {
+        return baiduFaceCompareUrl;
     }
 
-    public void setSmsTemplate(String smsTemplate) {
-        this.smsTemplate = smsTemplate;
+    public void setBaiduFaceCompareUrl(String baiduFaceCompareUrl) {
+        this.baiduFaceCompareUrl = baiduFaceCompareUrl;
     }
 
-}
+}

+ 1 - 1
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/exception/ApiLimitException.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/ApiLimitException.java

@@ -1,4 +1,4 @@
-package cn.com.qmth.examcloud.starters.face.verify.exception;
+package cn.com.qmth.examcloud.starters.face.verify.common;
 
 public class ApiLimitException extends RuntimeException {
 

+ 3 - 7
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/utils/StrUtils.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/CommonUtils.java

@@ -1,4 +1,4 @@
-package cn.com.qmth.examcloud.starters.face.verify.utils;
+package cn.com.qmth.examcloud.starters.face.verify.common;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
@@ -12,13 +12,9 @@ import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.nio.file.Files;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class StrUtils {
+public class CommonUtils {
 
-    private final static Logger log = LoggerFactory.getLogger(StrUtils.class);
+    private final static Logger log = LoggerFactory.getLogger(CommonUtils.class);
 
     public static String toBase64(File imageFile) {
         if (imageFile == null) {

+ 1 - 1
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/utils/HttpClientBuilder.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/HttpClientBuilder.java

@@ -1,4 +1,4 @@
-package cn.com.qmth.examcloud.starters.face.verify.utils;
+package cn.com.qmth.examcloud.starters.face.verify.common;
 
 import okhttp3.ConnectionPool;
 import okhttp3.OkHttpClient;

+ 4 - 13
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/IResult.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/IResult.java

@@ -1,20 +1,16 @@
-package cn.com.qmth.examcloud.starters.face.verify.model;
+package cn.com.qmth.examcloud.starters.face.verify.common;
 
 import java.io.Serializable;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
 public interface IResult extends Serializable {
 
     /**
-     * 是否人脸活体检测通过
+     * 是否人脸检测通过
      */
     boolean isDetectPass();
 
     /**
-     * 是否人脸识别对比通过
+     * 是否人脸对比通过
      */
     boolean isComparePass();
 
@@ -38,9 +34,4 @@ public interface IResult extends Serializable {
      */
     boolean requestOutOfLimit();
 
-    /**
-     * Token是否过期
-     */
-    boolean isTokenExpired();
-
-}
+}

+ 1 - 1
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/utils/JsonHelper.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/common/JsonHelper.java

@@ -1,4 +1,4 @@
-package cn.com.qmth.examcloud.starters.face.verify.utils;
+package cn.com.qmth.examcloud.starters.face.verify.common;
 
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.databind.DeserializationFeature;

+ 0 - 26
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/Constants.java

@@ -1,26 +0,0 @@
-package cn.com.qmth.examcloud.starters.face.verify.model;
-
-/**
- * 人脸照片处理接口地址前缀常量定义(待移至配置文件内)
- *
- * @author: QMTH
- * @since: 2019/3/25
- */
-public interface Constants {
-
-    /* 百度 获取Token API */
-    String BAI_DU_TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s";
-
-    /* 百度 人脸活体检测API */
-    String BAI_DU_DETECT_FACE_URL = "https://aip.baidubce.com/rest/2.0/face/v3/faceverify?access_token=%s";
-
-    /* 百度 人脸检测API(可检测人脸数) */
-    String BAIDU_DETECT_FACE_WITH_FACE_SIZE_URL = "https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=%s";
-
-    /* Face++ 人脸识别对比API */
-    String FACE_PLUS_COMPARE_FACE_URL = "https://api-cn.faceplusplus.com/facepp/v3/compare";
-
-    /* Face++ 人脸的活体检测API(可检测人脸数) */
-    String FACE_PLUS_DETECT_FACE_URL = "https://api-cn.faceplusplus.com/facepp/v3/detect";
-
-}

+ 0 - 11
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/IModel.java

@@ -1,11 +0,0 @@
-package cn.com.qmth.examcloud.starters.face.verify.model;
-
-import java.io.Serializable;
-
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public interface IModel extends Serializable {
-
-}

+ 0 - 31
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/baidu/BaiduAccessToken.java

@@ -1,31 +0,0 @@
-package cn.com.qmth.examcloud.starters.face.verify.model.baidu;
-
-import cn.com.qmth.examcloud.starters.face.verify.model.IModel;
-
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class BaiduAccessToken implements IModel {
-
-    private static final long serialVersionUID = 1L;
-
-    private static String TOKEN = null;
-
-    public static String getValue() {
-        return TOKEN;
-    }
-
-    public static void setValue(String value) {
-        TOKEN = value;
-    }
-
-    public static boolean isNotEmpty() {
-        if (TOKEN != null && TOKEN.length() > 0) {
-            return true;
-        }
-
-        return false;
-    }
-
-}

+ 11 - 81
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/FaceVerifyService.java

@@ -1,97 +1,27 @@
 package cn.com.qmth.examcloud.starters.face.verify.service;
 
-import cn.com.qmth.examcloud.starters.face.verify.model.IResult;
+import cn.com.qmth.examcloud.starters.face.verify.common.IResult;
 
-import java.io.File;
-import java.io.Serializable;
-
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public interface FaceVerifyService extends Serializable {
-
-    /**
-     * 执行百度的人脸的活体检测
-     *
-     * @param targetImageUrl 图片访问链接
-     * @return
-     */
-    IResult detectFaceByBaidu(String targetImageUrl);
-
-    /**
-     * 执行百度的人脸的活体检测
-     *
-     * @param imageFileBytes 图片文件流
-     * @return
-     */
-    IResult detectFaceByBaidu(byte[] imageFileBytes);
-
-    /**
-     * 执行百度的人脸的活体检测
-     *
-     * @param targetImageFile 图片文件
-     * @return
-     */
-    IResult detectFaceByBaidu(File targetImageFile);
-
-    /**
-     * 执行百度的人脸的检测(可检测人脸数)
-     *
-     * @param targetImageFile 图片文件
-     * @return
-     */
-    IResult detectFaceWithFaceSizeByBaidu(File targetImageFile);
-
-    /**
-     * 执行百度的人脸的检测(可检测人脸数)
-     *
-     * @param imageFileBytes 图片文件流
-     * @return
-     */
-    IResult detectFaceWithFaceSizeByBaidu(byte[] imageFileBytes);
-
-    /**
-     * 执行Face++的人脸的活体检测
-     *
-     * @param targetImageFile 图片文件
-     * @return
-     */
-    IResult detectFaceByFacePlus(File targetImageFile);
+public interface FaceVerifyService {
 
     /**
-     * 执行Face++的人脸的活体检测
-     *
-     * @param imageFileBytes 文件流
-     * @param imageFileName  文件名
-     * @return
+     * 百度 人脸检测
      */
-    IResult detectFaceByFacePlus(byte[] imageFileBytes, String imageFileName);
+    IResult faceDetectByBaidu(String imageUrl);
 
     /**
-     * 执行Face++的人脸识别对比
-     *
-     * @param sourceImageUrl 底照访问链接
-     * @param targetImageUrl 抓拍照访问链接
-     * @return
+     * 百度 人脸比对
      */
-    IResult compareFaceByFacePlus(String sourceImageUrl, String targetImageUrl);
+    IResult faceCompareByBaidu(String imageUrl, String imageUrl2);
 
     /**
-     * 执行Face++的人脸识别对比
-     *
-     * @param sourceImageFile 底照文件
-     * @param targetImageFile 抓拍照文件
+     * Face++ 人脸检测
      */
-    IResult compareFaceByFacePlus(File sourceImageFile, File targetImageFile);
+    IResult faceDetectByFacePlus(String imageUrl);
 
     /**
-     * 执行Face++的人脸识别对比
-     *
-     * @param sourceImageUrl  底照访问链接
-     * @param targetImageFile 抓拍照文件
-     * @return
+     * Face++ 人脸比对
      */
-    IResult compareFaceByFacePlus(String sourceImageUrl, File targetImageFile);
+    IResult faceCompareByFacePlus(String imageUrl, String imageUrl2);
 
-}
+}

+ 136 - 0
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduApiHelper.java

@@ -0,0 +1,136 @@
+package cn.com.qmth.examcloud.starters.face.verify.service.baidu;
+
+import cn.com.qmth.examcloud.starters.face.verify.common.HttpClientBuilder;
+import cn.com.qmth.examcloud.starters.face.verify.common.JsonHelper;
+import okhttp3.*;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class BaiduApiHelper {
+
+    private final static Logger log = LoggerFactory.getLogger(BaiduApiHelper.class);
+
+    public static BaiduSession getAccessToken(String apiKey, String apiSecret, String apiUrl) {
+        if (StringUtils.isBlank(apiKey)) {
+            throw new IllegalArgumentException("Baidu apiKey must be not empty.");
+        }
+
+        if (StringUtils.isBlank(apiSecret)) {
+            throw new IllegalArgumentException("Baidu apiSecret must be not empty.");
+        }
+
+        if (StringUtils.isBlank(apiUrl)) {
+            throw new IllegalArgumentException("Baidu apiUrl must be not empty.");
+        }
+
+        String requestUrl = String.format("%s?grant_type=client_credentials&client_id=%s&client_secret=%s", apiUrl, apiKey, apiSecret);
+        Request.Builder request = new Request.Builder().url(requestUrl).get();
+
+        BaiduSession result = null;
+        try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
+             ResponseBody body = response.body();) {
+            String bodyStr = body.string();
+
+            if (response.isSuccessful()) {
+                result = new JsonHelper().parseJson(bodyStr, BaiduSession.class);
+            } else {
+                log.warn("[baidu] url:{} response:{} body:{}", requestUrl, response.code(), bodyStr);
+            }
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+
+        if (result == null) {
+            throw new RuntimeException("获取 Baidu AccessToken 失败!");
+        }
+
+        return result;
+    }
+
+    public static BaiduResponse faceDetect(String accessToken, String apiUrl, String imageUrl) {
+        if (StringUtils.isBlank(apiUrl)) {
+            throw new IllegalArgumentException("Baidu apiUrl must be not empty.");
+        }
+
+        if (StringUtils.isBlank(imageUrl)) {
+            throw new IllegalArgumentException("face imageUrl must be not empty.");
+        }
+
+        String requestUrl = String.format("%s?access_token=%s", apiUrl, accessToken);
+
+        List<Map<String, String>> params = new ArrayList<>();
+        Map<String, String> imageData = new TreeMap<>();
+        // imageData.put("image_type", "BASE64");
+        imageData.put("image_type", "URL");
+        imageData.put("image", imageUrl);
+        params.add(imageData);
+        String jsonParams = new JsonHelper().toJson(params);
+
+        final String contentType = "application/json; charset=utf-8";
+        RequestBody formBody = FormBody.create(MediaType.parse(contentType), jsonParams);
+        Request.Builder request = new Request.Builder().url(requestUrl).post(formBody);
+
+        return callApi(apiUrl, request);
+    }
+
+    public static BaiduResponse faceCompare(String accessToken, String apiUrl, String imageUrl, String imageUrl2) {
+        if (StringUtils.isBlank(apiUrl)) {
+            throw new IllegalArgumentException("Baidu apiUrl must be not empty.");
+        }
+
+        if (StringUtils.isBlank(imageUrl)) {
+            throw new IllegalArgumentException("face imageUrl must be not empty.");
+        }
+
+        if (StringUtils.isBlank(imageUrl2)) {
+            throw new IllegalArgumentException("face imageUrl2 must be not empty.");
+        }
+
+        String requestUrl = String.format("%s?access_token=%s", apiUrl, accessToken);
+
+        List<Map<String, String>> params = new ArrayList<>();
+        Map<String, String> imageData = new TreeMap<>();
+        imageData.put("image_type", "URL");
+        imageData.put("image", imageUrl);
+        params.add(imageData);
+        Map<String, String> imageData2 = new TreeMap<>();
+        imageData2.put("image_type", "URL");
+        imageData2.put("image", imageUrl2);
+        params.add(imageData2);
+        String jsonParams = new JsonHelper().toJson(params);
+
+        final String contentType = "application/json; charset=utf-8";
+        RequestBody formBody = FormBody.create(MediaType.parse(contentType), jsonParams);
+        Request.Builder request = new Request.Builder().url(requestUrl).post(formBody);
+
+        return callApi(apiUrl, request);
+    }
+
+    private static BaiduResponse callApi(String apiUrl, Request.Builder request) {
+        BaiduResponse result = null;
+        try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
+             ResponseBody body = response.body();) {
+            String bodyStr = body.string();
+
+            System.out.println(bodyStr);
+
+            if (response.isSuccessful()) {
+                result = new JsonHelper().parseJson(bodyStr, BaiduResponse.class);
+            } else {
+                log.warn("[baidu] url:{} response:{} body:{}", apiUrl, response.code(), bodyStr);
+            }
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+
+        return result;
+    }
+
+}

+ 3 - 7
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/baidu/BaiduFaceInfo.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduFace.java

@@ -1,12 +1,8 @@
-package cn.com.qmth.examcloud.starters.face.verify.model.baidu;
+package cn.com.qmth.examcloud.starters.face.verify.service.baidu;
 
-import cn.com.qmth.examcloud.starters.face.verify.model.IModel;
+import java.io.Serializable;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class BaiduFaceInfo implements IModel {
+public class BaiduFace implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 7 - 12
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/baidu/BaiduResponseInfo.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduResponse.java

@@ -1,13 +1,9 @@
-package cn.com.qmth.examcloud.starters.face.verify.model.baidu;
+package cn.com.qmth.examcloud.starters.face.verify.service.baidu;
 
-import cn.com.qmth.examcloud.starters.face.verify.model.IResult;
-import cn.com.qmth.examcloud.starters.face.verify.utils.JsonHelper;
+import cn.com.qmth.examcloud.starters.face.verify.common.IResult;
+import cn.com.qmth.examcloud.starters.face.verify.common.JsonHelper;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class BaiduResponseInfo implements IResult {
+public class BaiduResponse implements IResult {
 
     private static final long serialVersionUID = 1L;
 
@@ -17,7 +13,7 @@ public class BaiduResponseInfo implements IResult {
 
     private Long log_id;
 
-    private BaiduResultInfo result;
+    private BaiduResult result;
 
     @Override
     public boolean isDetectPass() {
@@ -70,7 +66,6 @@ public class BaiduResponseInfo implements IResult {
         return false;
     }
 
-    @Override
     public boolean isTokenExpired() {
         // Token默认有效期为30天
         if (getError_code() == 110 || getError_code() == 111) {
@@ -109,11 +104,11 @@ public class BaiduResponseInfo implements IResult {
         this.log_id = log_id;
     }
 
-    public BaiduResultInfo getResult() {
+    public BaiduResult getResult() {
         return result;
     }
 
-    public void setResult(BaiduResultInfo result) {
+    public void setResult(BaiduResult result) {
         this.result = result;
     }
 

+ 6 - 11
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/baidu/BaiduResultInfo.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduResult.java

@@ -1,14 +1,9 @@
-package cn.com.qmth.examcloud.starters.face.verify.model.baidu;
-
-import cn.com.qmth.examcloud.starters.face.verify.model.IModel;
+package cn.com.qmth.examcloud.starters.face.verify.service.baidu;
 
+import java.io.Serializable;
 import java.util.List;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class BaiduResultInfo implements IModel {
+public class BaiduResult implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
@@ -16,7 +11,7 @@ public class BaiduResultInfo implements IModel {
 
     private Integer face_num;//人脸数
 
-    private List<BaiduFaceInfo> face_list;//人脸信息列表
+    private List<BaiduFace> face_list;//人脸信息列表
 
     private BaiduThresholds thresholds;//置信度阈值(误识率越低,准确率越高)
 
@@ -34,7 +29,7 @@ public class BaiduResultInfo implements IModel {
         return face_num;
     }
 
-    public List<BaiduFaceInfo> getFace_list() {
+    public List<BaiduFace> getFace_list() {
         return face_list;
     }
 
@@ -50,7 +45,7 @@ public class BaiduResultInfo implements IModel {
         this.face_num = face_num;
     }
 
-    public void setFace_list(List<BaiduFaceInfo> face_list) {
+    public void setFace_list(List<BaiduFace> face_list) {
         this.face_list = face_list;
     }
 

+ 3 - 7
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/baidu/BaiduAccessInfo.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduSession.java

@@ -1,12 +1,8 @@
-package cn.com.qmth.examcloud.starters.face.verify.model.baidu;
+package cn.com.qmth.examcloud.starters.face.verify.service.baidu;
 
-import cn.com.qmth.examcloud.starters.face.verify.model.IModel;
+import java.io.Serializable;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class BaiduAccessInfo implements IModel {
+public class BaiduSession implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 4 - 7
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/baidu/BaiduThresholds.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/baidu/BaiduThresholds.java

@@ -1,13 +1,10 @@
-package cn.com.qmth.examcloud.starters.face.verify.model.baidu;
+package cn.com.qmth.examcloud.starters.face.verify.service.baidu;
 
-import cn.com.qmth.examcloud.starters.face.verify.model.IModel;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class BaiduThresholds implements IModel {
+import java.io.Serializable;
+
+public class BaiduThresholds implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 94 - 0
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/faceplus/FacePlusApiHelper.java

@@ -0,0 +1,94 @@
+package cn.com.qmth.examcloud.starters.face.verify.service.faceplus;
+
+import cn.com.qmth.examcloud.starters.face.verify.common.HttpClientBuilder;
+import cn.com.qmth.examcloud.starters.face.verify.common.JsonHelper;
+import okhttp3.*;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public class FacePlusApiHelper {
+
+    private final static Logger log = LoggerFactory.getLogger(FacePlusApiHelper.class);
+
+    public static FacePlusResponse faceDetect(String apiKey, String apiSecret, String apiUrl, String imageUrl) {
+        if (StringUtils.isBlank(apiKey)) {
+            throw new IllegalArgumentException("Face++ apiKey must be not empty.");
+        }
+
+        if (StringUtils.isBlank(apiSecret)) {
+            throw new IllegalArgumentException("Face++ apiSecret must be not empty.");
+        }
+
+        if (StringUtils.isBlank(apiUrl)) {
+            throw new IllegalArgumentException("Face++ apiUrl must be not empty.");
+        }
+
+        if (StringUtils.isBlank(imageUrl)) {
+            throw new IllegalArgumentException("face imageUrl must be not empty.");
+        }
+
+        MultipartBody.Builder formBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
+                .addFormDataPart("api_key", apiKey)
+                .addFormDataPart("api_secret", apiSecret)
+                .addFormDataPart("image_url", imageUrl);
+        Request.Builder request = new Request.Builder().url(apiUrl).post(formBody.build());
+
+        return callApi(apiUrl, request);
+    }
+
+    public static FacePlusResponse faceCompare(String apiKey, String apiSecret, String apiUrl, String imageUrl, String imageUrl2) {
+        if (StringUtils.isBlank(apiKey)) {
+            throw new IllegalArgumentException("Face++ apiKey must be not empty.");
+        }
+
+        if (StringUtils.isBlank(apiSecret)) {
+            throw new IllegalArgumentException("Face++ apiSecret must be not empty.");
+        }
+
+        if (StringUtils.isBlank(apiUrl)) {
+            throw new IllegalArgumentException("Face++ apiUrl must be not empty.");
+        }
+
+        if (StringUtils.isBlank(imageUrl)) {
+            throw new IllegalArgumentException("face imageUrl must be not empty.");
+        }
+
+        if (StringUtils.isBlank(imageUrl2)) {
+            throw new IllegalArgumentException("face imageUrl2 must be not empty.");
+        }
+
+        RequestBody formBody = new FormBody.Builder()
+                .add("api_key", apiKey)
+                .add("api_secret", apiSecret)
+                .add("image_url1", imageUrl)
+                .add("image_url2", imageUrl2)
+                .build();
+        Request.Builder request = new Request.Builder().url(apiUrl).post(formBody);
+
+        return callApi(apiUrl, request);
+    }
+
+    private static FacePlusResponse callApi(String apiUrl, Request.Builder request) {
+        FacePlusResponse result = null;
+        try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
+             ResponseBody body = response.body();) {
+            String bodyStr = body.string();
+
+            System.out.println(bodyStr);
+
+            if (response.code() == 403 || response.isSuccessful()) {
+                result = new JsonHelper().parseJson(bodyStr, FacePlusResponse.class);
+            } else {
+                log.warn("[Face++] url:{} response:{} body:{}", apiUrl, response.code(), bodyStr);
+            }
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+
+        return result;
+    }
+
+}

+ 3 - 7
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/faceplus/FacePlusFaceInfo.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/faceplus/FacePlusFace.java

@@ -1,12 +1,8 @@
-package cn.com.qmth.examcloud.starters.face.verify.model.faceplus;
+package cn.com.qmth.examcloud.starters.face.verify.service.faceplus;
 
-import cn.com.qmth.examcloud.starters.face.verify.model.IModel;
+import java.io.Serializable;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class FacePlusFaceInfo implements IModel {
+public class FacePlusFace implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 8 - 17
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/faceplus/FacePlusResponseInfo.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/faceplus/FacePlusResponse.java

@@ -1,21 +1,17 @@
-package cn.com.qmth.examcloud.starters.face.verify.model.faceplus;
+package cn.com.qmth.examcloud.starters.face.verify.service.faceplus;
 
-import cn.com.qmth.examcloud.starters.face.verify.model.IResult;
-import cn.com.qmth.examcloud.starters.face.verify.utils.JsonHelper;
+import cn.com.qmth.examcloud.starters.face.verify.common.IResult;
+import cn.com.qmth.examcloud.starters.face.verify.common.JsonHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.List;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class FacePlusResponseInfo implements IResult {
+public class FacePlusResponse implements IResult {
 
     private static final long serialVersionUID = 1L;
 
-    private static Logger log = LoggerFactory.getLogger(FacePlusResponseInfo.class);
+    private static Logger log = LoggerFactory.getLogger(FacePlusResponse.class);
 
     private String request_id;
 
@@ -29,7 +25,7 @@ public class FacePlusResponseInfo implements IResult {
 
     private String image_id;
 
-    private List<FacePlusFaceInfo> faces;
+    private List<FacePlusFace> faces;
 
     @Override
     public boolean isDetectPass() {
@@ -91,11 +87,6 @@ public class FacePlusResponseInfo implements IResult {
         return false;
     }
 
-    @Override
-    public boolean isTokenExpired() {
-        return false;//ignore
-    }
-
     public String getRequest_id() {
         return request_id;
     }
@@ -144,11 +135,11 @@ public class FacePlusResponseInfo implements IResult {
         this.image_id = image_id;
     }
 
-    public List<FacePlusFaceInfo> getFaces() {
+    public List<FacePlusFace> getFaces() {
         return faces;
     }
 
-    public void setFaces(List<FacePlusFaceInfo> faces) {
+    public void setFaces(List<FacePlusFace> faces) {
         this.faces = faces;
     }
 

+ 4 - 7
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/model/faceplus/FacePlusThresholds.java → examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/faceplus/FacePlusThresholds.java

@@ -1,13 +1,10 @@
-package cn.com.qmth.examcloud.starters.face.verify.model.faceplus;
+package cn.com.qmth.examcloud.starters.face.verify.service.faceplus;
 
-import cn.com.qmth.examcloud.starters.face.verify.model.IModel;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
-public class FacePlusThresholds implements IModel {
+import java.io.Serializable;
+
+public class FacePlusThresholds implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 21 - 324
examcloud-starters/examcloud-face-verify-starter/src/main/java/cn/com/qmth/examcloud/starters/face/verify/service/impl/FaceVerifyServiceImpl.java

@@ -1,37 +1,14 @@
 package cn.com.qmth.examcloud.starters.face.verify.service.impl;
 
 import cn.com.qmth.examcloud.starters.face.verify.FaceVerifyProperties;
-import cn.com.qmth.examcloud.starters.face.verify.model.IResult;
-import cn.com.qmth.examcloud.starters.face.verify.model.baidu.BaiduAccessInfo;
-import cn.com.qmth.examcloud.starters.face.verify.model.baidu.BaiduAccessToken;
-import cn.com.qmth.examcloud.starters.face.verify.model.baidu.BaiduResponseInfo;
-import cn.com.qmth.examcloud.starters.face.verify.model.faceplus.FacePlusResponseInfo;
+import cn.com.qmth.examcloud.starters.face.verify.common.IResult;
 import cn.com.qmth.examcloud.starters.face.verify.service.FaceVerifyService;
-import cn.com.qmth.examcloud.starters.face.verify.utils.HttpClientBuilder;
-import cn.com.qmth.examcloud.starters.face.verify.utils.JsonHelper;
-import cn.com.qmth.examcloud.starters.face.verify.utils.StrUtils;
-import okhttp3.*;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
+import cn.com.qmth.examcloud.starters.face.verify.service.baidu.BaiduApiHelper;
+import cn.com.qmth.examcloud.starters.face.verify.service.baidu.BaiduSession;
+import cn.com.qmth.examcloud.starters.face.verify.service.faceplus.FacePlusApiHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.util.Base64Utils;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import static cn.com.qmth.examcloud.starters.face.verify.model.Constants.*;
-
-/**
- * @author: QMTH
- * @since: 2019/3/25
- */
 public class FaceVerifyServiceImpl implements FaceVerifyService {
 
     private final static Logger log = LoggerFactory.getLogger(FaceVerifyServiceImpl.class);
@@ -39,319 +16,39 @@ public class FaceVerifyServiceImpl implements FaceVerifyService {
     private FaceVerifyProperties properties;
 
     @Override
-    public IResult detectFaceByBaidu(String targetImageUrl) {
-        String accessToken = this.getAccessTokenByBaidu();
-        return this.detectFaceByBaidu(accessToken, targetImageUrl, false);
-    }
-
-    @Override
-    public IResult detectFaceByBaidu(byte[] imageFileBytes) {
-        String accessToken = this.getAccessTokenByBaidu();
-        String base64 = Base64Utils.encodeToString(imageFileBytes);
-        return this.detectFaceByBaidu(accessToken, base64, true);
-    }
-
-    @Override
-    public IResult detectFaceByBaidu(File targetImageFile) {
-        String accessToken = this.getAccessTokenByBaidu();
-        String base64 = StrUtils.toBase64(targetImageFile);
-        return this.detectFaceByBaidu(accessToken, base64, true);
-    }
-
-    private IResult detectFaceByBaidu(String accessToken, String targetImage, boolean isBases64) {
-        if (StringUtils.isBlank(accessToken)) {
-            throw new IllegalArgumentException("Baidu accessToken must be not empty.");
-        }
-
-        if (StringUtils.isBlank(targetImage)) {
-            throw new IllegalArgumentException("targetImage must be not empty.");
-        }
-
-        List params = new ArrayList();
-        Map<String, String> values = new TreeMap<>();
-        if (isBases64) {
-            values.put("image_type", "BASE64");
-        } else {
-            values.put("image_type", "URL");
-        }
-        values.put("image", targetImage);
-        params.add(values);
-
-        JsonHelper jsonMapper = new JsonHelper();
-        String jsonParams = jsonMapper.toJson(params);
-
-        String requestUrl = String.format(BAI_DU_DETECT_FACE_URL, accessToken);
-        IResult result = this.callForBaidu(jsonMapper, jsonParams, requestUrl);
-
-        if (result != null && result.isTokenExpired()) {
-            //Token过期,则重刷
-            accessToken = refreshAccessTokenByBaidu();
-            requestUrl = String.format(BAI_DU_DETECT_FACE_URL, accessToken);
-            return this.callForBaidu(jsonMapper, jsonParams, requestUrl);
-        }
-
-        return result;
-    }
-
-    @Override
-    public IResult detectFaceWithFaceSizeByBaidu(File targetImageFile) {
-        if (targetImageFile == null) {
-            throw new IllegalArgumentException("targetImageFile must be not empty.");
-        }
-
-        byte[] targetBytes;
-        try (InputStream targetStream = new FileInputStream(targetImageFile);) {
-            targetBytes = IOUtils.toByteArray(targetStream);
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-            return null;
-        }
-
-        return this.detectFaceWithFaceSizeByBaidu(targetBytes);
-    }
-
-    @Override
-    public IResult detectFaceWithFaceSizeByBaidu(byte[] imageFileBytes) {
-        String accessToken = this.getAccessTokenByBaidu();
-        String base64 = Base64Utils.encodeToString(imageFileBytes);
-        Map<String, String> params = new TreeMap<>();
-        params.put("max_face_num", "2");// 最多处理人脸的数目(默认值为1)
-        params.put("image_type", "BASE64");
-        params.put("image", base64);
-
-        JsonHelper jsonMapper = new JsonHelper();
-        String jsonParams = jsonMapper.toJson(params);
-
-        String requestUrl = String.format(BAIDU_DETECT_FACE_WITH_FACE_SIZE_URL, accessToken);
-        IResult result = this.callForBaidu(jsonMapper, jsonParams, requestUrl);
-
-        if (result != null && result.isTokenExpired()) {
-            //Token过期,则重刷
-            accessToken = this.refreshAccessTokenByBaidu();
-            requestUrl = String.format(BAIDU_DETECT_FACE_WITH_FACE_SIZE_URL, accessToken);
-            return this.callForBaidu(jsonMapper, jsonParams, requestUrl);
-        }
-
-        return result;
-    }
-
-    private String getAccessTokenByBaidu() {
-        if (BaiduAccessToken.isNotEmpty()) {
-            return BaiduAccessToken.getValue();
-        }
-
-        BaiduAccessInfo info = this.loadAccessTokenByBaidu();
-        if (info == null || info.getAccess_token() == null) {
-            throw new IllegalArgumentException("Baidu loadAccessToken fail.");
-        }
-
-        BaiduAccessToken.setValue(info.getAccess_token());
-        return info.getAccess_token();
-    }
-
-    private String refreshAccessTokenByBaidu() {
-        BaiduAccessToken.setValue(null);
-        return this.getAccessTokenByBaidu();
-    }
-
-    private BaiduAccessInfo loadAccessTokenByBaidu() {
-        if (StringUtils.isBlank(properties.getBaiduKey()) || StringUtils.isBlank(properties.getBaiduSecret())) {
-            throw new IllegalArgumentException("Baidu apiKey or apiSecret must be not empty.");
-        }
-
-        String requestUrl = String.format(BAI_DU_TOKEN_URL, properties.getBaiduKey(), properties.getBaiduSecret());
-        Request.Builder request = new Request.Builder().url(requestUrl).get();
-
-        try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
-             ResponseBody body = response.body();) {
-            String bodyStr = body.string();
-
-            if (log.isDebugEnabled()) {
-                log.debug("[response] code: " + response.code() + " body: " + bodyStr);
-            }
-
-            if (response.isSuccessful()) {
-                return new JsonHelper().parseJson(bodyStr, BaiduAccessInfo.class);
-            }
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        }
-        return null;
-    }
-
-    private BaiduResponseInfo callForBaidu(JsonHelper jsonMapper, String jsonParams, String requestUrl) {
-        final String contentType = "application/json; charset=utf-8";
-        RequestBody formBody = FormBody.create(MediaType.parse(contentType), jsonParams);
-        Request.Builder request = new Request.Builder().url(requestUrl).post(formBody);
-
-        try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
-             ResponseBody body = response.body();) {
-            String bodyStr = body.string();
-
-            if (log.isDebugEnabled()) {
-                log.debug("[response] code: " + response.code() + " body: " + bodyStr);
-            }
-
-            if (response.isSuccessful()) {
-                return jsonMapper.parseJson(bodyStr, BaiduResponseInfo.class);
-            }
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        }
-        return null;
-    }
-
-
-    @Override
-    public IResult detectFaceByFacePlus(File targetImageFile) {
-        if (targetImageFile == null) {
-            throw new IllegalArgumentException("targetImageFile must be not empty.");
+    public IResult faceDetectByBaidu(String imageUrl) {
+        String accessToken = null;
+        if (properties.getBaiduAccessTokenEnabled()) {
+            BaiduSession session = BaiduApiHelper.getAccessToken(properties.getBaiduKey(), properties.getBaiduSecret(), properties.getBaiduTokenUrl());
+            accessToken = session.getAccess_token();
         }
 
-        byte[] targetBytes;
-        try (InputStream targetStream = new FileInputStream(targetImageFile);) {
-            targetBytes = IOUtils.toByteArray(targetStream);
-        } catch (IOException e) {
-            log.error(e.getMessage());
-            return null;
-        }
-
-        return this.detectFaceByFacePlus(targetBytes, targetImageFile.getName());
+        return BaiduApiHelper.faceDetect(accessToken, properties.getBaiduFaceDetectUrl(), imageUrl);
     }
 
     @Override
-    public IResult detectFaceByFacePlus(byte[] imageFileBytes, String imageFileName) {
-        if (StringUtils.isBlank(properties.getFacePlusKey()) || StringUtils.isBlank(properties.getFacePlusSecret())) {
-            throw new IllegalArgumentException("Face++ apiKey or apiSecret must be not empty.");
-        }
-
-        if (imageFileBytes == null || imageFileBytes.length == 0) {
-            throw new IllegalArgumentException("fileBytes must be not empty.");
+    public IResult faceCompareByBaidu(String imageUrl, String imageUrl2) {
+        String accessToken = null;
+        if (properties.getBaiduAccessTokenEnabled()) {
+            BaiduSession session = BaiduApiHelper.getAccessToken(properties.getBaiduKey(), properties.getBaiduSecret(), properties.getBaiduTokenUrl());
+            accessToken = session.getAccess_token();
         }
 
-        if (log.isDebugEnabled()) {
-            log.debug("[request] " + FACE_PLUS_DETECT_FACE_URL + " imageFileName: " + imageFileName);
-        }
-
-        RequestBody targetBody = RequestBody.create(MediaType.parse("application/octet-stream"), imageFileBytes);
-        MultipartBody.Builder formBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
-                .addFormDataPart("api_key", properties.getFacePlusKey())
-                .addFormDataPart("api_secret", properties.getFacePlusSecret())
-                .addFormDataPart("image_file", StrUtils.urlEncode(imageFileName), targetBody);
-        return callForFacePlus(FACE_PLUS_DETECT_FACE_URL, formBody.build());
+        return BaiduApiHelper.faceCompare(accessToken, properties.getBaiduFaceCompareUrl(), imageUrl, imageUrl2);
     }
 
     @Override
-    public IResult compareFaceByFacePlus(String sourceImageUrl, String targetImageUrl) {
-        if (StringUtils.isBlank(properties.getFacePlusKey()) || StringUtils.isBlank(properties.getFacePlusSecret())) {
-            throw new IllegalArgumentException("Face++ apiKey or apiSecret must be not empty.");
-        }
-
-        if (StringUtils.isBlank(sourceImageUrl) || StringUtils.isBlank(targetImageUrl)) {
-            throw new IllegalArgumentException("sourceImageUrl or targetImageUrl must be not empty.");
-        }
-
-        if (log.isDebugEnabled()) {
-            log.debug("[request] " + FACE_PLUS_COMPARE_FACE_URL + " sourceImageUrl: " + sourceImageUrl + " targetImageUrl: " + targetImageUrl);
-        }
-
-        RequestBody formBody = new FormBody.Builder()
-                .add("api_key", properties.getFacePlusKey())
-                .add("api_secret", properties.getFacePlusSecret())
-                .add("image_url1", sourceImageUrl)
-                .add("image_url2", targetImageUrl)
-                .build();
-        return callForFacePlus(FACE_PLUS_COMPARE_FACE_URL, formBody);
+    public IResult faceDetectByFacePlus(String imageUrl) {
+        return FacePlusApiHelper.faceDetect(properties.getFacePlusKey(), properties.getFacePlusSecret(), properties.getFacePlusFaceDetectUrl(), imageUrl);
     }
 
     @Override
-    public IResult compareFaceByFacePlus(File sourceImageFile, File targetImageFile) {
-        if (StringUtils.isBlank(properties.getFacePlusKey()) || StringUtils.isBlank(properties.getFacePlusSecret())) {
-            throw new IllegalArgumentException("Face++ apiKey or apiSecret must be not empty.");
-        }
-
-        if (sourceImageFile == null || targetImageFile == null) {
-            throw new IllegalArgumentException("sourceImageFile or targetImageFile must be not empty.");
-        }
-
-        if (log.isDebugEnabled()) {
-            log.debug("[request] " + FACE_PLUS_COMPARE_FACE_URL + " sourceImageFile: " + sourceImageFile.getName() + " targetImageFile: " + targetImageFile.getName());
-        }
-
-        byte[] sourceBytes, targetBytes;
-        try (InputStream sourceStream = new FileInputStream(sourceImageFile);
-             InputStream targetStream = new FileInputStream(targetImageFile);) {
-            sourceBytes = IOUtils.toByteArray(sourceStream);
-            targetBytes = IOUtils.toByteArray(targetStream);
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-            return null;
-        }
-
-        RequestBody sourceBody = RequestBody.create(MediaType.parse("application/octet-stream"), sourceBytes);
-        RequestBody targetBody = RequestBody.create(MediaType.parse("application/octet-stream"), targetBytes);
-        MultipartBody.Builder formBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
-                .addFormDataPart("api_key", properties.getFacePlusKey())
-                .addFormDataPart("api_secret", properties.getFacePlusSecret())
-                .addFormDataPart("image_file1", StrUtils.urlEncode(sourceImageFile.getName()), sourceBody)
-                .addFormDataPart("image_file2", StrUtils.urlEncode(targetImageFile.getName()), targetBody);
-        return callForFacePlus(FACE_PLUS_COMPARE_FACE_URL, formBody.build());
-    }
-
-    @Override
-    public IResult compareFaceByFacePlus(String sourceImageUrl, File targetImageFile) {
-        if (StringUtils.isBlank(properties.getFacePlusKey()) || StringUtils.isBlank(properties.getFacePlusSecret())) {
-            throw new IllegalArgumentException("Face++ apiKey or apiSecret must be not empty.");
-        }
-
-        if (StringUtils.isBlank(sourceImageUrl) || targetImageFile == null) {
-            throw new IllegalArgumentException("sourceImageUrl or targetImageFile must be not empty.");
-        }
-
-        if (log.isDebugEnabled()) {
-            log.debug("[request] " + FACE_PLUS_COMPARE_FACE_URL + " sourceImageUrl: " + sourceImageUrl + " targetImageFile: " + targetImageFile.getName());
-        }
-
-        byte[] targetBytes;
-        try (InputStream targetStream = new FileInputStream(targetImageFile);) {
-            targetBytes = IOUtils.toByteArray(targetStream);
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-            return null;
-        }
-
-        RequestBody targetBody = RequestBody.create(MediaType.parse("application/octet-stream"), targetBytes);
-        MultipartBody.Builder formBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
-                .addFormDataPart("api_key", properties.getFacePlusKey())
-                .addFormDataPart("api_secret", properties.getFacePlusSecret())
-                .addFormDataPart("image_url1", sourceImageUrl)
-                .addFormDataPart("image_file2", StrUtils.urlEncode(targetImageFile.getName()), targetBody);
-        return callForFacePlus(FACE_PLUS_COMPARE_FACE_URL, formBody.build());
-    }
-
-    private FacePlusResponseInfo callForFacePlus(String url, RequestBody formBody) {
-        Request.Builder request = new Request.Builder().url(url).post(formBody);
-
-        try (Response response = HttpClientBuilder.getClient().newCall(request.build()).execute();
-             ResponseBody body = response.body();) {
-            String bodyStr = body.string();
-
-            if (log.isDebugEnabled()) {
-                log.debug("[response] code: " + response.code() + " body: " + bodyStr);
-            }
-
-            //403有并发超限情况
-            if (response.code() == 403 || response.isSuccessful()) {
-                return new JsonHelper().parseJson(bodyStr, FacePlusResponseInfo.class);
-            }
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-        }
-        return null;
+    public IResult faceCompareByFacePlus(String imageUrl, String imageUrl2) {
+        return FacePlusApiHelper.faceCompare(properties.getFacePlusKey(), properties.getFacePlusSecret(), properties.getFacePlusFaceCompareUrl(), imageUrl, imageUrl2);
     }
 
     public void setProperties(FaceVerifyProperties properties) {
         this.properties = properties;
     }
 
-}
+}

+ 32 - 0
examcloud-starters/examcloud-face-verify-starter/src/test/java/cn/com/qmth/examcloud/starters/face/verify/test/FaceVerifyTest.java

@@ -0,0 +1,32 @@
+package cn.com.qmth.examcloud.starters.face.verify.test;
+
+import cn.com.qmth.examcloud.starters.face.verify.FaceVerifyProperties;
+import cn.com.qmth.examcloud.starters.face.verify.common.IResult;
+import cn.com.qmth.examcloud.starters.face.verify.common.JsonHelper;
+import cn.com.qmth.examcloud.starters.face.verify.service.impl.FaceVerifyServiceImpl;
+import org.junit.Test;
+
+public class FaceVerifyTest {
+
+    @Test
+    public void demo() {
+        FaceVerifyProperties properties = new FaceVerifyProperties();
+        properties.setBaiduKey("xxx");
+        properties.setBaiduSecret("xxx");
+        properties.setFacePlusKey("xxx");
+        properties.setFacePlusSecret("xxx");
+
+        FaceVerifyServiceImpl faceVerifyService = new FaceVerifyServiceImpl();
+        faceVerifyService.setProperties(properties);
+
+        String imageUrl = "https://ecs-test-static.qmth.com.cn/student_base_photo/0/675692/1653361979769.jpg";
+        String imageUrl2 = "https://ecs-test-static.qmth.com.cn/student_base_photo/0/675664/1664182785685.jpg";
+
+        // IResult result = faceVerifyService.faceDetectByBaidu(imageUrl);
+        // IResult result = faceVerifyService.faceCompareByBaidu(imageUrl, imageUrl2);
+        // IResult result = faceVerifyService.faceDetectByFacePlus(imageUrl);
+        // IResult result = faceVerifyService.faceCompareByFacePlus(imageUrl, imageUrl2);
+        // System.out.println(new JsonHelper().toJson(result));
+    }
+
+}