JAVA調用騰訊雲API,實現人臉識別功能 (一)


本次將分享給大家,調用騰訊雲API實現人臉識別功能(參考API https://cloud.tencent.com/document/api/867/32777)

package com.sf.vsolution.hb.sfce.util.wechat.face;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sf.vsolution.hb.sfce.util.wechat.face.req.CreateFace;
import com.sf.vsolution.hb.sfce.util.wechat.face.req.CreateGroup;
import com.sf.vsolution.hb.sfce.util.wechat.face.req.CreatePerson;
import com.sf.vsolution.hb.sfce.util.wechat.face.req.GetPersonBaseInfo;
import com.sf.vsolution.hb.sfce.util.wechat.face.resp.GetPersonBaseInfoResp;
import com.sf.vsolution.hb.sfce.util.wechat.face.resp.VerifyFaceResp;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * @description: 人臉識別工具類
 * @author: zhucj
 * @date: 2019-10-18 16:10
 */
@Slf4j
@Component
public class AFSUtils {

    @Value("${tencent.secretId}")
    private String sercretId;

    @Value("${tencent.secretKey}")
    private String sercretKey;


    /**
     * 創建人員庫
     * @param createGroup
     * @return
     */
    @ApiOperation(value = "創建人員庫")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "groupName",value = "人員庫名稱",required = true,dataType = "String"),
            @ApiImplicitParam(name = "groupId",value = "人員庫ID",required = true,dataType = "String")
    })
    public R createGroup(CreateGroup createGroup){
        //構建簽名參數
        TreeMap treeMap = createPublicMap("CreateGroup", "2018-03-01");
        treeMap.put("GroupName",createGroup.getGroupName());
        treeMap.put("GroupId",createGroup.getGroupId());
        if(!StringUtils.isEmpty(createGroup.getGroupExDescriptions01())){
            treeMap.put("GroupExDescriptions.0",createGroup.getGroupId());
        }
        if(!StringUtils.isEmpty(createGroup.getGroupExDescriptions02())){
            treeMap.put("GroupExDescriptions.1",createGroup.getGroupId());
        }
        if(!StringUtils.isEmpty(createGroup.getGroupExDescriptions03())){
            treeMap.put("GroupExDescriptions.2",createGroup.getGroupId());
        }
        if(!StringUtils.isEmpty(createGroup.getTag())){
            treeMap.put("Tag",createGroup.getTag());
        }
        try {
            treeMap.put("Signature",SignUtils.sign(treeMap,HttpMethodEnum.GET,SignMenodEnum.HMACSHA1, JSON.toJSONString(createGroup),
                    AFSServerApi.SERVER_NAME_API,sercretKey,ContentTypeEnum.JSON));
        } catch (Exception e) {
            log.error("簽名異常:{}",e.getMessage());
            R.error("簽名異常").setCode(SystemConstants.SERVER_ERROR_CODE);
        }
        String reqUrl = null;
        try {
            reqUrl = SignUtils.getUrl(treeMap, AFSServerApi.SERVER_NAME_API);
        } catch (UnsupportedEncodingException e) {
            log.error("URL編碼異常:{}",e.getMessage());
            return R.error("URL編碼異常").setCode(SystemConstants.SERVER_ERROR_CODE);
        }

        try {
            String s = HttpUtil.httpGet(reqUrl);
            JSONObject jsonObject = JSON.parseObject(s);
            String response = jsonObject.getString("Response");
            JSONObject error =(JSONObject) JSON.parseObject(response).get("Error");
            if (Objects.nonNull(error)){
                return R.error(String.valueOf(error.get("Message"))).setCode(SystemConstants.SERVER_ERROR_CODE);
            }else {
                return R.ok(null,"創建成功");
            }

        } catch (Exception e) {
            log.error("創建失敗:{}",e.getMessage());
            return R.error("創建失敗").setCode(SystemConstants.SERVER_ERROR_CODE);
        }

    }


    /**
     * 創建人員
     * @param createPerson
     * @return
     */
    @ApiOperation(value = "創建人員")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "groupId",value = "人員庫ID",required = true,dataType = "String"),
            @ApiImplicitParam(name = "personName",value = "人員名字",required = true,dataType = "String"),
            @ApiImplicitParam(name = "personId",value = "人員ID",required = true,dataType = "String"),
            @ApiImplicitParam(name = "gender",value = "性別",required = true,dataType = "Integer"),
            @ApiImplicitParam(name = "image",value = "圖片名字Base64字符串",required = true,dataType = "String")
    })
    public R  createPerson(CreatePerson createPerson){
        //構建簽名參數map
        TreeMap treeMap = createPublicMap("CreatePerson", "2018-03-01");
        //構建JSON格式參數
        HashMap<String,Object> hashMap = new HashMap<>();
        hashMap.put("PersonName",createPerson.getPersonName());
        hashMap.put("PersonId",createPerson.getPersonId());
        hashMap.put("GroupId",createPerson.getGroupId());
        hashMap.put("Image",createPerson.getImage());
        hashMap.put("Gender",createPerson.getGender()==null?0:createPerson.getGender());
        if (!StringUtils.isEmpty(createPerson.getPersonExDescription01())){
            hashMap.put("PersonExDescriptionInfos.0.PersonExDescriptionIndex",0);
            hashMap.put("PersonExDescriptionInfos.0.PersonExDescription",createPerson.getPersonExDescription01());
        }
        if (!StringUtils.isEmpty(createPerson.getPersonExDescription02())){
            hashMap.put("PersonExDescriptionInfos.1.PersonExDescriptionIndex",1);
            hashMap.put("PersonExDescriptionInfos.1.PersonExDescription",createPerson.getPersonExDescription02());
        }
        if (!StringUtils.isEmpty(createPerson.getPersonExDescription03())){
            hashMap.put("PersonExDescriptionInfos.2.PersonExDescriptionIndex",2);
            hashMap.put("PersonExDescriptionInfos.2.PersonExDescription",createPerson.getPersonExDescription03());
        }
        String sign = null;
        try {
            sign = SignUtils.sign(treeMap, HttpMethodEnum.POST, SignMenodEnum.TC3_HMAC_SHA256, JSON.toJSONString(hashMap)
                    , AFSServerApi.SERVER_NAME_API, sercretKey, ContentTypeEnum.JSON);
        } catch (Exception e) {
            log.error("簽名異常:{}",e.getMessage());
            return R.error("簽名異常");
        }
        try {
            String respJson = HttpUtil.httpPost(AFSServerApi.SERVER_NAME_API, JSON.parseObject(sign,Map.class),hashMap);
            JSONObject jsonObject = JSON.parseObject(respJson);
            String response = jsonObject.getString("Response");
            JSONObject error =(JSONObject) JSON.parseObject(response).get("Error");
            if (Objects.nonNull(error)){
                return R.error(String.valueOf(error.get("Message"))).setCode(SystemConstants.SERVER_ERROR_CODE);
            }else {
                return R.ok(null,"創建成功");
            }

        } catch (Exception e) {
           log.error("創建失敗:{}",e.getMessage());
           return R.error("創建失敗");
        }
    }


    /**
     * 查詢人員列表
     * @param getPersonBaseInfo
     * @return
     */
    @ApiOperation(value = "查詢人員列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "personId",value = "人員ID",required = true,dataType = "String"),
    })
    public R getPersonBaseInfo(GetPersonBaseInfo getPersonBaseInfo){
        //封裝公共map簽名
        TreeMap treeMap = createPublicMap("GetPersonBaseInfo", "2018-03-01");
        //HashMap<String,Object> hashMap = new HashMap<>();
        //封裝請求參數
        treeMap.put("PersonId",getPersonBaseInfo.getPersonId());
        String sign = null;
        try {
            sign = SignUtils.sign(treeMap, HttpMethodEnum.GET, SignMenodEnum.HMACSHA1, null, AFSServerApi.SERVER_NAME_API, sercretKey, ContentTypeEnum.JSON);
        } catch (Exception e) {
            log.error("簽名異常",e.getMessage());
            return R.error("簽名異常");
        }
        treeMap.put("Signature",sign);

        try {
            String url = SignUtils.getUrl(treeMap, AFSServerApi.SERVER_NAME_API);
            String respJson = HttpUtil.httpGet(url);
            JSONObject jsonObject = JSON.parseObject(respJson);
            String response = jsonObject.getString("Response");
            JSONObject error =(JSONObject) JSON.parseObject(response).get("Error");
            if (Objects.nonNull(error)){
                return R.error(String.valueOf(error.get("Message"))).setCode(SystemConstants.SERVER_ERROR_CODE);
            }else {
                return R.ok(JSON.parseObject(response, GetPersonBaseInfoResp.class));
            }

        } catch (Exception e) {
            log.error("查詢失敗:{}",e.getMessage());
            return R.error("查詢失敗:"+e.getMessage());
        }

    };

    /**
     * 創建人臉
     * @param createFace
     * @return
     */
    public R createFace(CreateFace createFace){
        //封裝公共請求參數
        TreeMap treeMap = createPublicMap("CreateFace", "2018-03-01");
        //封裝請求參數
        HashMap<String,Object> hashMap = new HashMap<>();
        hashMap.put("PersonId",createFace.getPersonId());
        ArrayList<String> images = new ArrayList<>();
        if (!StringUtils.isEmpty(createFace.getImg01())){
            images.add(createFace.getImg01());
        }
        if (!StringUtils.isEmpty(createFace.getImg02())){
            images.add(createFace.getImg02());
        }
        if (!StringUtils.isEmpty(createFace.getImg03())){
            images.add(createFace.getImg03());
        }
        if (!StringUtils.isEmpty(createFace.getImg04())){
            images.add(createFace.getImg04());
        }
        if (!StringUtils.isEmpty(createFace.getImg05())){
            images.add(createFace.getImg05());
        }
        hashMap.put("Images",images);
        //獲取請求頭JSON數據
        String haerdsJson = null;
        try {
            haerdsJson = SignUtils.sign(treeMap, HttpMethodEnum.POST, SignMenodEnum.TC3_HMAC_SHA256, JSON.toJSONString(hashMap),
                    AFSServerApi.SERVER_NAME_API, sercretKey, ContentTypeEnum.JSON);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //發起post請求
        try {
            String respJson = HttpUtil.httpPost(AFSServerApi.SERVER_NAME_API, JSON.parseObject(haerdsJson, TreeMap.class), hashMap);
            JSONObject jsonObject = JSON.parseObject(respJson);
            String response = jsonObject.getString("Response");
            JSONObject error =(JSONObject) JSON.parseObject(response).get("Error");
            if (Objects.nonNull(error)){
                return R.error(String.valueOf(error.get("Message"))).setCode(SystemConstants.SERVER_ERROR_CODE);
            }else {
                return R.ok("新增成功");
            }

        } catch (Exception e) {
            log.error("新增失敗:{}",e.getMessage());
            return R.error("新增失敗:"+e.getMessage());
        }
    }


    public R verifyFace(CreatePerson createPerson){
        //封裝公共請求參數
        TreeMap treeMap = createPublicMap("VerifyFace", "2018-03-01");
        //封裝請求參數
        HashMap<String,Object> hashMap = new HashMap<>();
        hashMap.put("PersonId",createPerson.getPersonId());
        hashMap.put("Image",createPerson.getImage());
        //獲取請求頭JSON數據
        String haerdsJson = null;
        try {
            haerdsJson = SignUtils.sign(treeMap, HttpMethodEnum.POST, SignMenodEnum.TC3_HMAC_SHA256, JSON.toJSONString(hashMap),
                    AFSServerApi.SERVER_NAME_API, sercretKey, ContentTypeEnum.JSON);
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("簽名異常");
        }
        //發起post請求
        try {
            String respJson = HttpUtil.httpPost(AFSServerApi.SERVER_NAME_API, JSON.parseObject(haerdsJson, TreeMap.class), hashMap);
            JSONObject jsonObject = JSON.parseObject(respJson);
            String response = jsonObject.getString("Response");
            JSONObject error =(JSONObject) JSON.parseObject(response).get("Error");
            if (Objects.nonNull(error)){
                return R.error(String.valueOf(error.get("Message"))).setCode(SystemConstants.SERVER_ERROR_CODE);
            }else {
                VerifyFaceResp verifyFaceResp = JSON.parseObject(response, VerifyFaceResp.class);
                if (verifyFaceResp.getIsMatch()){
                    return R.ok(null,"識別成功,相識度"+verifyFaceResp.getScore()+"%");
                }else {
                   return R.ok(null,"識別不成功,相識度"+verifyFaceResp.getScore()+"%");
                }
            }
        } catch (Exception e) {
            log.error("識別失敗:{}",e.getMessage());
            return R.error("識別失敗:"+e.getMessage());
        }
    }
    /**
     * 獲取當前時間戳,單位秒
     * @return
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis()/1000;
    }


    /**
     * 封裝請求參數
     * @param action
     * @param version
     * @return
     */
    public TreeMap createPublicMap(String action,String version){

        TreeMap<String,Object> treeMap = new TreeMap<>();
        treeMap.put("Action",action);
        treeMap.put("Version",version);
        treeMap.put("Timestamp",getCurrentTimestamp());
        treeMap.put("Nonce",new Random().nextInt(Integer.MAX_VALUE));
        treeMap.put("SecretId",sercretId);
        return treeMap;
    }
}

 

