首页 > 技术文章 > JAVA调用腾讯云API,实现人脸识别功能 (一)

zhucj-java 2019-11-25 17:03 原文

本次将分享给大家,调用腾讯云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>

 

 

推荐阅读