• JAVA调用腾讯云API-实现语音合成(TTS)(三)


    本节分享给大家通过调用腾讯云API实现语音合成技术

    package com.example.combat.controller;
    
    import com.example.combat.service.TTSService;
    import com.example.combat.ttsutis.param.TextToVoice;
    import io.swagger.annotations.ApiImplicitParam;
    import io.swagger.annotations.ApiImplicitParams;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletResponse;
    import javax.validation.Valid;
    
    /**
     * @description: 语音合成
     * @author:zhucj
     * @date: 2019-11-27 16:37
     */
    @RestController
    @RequestMapping("/tts")
    public class TTSControllerl {
    
        @Autowired
        private TTSService ttsService;
    
        @ApiOperation(value = "语音合成")
        @ApiImplicitParams({
                @ApiImplicitParam(name = "text",value = "合成语音的源文本",required = true,dataType = "String"),
                @ApiImplicitParam(name = "volume",value = "音量大小,范围:[0,10]",required = true,dataType = "String"),
                @ApiImplicitParam(name = "speed",value = "语速,范围:[-2,2]",required = true,dataType = "String"),
                @ApiImplicitParam(name = "voiceType",value = "音色",required = true,dataType = "Integer")
        })
        @PostMapping(value = "textToVoice")
        public void textToVoice(@Valid @RequestBody TextToVoice textToVoice, HttpServletResponse response){
            ttsService.voiceSynthesis(textToVoice,response);
        }
    }
    package com.example.combat.service;
    
    import com.example.combat.ttsutis.R;
    import com.example.combat.ttsutis.param.TextToVoice;
    
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @description: 语音合成实现类
     * @author: zhucj
     * @date: 2019-11-27 16:12
     */
    public interface TTSService {
    
        /**
         * 语音合成
         * @param textToVoice
         */
        void voiceSynthesis(TextToVoice textToVoice, HttpServletResponse response);
    }
    package com.example.combat.service.Impl;
    
    import cn.hutool.core.io.FileUtil;
    import com.example.combat.afsutils.Base64ConvertUtils;
    import com.example.combat.gaodemapUtils.SystemConstant;
    import com.example.combat.service.TTSService;
    import com.example.combat.ttsutis.R;
    import com.example.combat.ttsutis.TTSUtil;
    import com.example.combat.ttsutis.param.TextToVoice;
    import com.example.combat.ttsutis.param.TextToVoiceResponse;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    import sun.misc.BASE64Decoder;
    
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    import java.util.Objects;
    
    /**
     * @description:
     * @author: zhucj
     * @date: 2019-11-27 16:15
     */
    @Service
    @Slf4j
    public class TTSServiceImpl implements TTSService {
    
        @Autowired
        private TTSUtil ttsUtil;
    
        @Value("${tencent.pathImg}")
        private String pathImg;
    
        @Override
        public void voiceSynthesis(TextToVoice textToVoice, HttpServletResponse response) {
            R r = ttsUtil.voiceSynthesis(textToVoice);
            if (r.getSuccess() && Objects.equals(r.getCode(), SystemConstant.SUCCESS_CODE)){
                TextToVoiceResponse data =(TextToVoiceResponse) r.getData();
                String audio = data.getAudio();
                //将base64编码的wav/mp3音频数据 下载给前端
                exportImg(response,pathImg,audio);
            }else {
                throw new RuntimeException("语音合成失败");
            }
        }
    
        public static void exportImg(HttpServletResponse response, String filePath,String imgStr) {
    
            //对字节数组字符串进行Base64解码并生成图片
            String imgFilePath = null;
            //图像数据为空
            if (imgStr == null){
                return ;
            }
            BASE64Decoder decoder = new BASE64Decoder();
            BufferedOutputStream buff = null;
            ServletOutputStream outStr = null;
            try {
                //Base64解码
                byte[] b = decoder.decodeBuffer(imgStr);
                for (int i = 0; i < b.length; ++i) {
                    if (b[i] < 0) {
                        //调整异常数据
                        b[i] += 256;
                    }
                }
                response.setCharacterEncoding("utf-8");
                //设置响应的内容类型
                response.setContentType("text/plain");
                //设置文件的名称和格式
                response.setHeader("content-type", "application/octet-stream");
                response.setContentType("application/octet-stream");
                response.addHeader("Content-Disposition", "attachment;filename=" + "合成语音.wav");
                outStr = response.getOutputStream();
                buff = new BufferedOutputStream(outStr);
                buff.write(b);
                buff.flush();
                buff.close();
            } catch (Exception e) {
                e.printStackTrace();
                log.error("文件导出异常:", e);
            } finally {
                try {
                    buff.close();
                } catch (Exception e) {
                    log.error("流关闭异常:", e);
                }
                try {
                    outStr.close();
                } catch (Exception e) {
                    log.error("流关闭异常:", e);
                }
            }
        }
    }
    package com.example.combat.ttsutis;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.example.combat.afsutils.HttpUtil;
    import com.example.combat.afsutils.SignUtils;
    import com.example.combat.asrutils.param.SentenceRecognitionApi;
    import com.example.combat.asrutils.param.SentenceResponse;
    import com.example.combat.asrutils.param.SystemConstants;
    import com.example.combat.config.constant.ContentTypeEnum;
    import com.example.combat.config.constant.HttpMethodEnum;
    import com.example.combat.config.constant.SignMenodEnum;
    import com.example.combat.ttsutis.param.TextToVoice;
    import com.example.combat.ttsutis.param.TextToVoiceResponse;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.*;
    
    /**
     * @description: 语音合成
     * @author: zhucj
     * @date: 2019-11-27 15:35
     */
    @Component
    @Slf4j
    public class TTSUtil {
    
        @Value("${tencent.secretId}")
        private String sercretId;
    
        @Value("${tencent.secretKey}")
        private String sercretKey;
    
        /**
         * 语音合成
         * @param textToVoice
         * @return
         */
       public R voiceSynthesis(TextToVoice textToVoice){
    
           TreeMap treeMap = createPublicMap("TextToVoice", "2019-08-23", "ap-shenzhen-fsi");
           HashMap<String,Object> hashMap = new HashMap<>();
           try {
               hashMap.put("Text", URLEncoder.encode(textToVoice.getText(),"UTF-8"));
           } catch (UnsupportedEncodingException e) {
              log.error("URL Encoder异常:{}",e.getMessage());
              return R.error("语音合成失败").setCode(SystemConstants.SERVER_ERROR_CODE);
           }
           hashMap.put("SessionId", UUID.randomUUID().toString());
           hashMap.put("ModelType",1);
           hashMap.put("Volume",Float.valueOf(textToVoice.getVolume()));
           hashMap.put("Speed",Float.valueOf(textToVoice.getSpeed()));
           hashMap.put("VoiceType",textToVoice.getVoiceType());
    
           //签名,公共参数不需要放到body中
           String sign = null;
           try {
               sign = SignUtils.sign(treeMap, HttpMethodEnum.POST, SignMenodEnum.TC3_HMAC_SHA256, JSON.toJSONString(hashMap)
                       , TextToVoiceConstant.TEXT_TO_VOICE, sercretKey, ContentTypeEnum.JSON);
           } catch (Exception e) {
               log.error("签名异常:{}",e.getMessage());
               return R.error("签名异常").setCode(SystemConstants.SERVER_ERROR_CODE);
           }
           try {
               String respJson = HttpUtil.httpPost(TextToVoiceConstant.TEXT_TO_VOICE, 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 {
                   TextToVoiceResponse textToVoiceResponse = JSON.parseObject(response, TextToVoiceResponse.class);
                   return R.ok(textToVoiceResponse.getAudio()).setCode(SystemConstants.SUCCESS_CODE);
               }
    
           } catch (Exception e) {
               log.error("语音合成失败:{}",e.getMessage());
               return R.error("语音合成失败").setCode(SystemConstants.SERVER_ERROR_CODE);
           }
       }
        /**
         * 封装请求公共参数
         * @param action
         * @param version
         * @return
         */
        public TreeMap createPublicMap(String action, String version,String region ){
    
            TreeMap<String,Object> treeMap = new TreeMap<>();
            treeMap.put("Action",action);
            treeMap.put("Version",version);
            treeMap.put("Region",region);
            treeMap.put("Timestamp",getCurrentTimestamp());
            treeMap.put("Nonce",new Random().nextInt(Integer.MAX_VALUE));
            treeMap.put("SecretId",sercretId);
            return treeMap;
        }
    
        /**
         * 获取当前时间戳,单位秒
         * @return
         */
        public static long getCurrentTimestamp() {
            return System.currentTimeMillis()/1000;
        }
    
    }
    package com.example.combat.ttsutis;
    
    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.example.combat.ttsutis;
    
    /**
     * @description: 语音合成常量
     * @author: zhucj
     * @date: 2019-11-27 15:51
     */
    public class TextToVoiceConstant {
    
        /**
         * 语音合成Api
         */
        public static final String TEXT_TO_VOICE = "https://tts.ap-shenzhen-fsi.tencentcloudapi.com";
    }
    package com.example.combat.ttsutis.param;
    
    import io.swagger.annotations.ApiModel;
    import lombok.*;
    
    import javax.validation.constraints.NotNull;
    
    /**
     * @description:
     * @author: zhucj
     * @date: 2019-11-27 15:39
     */
    @Data
    @ApiModel(description = "语音合成请求实体")
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class TextToVoice {
    
    
        /**
         * 合成语音的源文本,按UTF-8编码统一计算。
         * 中文最大支持100个汉字(全角标点符号算一个汉字);
         * 英文最大支持400个字母(半角标点符号算一个字母)。包含空格等字符时需要url encode再传输。
         */
        @NotNull(message = "合成语音的源文本不为空")
        private String text;
    
        /**
         * 音量大小,范围:[0,10],分别对应11个等级的音量,默认为0
         */
        @NotNull(message = "音量大小不为空")
        private String volume;
    
        /**
         *语速,范围:[-2,2],分别对应不同语速:
         * -2代表0.6倍
         * -1代表0.8倍
         * 0代表1.0倍(默认)
         * 1代表1.2倍
         * 2代表1.5倍
         * 输入除以上整数之外的其他参数不生效,按默认值处理。
         */
        @NotNull(message = "语速大小不为空")
        private String speed;
    
        /**
         * 音色
         * 0-亲和女声(默认)
         * 1-亲和男声
         * 2-成熟男声
         * 4-温暖女声
         * 5-情感女声
         * 6-情感男声
         */
        @NotNull(message = "音色选择不为空")
        private Integer voiceType;
    
    }
    package com.example.combat.ttsutis.param;
    
    import com.example.combat.afsutils.param.resp.Response;
    import io.swagger.annotations.ApiModel;
    import lombok.*;
    
    /**
     * @description:
     * @author: zhucj
     * @date: 2019-11-27 16:09
     */
    @Data
    @ApiModel(description = "语音合成响应实体")
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class TextToVoiceResponse extends Response {
    
        private String Audio;
    
        private String SessionId;
    }
    package com.example.combat.afsutils;
    
    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 {
            log.info("POST请求参数:{}",params);
            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.example.combat.afsutils;
    
    import com.alibaba.fastjson.JSON;
    import com.example.combat.config.constant.ContentTypeEnum;
    import com.example.combat.config.constant.HttpMethodEnum;
    import com.example.combat.config.constant.SignMenodEnum;
    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() +"
    " + "host:" + host + "
    ";
                    String signedHeaders = "content-type;host";
    
                    String hashedRequestPayload = sha256Hex(jsonString);
                    String canonicalRequest = menth.getName() + "
    " + canonicalUri + "
    " + canonicalQueryString + "
    "
                            + canonicalHeaders + "
    " + signedHeaders + "
    " + hashedRequestPayload;
    
                    // ************* 步骤 2:拼接待签名字符串 *************
                    String credentialScope = date + "/" + service + "/" + "tc3_request";
                    String hashedCanonicalRequest = sha256Hex(canonicalRequest);
                    String stringToSign = signMenodEnum.getMendoName() + "
    " + params.get("Timestamp") + "
    " + credentialScope + "
    " + 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();
        }
    
    
    }
    #腾讯云服务配置
    tencent:
      secretId: *******
      secretKey: *******
      pathImg: E:/upload/
  • 相关阅读:
    Swap 2 Variables in Python
    Python Static Method
    Longest Palindromic Substring-Dynamic Programing
    Config Static IP Address manually in Ubuntu
    network FAQ
    [Python] Send emails to the recepients specified in Message["CC"]
    Rare But Powerful Vim Commands.
    主机名 域名 网站名 URL
    Extracts
    关于hibernate一对一配置
  • 原文地址:https://www.cnblogs.com/zhucj-java/p/11949833.html
Copyright © 2020-2023  润新知