package com.sf.vsolution.hb.sfce.util.wechat.face;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class HttpUtil {

    public static final ContentType TEXT_PLAIN = ContentType.create("text/plain", StandardCharsets.UTF_8);

    /**
     * HttpClient 連接池
     */
    private static PoolingHttpClientConnectionManager cm = null;

    static {
        // 初始化連接池,可用於請求HTTP/HTTPS(信任所有證書)
        cm = new PoolingHttpClientConnectionManager(getRegistry());
        // 整個連接池最大連接數
        cm.setMaxTotal(200);
        // 每路由最大連接數,默認值是2
        cm.setDefaultMaxPerRoute(5);
    }

    /**
     * 發送 HTTP GET請求
     * <p>不帶請求參數和請求頭</p>
     * @param url 地址
     * @return
     * @throws Exception
     */
    public static String httpGet(String url) throws Exception {
        log.info("請求參數:{}",url);
        HttpGet httpGet = new HttpGet(url);

        return doHttp(httpGet);
    }

    /**
     * 發送 HTTP GET請求
     * <p>帶請求參數,不帶請求頭</p>
     * @param url    地址
     * @param params 參數
     * @return
     * @throws Exception
     * @throws Exception
     */
    public static String httpGet(String url, Map<String, Object> params) throws Exception {
        // 轉換請求參數
        List<NameValuePair> pairs = covertParams2NVPS(params);

        // 裝載請求地址和參數
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());

        return doHttp(httpGet);
    }

    /**
     * 發送 HTTP GET請求
     * <p>帶請求參數和請求頭</p>
     * @param url     地址
     * @param headers 請求頭
     * @param params  參數
     * @return
     * @throws Exception
     * @throws Exception
     */
    public static String httpGet(String url, Map<String, Object> headers, Map<String, Object> params) throws Exception {
        // 轉換請求參數
        List<NameValuePair> pairs = covertParams2NVPS(params);

        // 裝載請求地址和參數
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());
        // 設置請求頭
        for (Map.Entry<String, Object> param : headers.entrySet()){
            httpGet.addHeader(param.getKey(), String.valueOf(param.getValue()));}

        return doHttp(httpGet);
    }

    /**
     * 發送 HTTP POST請求
     * <p>不帶請求參數和請求頭</p>
     *
     * @param url 地址
     * @return
     * @throws Exception
     */
    public static String httpPost(String url) throws Exception {
        HttpPost httpPost = new HttpPost(url);

        return doHttp(httpPost);
    }

    /**
     * 發送 HTTP POST請求
     * <p>帶請求參數,不帶請求頭</p>
     *
     * @param url    地址
     * @param params 參數
     * @return
     * @throws Exception
     */
    public static String httpPost(String url, Map<String, Object> params) throws Exception {
        // 轉換請求參數
        List<NameValuePair> pairs = covertParams2NVPS(params);

        HttpPost httpPost = new HttpPost(url);
        // 設置請求參數
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, StandardCharsets.UTF_8.name()));

        return doHttp(httpPost);
    }

    /**
     * 發送 HTTP POST請求
     * <p>帶請求參數和請求頭</p>
     *
     * @param url     地址
     * @param headers 請求頭
     * @param params  參數
     * @return
     * @throws Exception
     */
    public static String httpPost(String url, Map<String, Object> headers, Map<String, Object> params) throws Exception {

        HttpPost httpPost = new HttpPost(url);
        // 設置請求參數
        StringEntity entity = new StringEntity(JSON.toJSONString(params), ContentType.APPLICATION_JSON);
        httpPost.setEntity(entity);
        // 設置請求頭
        for (Map.Entry<String, Object> param : headers.entrySet()){
            httpPost.addHeader(param.getKey(), String.valueOf(param.getValue()));}

        return doHttp(httpPost);
    }



    /**
     * 轉換請求參數
     *
     * @param params
     * @return
     */
    public static List<NameValuePair> covertParams2NVPS(Map<String, Object> params) {
        List<NameValuePair> pairs = new ArrayList<NameValuePair>();

        for (Map.Entry<String, Object> param : params.entrySet()){
            pairs.add(new BasicNameValuePair(param.getKey(), String.valueOf(param.getValue())));}

        return pairs;
    }

    /**
     * 發送 HTTP 請求
     *
     * @param request
     * @return
     * @throws Exception
     */
    private static String doHttp(HttpRequestBase request) throws Exception {
        // 通過連接池獲取連接對象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();

        return doRequest(httpClient, request);
    }

    /**
     * 發送 HTTPS 請求
     * <p>使用指定的證書文件及密碼</p>
     *
     * @param request
     * @param path
     * @param password
     * @return
     * @throws Exception
     * @throws Exception
     */
    private static String doHttps(HttpRequestBase request, String path, String password) throws Exception {
        // 獲取HTTPS SSL證書
        SSLConnectionSocketFactory csf = getSSLFactory(path, password);
        // 通過連接池獲取連接對象
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();

        return doRequest(httpClient, request);
    }

    /**
     * 獲取HTTPS SSL連接工廠
     * <p>使用指定的證書文件及密碼</p>
     *
     * @param path     證書全路徑
     * @param password 證書密碼
     * @return
     * @throws Exception
     * @throws Exception
     */
    private static SSLConnectionSocketFactory getSSLFactory(String path, String password) throws Exception {

        // 初始化證書,指定證書類型為“PKCS12”
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        // 讀取指定路徑的證書
        FileInputStream input = new FileInputStream(new File(path));

        try {
            // 裝載讀取到的證書,並指定證書密碼
            keyStore.load(input, password.toCharArray());
        } finally {
            input.close();
        }

        // 獲取HTTPS SSL證書連接上下文
        SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, password.toCharArray()).build();

        // 獲取HTTPS連接工廠,指定TSL版本
        SSLConnectionSocketFactory sslCsf = new SSLConnectionSocketFactory(sslContext, new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());

        return sslCsf;
    }

    /**
     * 獲取HTTPS SSL連接工廠
     * <p>跳過證書校驗,即信任所有證書</p>
     *
     * @return
     * @throws Exception
     */
    private static SSLConnectionSocketFactory getSSLFactory() throws Exception {
        // 設置HTTPS SSL證書信息,跳過證書校驗,即信任所有證書請求HTTPS
        SSLContextBuilder sslBuilder = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        });

        // 獲取HTTPS SSL證書連接上下文
        SSLContext sslContext = sslBuilder.build();

        // 獲取HTTPS連接工廠
        SSLConnectionSocketFactory sslCsf = new SSLConnectionSocketFactory(sslContext, new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE);

        return sslCsf;
    }

    /**
     * 獲取 HTTPClient注冊器
     *
     * @return
     * @throws Exception
     */
    private static Registry<ConnectionSocketFactory> getRegistry() {
        Registry<ConnectionSocketFactory> registry = null;

        try {
            registry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", new PlainConnectionSocketFactory()).register("https", getSSLFactory()).build();
        } catch (Exception e) {
            log.error("獲取 HTTPClient注冊器失敗", e);
        }

        return registry;
    }


    /**
     * 處理Http/Https請求,並返回請求結果
     * <p>注:默認請求編碼方式 UTF-8</p>
     *
     * @param httpClient
     * @param request
     * @return
     * @throws Exception
     */
    private static String doRequest(CloseableHttpClient httpClient, HttpRequestBase request) throws Exception {
        String result = null;
        CloseableHttpResponse response = null;

        try {
            // 獲取請求結果
            response = httpClient.execute(request);
            // 解析請求結果
            HttpEntity entity = response.getEntity();
            // 轉換結果
            result = EntityUtils.toString(entity, StandardCharsets.UTF_8.name());
            // 關閉IO流
            EntityUtils.consume(entity);
        } finally {
            if (null != response){
                response.close();}
        }

        return result;
    }
}
package com.sf.vsolution.hb.sfce.util.wechat.face;

