spring boot 集成腾讯文本翻译遇到的那些坑

第一步:根据api文档,先生成api秘钥
https://cloud.tencent.com/document/product/551/16611
第二步:编写http请求工具类,网上有很多
第三步:编写返回结果的实体类
package com.central.util.tencent;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
@Data
public class TencentResult {
/**
* 翻译后的文本
*/
private String TargetText;
private String Source;//源语言
private String Target;//目标语言
private String RequestId;//唯一请求ID,每次请求都会返回
}
第五步:编写翻译工具类,借鉴了某位大神的代码,自己加以修改了一下
package com.central.util.tencent;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.central.util.baidu.HttpUtil;
import com.central.util.baidu.TransResult;
import com.google.common.collect.Maps;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomUtils;
import springfox.documentation.spring.web.json.Json;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class TencentTrans {

private static final String TRANS_API_HOST = "https://tmt.tencentcloudapi.com/";
private static final Charset UTF_8 = StandardCharsets.UTF_8;
private static final String SECRET_ID = "#######";//填写自己的SECRET_ID
private static final String SECRET_KEY = "############";//填写自己SECRET_KEY

public static String getTransResult(String content,String from ,String to) throws IOException {
    Map<String,String> params = buildParams(content,from,to);
    JSONObject jsonObject = null;
    //译文长度大于2000,用POST请求
    if (content.length() >= 200) {
        jsonObject = HttpUtil.doPost(TRANS_API_HOST,params);
    } else {
        String url =  getUrlWithQueryString(TRANS_API_HOST,params);
        System.out.println("请求地址:" + url);
        jsonObject = HttpUtil.doGet(url);
    }
    Map map = JSON.parseObject(jsonObject.get("Response").toString());
    String requestId = map.get("RequestId").toString();
    if (map.get("Error") != null) {
        JSONObject obj = (JSONObject)map.get("Error");
        String code = obj.getString("Code");
        String message = obj.getString("Message");
        return "翻译失败,原因:" + message;
    } else {
        TencentResult result = JSONObject.parseObject(jsonObject.get("Response").toString(),TencentResult.class);
        System.out.println("翻译结果:"+result.getTargetText());
        return "翻译结果:"+result.getTargetText();
    }
}

public static Map<String,String> buildParams (String content,String from,String to) {
    Map<String,String> paramMap = Maps.newLinkedHashMapWithExpectedSize(10);
    paramMap.put("Action", "TextTranslate");
    paramMap.put("Nonce", String.valueOf(RandomUtils.nextInt(10,1000)));
    paramMap.put("ProjectId", "0");// 请填写自己的ProjectId
    paramMap.put("Region", "ap-shanghai");
    paramMap.put("SecretId", SECRET_ID);
    paramMap.put("Source",from);
    paramMap.put("SourceText", content);
    paramMap.put("Target", to);
    // 此处的时间戳要格外注意,是Unix时间戳
    paramMap.put("Timestamp", String.valueOf(System.currentTimeMillis() / 1000));
    paramMap.put("Version","2018-03-21");

    // 构造签名信息
    StringBuilder builder = new StringBuilder();
    for (String key : paramMap.keySet()) {
        // 若输入参数中包含下划线,则需要将其转换为“.”
        builder.append('&').append(key).append('=').append(paramMap.get(key).replace('_', '.'));
    }
    builder = builder.deleteCharAt(0);
    System.out.println("请求字符串:" + builder.toString());
    String str = "GETtmt.tencentcloudapi.com/?" + builder.toString();
    str = Base64.encodeBase64String(hmacSha1(str, SECRET_KEY));
    System.out.println("签名串:" + str);
    str = encode(str);
    System.out.println("签名串编码后:" + str);

    paramMap.put("Signature",str);
    return paramMap;
}


public static byte[] hmacSha1(String src, String key){
    try {
        SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("utf-8"),"HmacSHA1");
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(signingKey);
        return mac.doFinal(src.getBytes("utf-8"));
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

public static String getUrlWithQueryString(String url,Map<String,String> params){
    if (params == null) {
        return url;
    }
    StringBuilder builder = new StringBuilder(url);
    if (url.contains("?")){
        builder.append("&");
    } else {
        builder.append("?");
    }

    int i = 0;
    for (String key : params.keySet()) {
        String value = params.get(key);
        if(value == null){//过滤空的key
            continue;
        }

        if (i != 0) {
            builder.append("&");
        }
        builder.append(key);
        builder.append("=");
        builder.append(encode(value));

        i++;
    }
    return builder.toString();
}

public static String encode(String input){
    if(input == null){
        return "";
    }
    try {
        return URLEncoder.encode(input,"utf-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return input;
}

public static void main(String[] args) throws IOException {
    String result = getTransResult("皇帝岛珊瑚岛是普吉必玩岛屿,精致绝美的天然热带岛屿风光,珊瑚礁的海岸景色","auto","en");
    System.out.println(result);
}

}
到了这里,开始进行测试啦!满心期待,一定可以成功,然而结果却不如人意,出现了异常,签名错误
翻译失败,原因:The provided credentials could not be validated. Please check your signature is correct.
什么情况,步骤没错啊,怎么会报异常呢?检查代码,嗯,没有发现什么异常,怎么会执行不下去呢,百思不得其解,再次查看api文档,可能是签名转码的问题,抱着试一试的态度,将buildParams方法中URLEncode这一步注释掉,执行正常,返回翻译结果
public static Map<String,String> buildParams (String content,String from,String to) {
Map<String,String> paramMap = Maps.newLinkedHashMapWithExpectedSize(10);
paramMap.put(“Action”, “TextTranslate”);
paramMap.put(“Nonce”, String.valueOf(RandomUtils.nextInt(10,1000)));
paramMap.put(“ProjectId”, “0”);// 请填写自己的ProjectId
paramMap.put(“Region”, “ap-shanghai”);
paramMap.put(“SecretId”, SECRET_ID);
paramMap.put(“Source”,from);
paramMap.put(“SourceText”, content);
paramMap.put(“Target”, to);
// 此处的时间戳要格外注意,是Unix时间戳
paramMap.put(“Timestamp”, String.valueOf(System.currentTimeMillis() / 1000));
paramMap.put(“Version”,“2018-03-21”);

    // 构造签名信息
    StringBuilder builder = new StringBuilder();
    for (String key : paramMap.keySet()) {
        // 若输入参数中包含下划线,则需要将其转换为“.”
        builder.append('&').append(key).append('=').append(paramMap.get(key).replace('_', '.'));
    }
    builder = builder.deleteCharAt(0);
    System.out.println("请求字符串:" + builder.toString());
    String str = "GETtmt.tencentcloudapi.com/?" + builder.toString();
    str = Base64.encodeBase64String(hmacSha1(str, SECRET_KEY));
    System.out.println("签名串:" + str);
    //str = encode(str);
    //System.out.println("签名串编码后:" + str);

    paramMap.put("Signature",str);
    return paramMap;
}

测试成功后,突然想用腾讯API进行测试,在项目添加腾讯云api的依赖

   <dependency>
	   <groupId>com.tencentcloudapi</groupId>
	   <artifactId>tencentcloud-sdk-java</artifactId>
	   <version>3.0.29</version>
   </dependency>

在文档中找到开发者资源,点击进入页面,填写相关信息,右边代码直接生成代码,自己整理了一下传送的字符串,简直简单到想哭,适合我这种不想深入了解代码的菜鸟
spring boot 集成腾讯文本翻译遇到的那些坑
spring boot 集成腾讯文本翻译遇到的那些坑
/**
* 文本翻译
*/

@RequestMapping("/textTranslate")
public Result textTranslate(@RequestParam Map<String,String> params){
    String sourceText = params.get("content").toString();
    String source = params.get("from").toString();
    String target = params.get("to").toString();
    Integer projectId = 0;

    try {
        //实例化一个认证对象
        Credential cred = new Credential(SECRET_ID,SECRET_KEY);
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("tmt.tencentcloudapi.com");

        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);

        TmtClient client = new TmtClient(cred, "ap-guangzhou", clientProfile);
        String sendParams = "{\"SourceText\":\"" + sourceText
                + "\", \"Source\":\"" + source
                + "\",\"Target\":\"" + target
                +"\",\"ProjectId\":\"" + projectId + "\"}";
        System.out.println("传送的参数:" + sendParams);
        TextTranslateRequest req = TextTranslateRequest.fromJsonString(sendParams,TextTranslateRequest.class);
        TextTranslateResponse resp = client.TextTranslate(req);

        Result result = new Result();
        result.setDatas(TextTranslateRequest.toJsonString(resp));
        result.setResp_code(0);
        result.setResp_msg("翻译成功");
        return result;
    } catch (TencentCloudSDKException e) {
        e.printStackTrace();
        return Result.failed("翻译失败");
    }
}

一开始咋没发现这个呢,要被自己蠢哭了