import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.*;

/**
 * @description: 圖片和Base64字符串轉換
 * @author: zhucj
 * @date: 2019-10-21 17:41
 */
public class Base64ConvertUtils {

    /**
     * @Description: 圖片轉化成base64字符串
     * @param:    path 路徑
     * @Return:
     */
    public static String getImageStr(String path) {
        //將圖片文件轉化為字節數組字符串,並對其進行Base64編碼處理
        //待處理的圖片
        String imgFile = path;
        InputStream in = null;
        byte[] data = null;
        //讀取圖片字節數組
        try
        {
            in = new FileInputStream(imgFile);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        //對字節數組Base64編碼
        BASE64Encoder encoder = new BASE64Encoder();
        //返回Base64編碼過的字節數組字符串
        return encoder.encode(data);
    }

    /**
     * @Description: 圖片轉化成base64字符串
     * @param:    file 類型
     * @Return:
     */
    public static String getImageStr(MultipartFile file) {
        //待處理的圖片
        InputStream in = null;
        byte[] data = null;
        //讀取圖片字節數組
        try
        {
            in = file.getInputStream();
            data = new byte[in.available()];
            in.read(data);
            in.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        //對字節數組Base64編碼
        BASE64Encoder encoder = new BASE64Encoder();
        //返回Base64編碼過的字節數組字符串
        return encoder.encode(data);
    }


    /**
     * @Description: base64字符串轉化成圖片
     * @param:     imgStr
     * @Return:
     */
    public static boolean GenerateImage(String imgStr,String photoname)
    {
        //對字節數組字符串進行Base64解碼並生成圖片
        //圖像數據為空
        if (imgStr == null){
            return false;
        }

        BASE64Decoder decoder = new BASE64Decoder();
        try
        {
            //Base64解碼
            byte[] b = decoder.decodeBuffer(imgStr);
            for(int i=0;i<b.length;++i) {
                if(b[i]<0) {
                    //調整異常數據
                    b[i]+=256;
                }
            }
            //生成jpeg圖片
            String imagePath= "E:/upload/img";
            //System.currentTimeMillis()
            //新生成的圖片
            String imgFilePath = imagePath+photoname;
            OutputStream out = new FileOutputStream(imgFilePath);
            out.write(b);
            out.flush();
            out.close();
            return true;
        }
        catch (Exception e)
        {
            return false;
        }
    }

}
package com.sf.vsolution.hb.sfce.util.wechat.face;

/**
 * @description: 騰訊雲 API服務名稱
 * @author: zhucj
 * @date: 2019-10-18 15:12
 */
public class AFSServerApi {


    /**
     * 創建人員庫
     */
    public static final String SERVER_NAME_API = "https://iai.tencentcloudapi.com";



}
package com.sf.vsolution.hb.sfce.util.wechat.face;

/**
 * @description:
 * @author:zhucj
 * @date: 2019-10-21 15:02
 */
public enum  ContentTypeEnum {
    JSON("application/json; charset=utf-8"),
     MULTIPART("multipart/form-data");

    private String name;

    ContentTypeEnum(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.sf.vsolution.hb.sfce.util.wechat.face;

/**
 * @description:
 * @author: zhucj
 * @date: 2019-10-21 14:44
 */
public enum  HttpMethodEnum {

    GET("GET"),
    HEAD("HEAD"),
    POST("POST"),
    PUT("PUT"),
    PATCH("PATCH"),
    DELETE("DELETE"),
    OPTIONS("OPTIONS"),
    TRACE("TRACE");
    ;

    private String name;

    HttpMethodEnum(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.sf.vsolution.hb.sfce.util.wechat.face;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.ToString;

import java.io.Serializable;

/**
 * 返回類型
 * @author choleece
 * @date 2018/9/27
 */
@ApiModel
@ToString
public class R<T> implements Serializable {

    private static final long serialVersionUID = -6287952131441663819L;

    /**
     * 編碼
     */
    @ApiModelProperty(value = "響應碼", example = "200")
    private int code = 200;

    /**
     * 成功標志
     */
    @ApiModelProperty(value = "成功標志", example = "true")
    private Boolean success;

    /**
     * 返回消息
     */
    @ApiModelProperty(value = "返回消息說明", example = "操作成功")
    private String msg="操作成功";

    /**
     * 返回數據
     */
    @ApiModelProperty(value = "返回數據")
    private T data;

    /**
     * 創建實例
     * @return
     */
    public static R instance() {
        return new R();
    }

    public int getCode() {
        return code;
    }

    public R setCode(int code) {
        this.code = code;
        return this;
    }

    public Boolean getSuccess() {
        return success;
    }

    public R setSuccess(Boolean success) {
        this.success = success;
        return this;
    }

    public String getMsg() {
        return msg;
    }

    public R setMsg(String msg) {
        this.msg = msg;
        return this;
    }

    public T getData() {
        return data;
    }
    public R setData(T data) {
        this.data = data;
        return this;
    }

    public static R ok() {
        return R.instance().setSuccess(true);
    }

    public static R ok(Object data) {
        return ok().setData(data);
    }

    public static R ok(Object data, String msg) {
        return ok(data).setMsg(msg);
    }

    public static R error() {
        return R.instance().setSuccess(false);
    }

    public static R error(String msg) {
        return error().setMsg(msg);
    }

    /**
     * 無參
     */
    public R() {
    }

    public R(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public R(int code, T data){
        this.code = code;
        this.data = data;
    }

    /**
     * 有全參
     * @param code
     * @param msg
     * @param data
     * @param success
     */
    public R(int code, String msg, T data, Boolean success) {
        this.code = code;
        this.msg = msg;
        this.data = data;
        this.success = success;
    }

    /**
     * 有參
     * @param code
     * @param msg
     * @param data
     */
    public R(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

   
}
package com.sf.vsolution.hb.sfce.util.wechat.face;

/**
 * @description: 簽名方法
 * @author: zhucj
 * @date: 2019-10-21 13:58
 */
public enum  SignMenodEnum {

    HMACSHA1("HmacSHA1"),
    HMACSHA256("HmacSHA256"),
    TC3_HMAC_SHA256("TC3-HMAC-SHA256");

    private String mendoName;

    SignMenodEnum(String mendoName) {
        this.mendoName = mendoName;
    }

    public String getMendoName() {
        return mendoName;
    }

    public void setMendoName(String mendoName) {
        this.mendoName = mendoName;
    }
}
package com.sf.vsolution.hb.sfce.util.wechat.face;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
import java.util.TimeZone;
import java.util.TreeMap;

/**
 * @description: 騰訊雲 簽名方法
 * @author: zhucj
 * @date: 2019-10-18 14:14
 */
@Slf4j
public class SignUtils {


    private final static String CHARSET = "UTF-8";

    private final static Charset UTF8 = StandardCharsets.UTF_8;




    public static String sign(TreeMap<String, Object> params,HttpMethodEnum menth,SignMenodEnum signMenodEnum,
                               String jsonString,String reqUrl,String sercretKey,ContentTypeEnum typeEnum) throws Exception {
        String signString = null;
        String  sercretId  = String.valueOf(params.get("SecretId"));

        switch (signMenodEnum){
            case TC3_HMAC_SHA256:
                String replace = reqUrl.replace("https://", "");
                String service = replace.substring(0,3);
                String host = replace;
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                // 注意時區,否則容易出錯
                sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
                String date = sdf.format(new Date(Long.valueOf(params.get("Timestamp") + "000")));
                // ************* 步驟 1:拼接規范請求串 *************
                String canonicalUri = "/";
                String canonicalQueryString = "";
                String canonicalHeaders = "content-type:"+typeEnum.getName() +"\n" + "host:" + host + "\n";
                String signedHeaders = "content-type;host";

                String hashedRequestPayload = sha256Hex(jsonString);
                String canonicalRequest = menth.getName() + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
                        + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;

                // ************* 步驟 2:拼接待簽名字符串 *************
                String credentialScope = date + "/" + service + "/" + "tc3_request";
                String hashedCanonicalRequest = sha256Hex(canonicalRequest);
                String stringToSign = signMenodEnum.getMendoName() + "\n" + params.get("Timestamp") + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
                log.info("待簽名參數:{}",stringToSign);

                // ************* 步驟 3:計算簽名 *************
                byte[] secretDate = hmac256(("TC3" +sercretKey).getBytes(UTF8), date);
                byte[] secretService = hmac256(secretDate, service);
                byte[] secretSigning = hmac256(secretService, "tc3_request");
                String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
                log.info("生成簽名參數:{}",signature);

                // ************* 步驟 4:拼接 Authorization *************
                String authorization = signMenodEnum.getMendoName() + " " + "Credential=" + sercretId + "/" + credentialScope + ", "
                        + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
                log.info("生成authorization參數:{}",authorization);

                TreeMap<String, String> headers = new TreeMap<String, String>();
                headers.put("Authorization", authorization);
                headers.put("Content-Type",typeEnum.getName());
                headers.put("Host", host);
                headers.put("X-TC-Action",String.valueOf(params.get("Action")) );
                headers.put("X-TC-Timestamp",String.valueOf(params.get("Timestamp")));
                headers.put("X-TC-Version",String.valueOf(params.get("Version")));
                if (Objects.nonNull(params.get("Region"))){
                    headers.put("X-TC-Region",String.valueOf(params.get("Region")));
                }
                signString = JSON.toJSONString(headers);

                break;
                default:
                    StringBuilder s2s = new StringBuilder(reqUrl.replace("https://",menth.getName())+"/?");
                    // 簽名時要求對參數進行字典排序,此處用TreeMap保證順序
                    for (String k : params.keySet()) {
                        s2s.append(k).append("=").append(params.get(k).toString()).append("&");
                    }
                    String s = s2s.toString().substring(0, s2s.length() - 1);
                    Mac mac = Mac.getInstance(signMenodEnum.getMendoName());
                    SecretKeySpec secretKeySpec = new SecretKeySpec(sercretKey.getBytes(CHARSET), mac.getAlgorithm());
                    mac.init(secretKeySpec);
                    byte[] hash = mac.doFinal(s.getBytes(CHARSET));
                    signString = DatatypeConverter.printBase64Binary(hash);
                    break;
        }
        return signString ;


    }

    /**
     * 獲取簽名之后的請求Url
     * @param params
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String getUrl(TreeMap<String, Object> params,String reqUrl) throws UnsupportedEncodingException {
        StringBuilder url = new StringBuilder(reqUrl+"/?");
        // 實際請求的url中對參數順序沒有要求
        for (String k : params.keySet()) {
            // 需要對請求串進行urlencode,由於key都是英文字母,故此處僅對其value進行urlencode
            url.append(k).append("=").append(URLEncoder.encode(params.get(k).toString(), CHARSET)).append("&");
        }
        return url.toString().substring(0, url.length() - 1);
    }

    public static String getUrl(TreeMap<String, Object> params,String reqUrl,String jsonString,ContentTypeEnum typeEnum){
        String replace = reqUrl.replace("https://", "");
        StringBuilder sb = new StringBuilder();
        sb.append("curl -X POST https://").append(replace)
                .append(" -H \"Authorization: ").append(params.get("Authorization")).append("\"")
                .append(" -H \"Content-Type:").append(typeEnum.getName())
                .append(" -H \"Host: ").append(replace).append("\"")
                .append(" -H \"X-TC-Action: ").append(params.get("Action")).append("\"")
                .append(" -H \"X-TC-Timestamp: ").append(params.get("Timestamp")).append("\"")
                .append(" -H \"X-TC-Version: ").append(params.get("Version")).append("\"");
        if (Objects.nonNull(params.get("Region"))){
            sb.append(" -H \"X-TC-Region: ").append(params.get("Region")).append("\"");
        }
        sb.append(" -d '").append(jsonString).append("'");
        return sb.toString();
    }


    public static byte[] hmac256(byte[] key, String msg) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
        mac.init(secretKeySpec);
        return mac.doFinal(msg.getBytes(UTF8));
    }


    public static String sha256Hex(String s) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] d = md.digest(s.getBytes(UTF8));
        return DatatypeConverter.printHexBinary(d).toLowerCase();
    }


}
package com.sf.vsolution.hb.sfce.util.wechat.face;

/**
 * @ClassName SystemConstants
 * @Description 常量字段
 * @Author YangLei
 * @Date 2019/5/7 11:13
 * @Version 1.0
 **/
public class SystemConstants {
   
    /** 傳參不規范,code:400*/
    public static final Integer PARAM_INCORRECT_CODE = 400;

    /** 成功,code:200*/
    public static final Integer SUCCESS_CODE = 200;

    /** 服務內部調用失敗,code:500*/
    public static final Integer SERVER_ERROR_CODE = 500;

    /** 登錄失效,code:401*/
    public static final Integer AUTH_FAIL_CODE = 401;

    /** 無對應接口權限,code:402*/
    public static final Integer HAVE_NOT_PERMISSION_CODE = 402;

    /** 操作無記錄,code:403*/
    public static final Integer NO_RECORD_OPERATION = 403;
    
}

 ---------------------------

請求參數和響應參數

package com.sf.vsolution.hb.sfce.util.wechat.face.req;

import lombok.Builder;
import lombok.Data;

/**
 * @description: 增加人臉
 * @author: zhucj
 * @date: 2019-10-22 15:04
 */
@Data
@Builder
public class CreateFace {

    private String personId;

    private String img01;

    private String img02;

    private String img03;

    private String img04;

    private String img05;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.req;

import lombok.Builder;
import lombok.Data;

/**
 * @description: 創建人臉請求參數
 * @author: zhucj
 * @date: 2019-10-18 15:30
 */
@Data
@Builder
public class CreateGroup extends PublicParam {

    /**
     * 人員庫名稱,[1,60]個字符,可修改,不可重復
     */
    private String groupName;

    /**
     * 人員庫 ID,不可修改,不可重復。支持英文、數字、-%@#&_,長度限制64B
     */
    private String groupId;

    /**
     * 人員庫自定義描述字段,用於描述人員庫中人員屬性,該人員庫下所有人員將擁有此描述字段。
     * 最多可以創建5個。
     * 每個自定義描述字段支持[1,30]個字符。
     * 在同一人員庫中自定義描述字段不可重復。
     * 例: 設置某人員庫“自定義描述字段”為["學號","工號","手機號"],
     * 則該人員庫下所有人員將擁有名為“學號”、“工號”、“手機號”的描述字段,
     * 可在對應人員描述字段中填寫內容,登記該人員的學號、工號、手機號等信息。
     */
    private String groupExDescriptions01;

    private String groupExDescriptions02;

    private String groupExDescriptions03;

    /**
     * 人員庫信息備注,[0,40]個字符
     */
    private String tag;

}
package com.sf.vsolution.hb.sfce.util.wechat.face.req;

import lombok.Builder;
import lombok.Data;

/**
 * @description: 人員請求參數
 * @author: zhucj
 * @date: 2019-10-21 16:15
 */
@Data
@Builder
public class CreatePerson {

    private String groupId;

    private String personName;

    private String personId;

    private Integer gender;

    private String  personExDescription01;

    private String  personExDescription02;

    private String  personExDescription03;

    private String image;

    private String url;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.req;

import lombok.Data;

/**
 * @description: 刪除人員庫請求參數
 * @author:zhucj
 * @date: 2019-10-18 15:37
 */
@Data
public class DeleteGroup extends PublicParam{

    /**
     * 人員庫ID
     */
    private String groupId;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.req;

import lombok.Data;

/**
 * @description: 人員庫列表請求參數
 * @author: zhucj
 * @date: 2019-10-18 15:39
 */
@Data
public class GetGroupList extends PublicParam {

    /**
     * 起始序號,默認值為0
     */
    private Integer offset;

    /**
     * 返回數量,默認值為10,最大值為1000
     */
    private Integer limit;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.req;

import lombok.Data;

/**
 * @description: 獲取人員信息
 * @author: zhucj
 * @date: 2019-10-22 13:58
 */
@Data
public class GetPersonBaseInfo{

    private String personId;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.req;

import lombok.Data;

/**
 * @description:
 * @author: zhucj
 * @date: 2019-10-18 15:42
 */
@Data
public class ModifyGroup extends PublicParam {

    /**
     * 人員庫ID
     */
    private String groupId;

    /**
     * 需要修改的人員庫自定義描述字段,key-value
     */
    private String groupExDescriptionInfos01;

    /**
     * 需要修改的人員庫自定義描述字段,key-value
     */
    private String groupExDescriptionInfosIndex01;

    /**
     * 需要修改的人員庫自定義描述字段,key-value
     */
    private String groupExDescriptionInfos02;

    /**
     * 需要修改的人員庫自定義描述字段,key-value
     */
    private String groupExDescriptionInfosIndex02;

    /**
     * 人員庫信息備注
     */
    private String tag;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.req;

import lombok.Data;

/**
 * @description: 通用公共請求參數
 * @author:zhucj
 * @date: 2019-10-18 15:35
 */
@Data
public class PublicParam {

    private String action;

    private String version;

    private String region;

}
package com.sf.vsolution.hb.sfce.util.wechat.face.resp;

import lombok.Data;

/**
 * @description:
 * @author:zhucj
 * @date: 2019-10-21 17:08
 */
@Data
public class CreatePersonResp extends Response {

    private String FaceId;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.resp;

import lombok.Data;

/**
 * @description:
 * @author:zhucj
 * @date: 2019-10-18 15:58
 */
@Data
public class Error {

    private String Code;

    private String Messag;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.resp;

import lombok.Data;

import java.util.List;

/**
 * @description:
 * @author: zhucj
 * @date: 2019-10-18 16:02
 */
@Data
public class GetGroupListResp extends Response {

    private String GroupNum;

    private List<GroupInfos> GroupInfos;

}
package com.sf.vsolution.hb.sfce.util.wechat.face.resp;

import lombok.Data;

/**
 * @description:
 * @author: zhucj
 * @date: 2019-10-22 14:01
 */
@Data
public class GetPersonBaseInfoResp extends Response {

    private String PersonName;

    private String Gender;

    private String[] FaceIds;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.resp;

import lombok.Data;

/**
 * @description:
 * @author:zhucj
 * @date: 2019-10-18 16:00
 */
@Data
public class GroupInfos {

    private String GroupName;

    private String GroupId;

    private String[] GroupExDescriptions;

    private String Tag;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.resp;

import lombok.Data;

/**
 * @description: 請求返回公共參數
 * @author: zhucj
 * @date: 2019-10-18 15:56
 */
@Data
public class Response {

    private String RequestId;

    private Error Error;
}
package com.sf.vsolution.hb.sfce.util.wechat.face.resp;

import lombok.Data;

/**
 * @description:
 * @author: zhucj
 * @date: 2019-10-22 17:27
 */
@Data
public class VerifyFaceResp extends Response {

    private String Score;

    private Boolean IsMatch;

}

 --------------------------------------------

Yml配置文件

#騰訊雲服務配置
tencent:
  secretId: *********
  secretKey: ********

依賴Maven包

         <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.6.0</version>
         </dependency>
         <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.6.0</version>
         </dependency>

         <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
         </dependency>

         <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.55</version>
         </dependency>
        <!--httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.6</version>
        </dependency>

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM