微信公眾號02 接收文本消息、回復文本消息、接入百度翻譯功能


 

1 說明

  本篇博文承接上一篇博文:https://www.cnblogs.com/NeverCtrl-C/p/10241763.html

2 接收文本消息

  微信公眾號官方文檔:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140453

  說明:接收文本消息屬於接收普通消息的范圍,當公眾號粉絲向公眾號發送消息時,微信服務器會向開發者服務器發送一個POST請求,這個POST請求攜帶XML格式的數據包到開發者填寫的URL上

2.1 文本消息XML格式

<xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1348831860</CreateTime>
    <MsgType>< ![CDATA[text] ]></MsgType>
    <Content>< ![CDATA[this is a test] ]></Content>
    <MsgId>1234567890123456</MsgId>
</xml>

2.2 文本消息參數說明

參數 描述
ToUserName 開發者微信號
FromUserName 發送方帳號(一個OpenID)
CreateTime 消息創建時間 (整型)
MsgType text
Content 文本消息內容
MsgId 消息id,64位整型


step01 創建一個com.xunyji.xunyjitest.comm.TransformUtils類用來存放一下數據類型轉換相關的工具方法
2.3 Java代碼實現

step02 引入XML和對象相互轉換相關的jar包

        <!--xml2對象 start-->
        <!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <!--xml2對象 end-->

        <!--對象2XML start-->
        <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--對象2XML end-->

step03 創建com.xunyji.xunyjitest.comm.TransformUtils#xml2Map方法用於將XML轉化成Map類型

    /**
     * xml轉換成map【微信平台請求開發者平台時的數據格式都是XML格式的】
     * @param request
     * @return
     * @throws IOException
     * @throws DocumentException
     */
    public static Map<String, String> xml2Map(HttpServletRequest request) throws IOException, DocumentException {
//        01 定義Map對象用來存放數據
        Map<String, String> map = new HashMap<>();

//        02 創建SAXReader用於讀取xml文件
        SAXReader reader = new SAXReader();

//        03 讀取Request中的信息
        InputStream ins = request.getInputStream();
        Document doc = reader.read(ins);

//        04 獲取xml的根元素
        Element root = doc.getRootElement();

//        05 獲取根元素中的所有子元素
        List<Element> list = root.elements();

//        06 遍歷所有子元素並將數據存放到定義好的集合中
        for (Element e : list) {
            map.put(e.getName(), e.getText());
        }

//        07 關閉輸入流
        ins.close();

//        08 返回存放xml內容的Map對象
        return map;
    }

step04 創建一個com.xunyji.xunyjitest.web.weixin.WeixinController#receiveMessage方法用於接收微信平台發送的POST請求

  step0401 該方法接收POST請求

  step0402 通過 HttpServletRequest 對象獲取微信平台傳過來的XML數據包

  step0403 將XML數據轉化成Map數據並打印輸出

    @PostMapping
    public void receiveMessage(HttpServletRequest request, HttpServletResponse response) throws IOException, DocumentException {
//        01 請求、響應編碼格式設定
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

//        02 獲取輸出對象
        PrintWriter out = response.getWriter();
//        03 獲取微信平台傳過來的請求參數【PS:默認是XML格式的,這里轉化成了Mapl類型】
        Map<String, String> receiveMap = TransformUtils.xml2Map(request);
        log.info("接收微信消息時獲取到的信息為:" + receiveMap);

//        04 從Map對象中獲取單個數據
        String fromUserName = receiveMap.get("FromUserName");
        String toUserName = receiveMap.get("ToUserName");
        String msgType = receiveMap.get("MsgType");
        String content = receiveMap.get("Content");

    }

  step0404 啟動項目並通過粉絲賬戶向公眾號發送文本消息,效果如圖所示

 

3 回復文本消息

  回復文本消息屬於被動回復消息的范圍,微信官網提供的被動回復消息文檔:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140543

  技巧01:粉絲向公眾號發送消息時微信服務器會向開發者服務器發送一個POST請求,開發者可以從這個POST請求中獲取到一些信息,也可以像發送者返回一些信息

3.1 回復文本消息XML格式

<xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType>< ![CDATA[text] ]></MsgType>
    <Content>< ![CDATA[你好] ]></Content>
</xml>

3.2 回復文本消息參數說明

參數 是否必須 說明
ToUserName 接收方帳號(收到的OpenID)
FromUserName 開發者微信號
CreateTime 消息創建時間 (整型)
MsgType image
MediaId 通過素材管理中的接口上傳多媒體文件,得到的id。

3.3 Java代碼實現

step01 創建一個com.xunyji.xunyjitest.model.weixin.send.SendBaseMessage類作為所有被動回復消息的基類

step02 創建一個com.xunyji.xunyjitest.model.weixin.send.ReplyTextMessage類作為回復文本消息的實體類

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReplyTextMessage extends ReplyBaseMessage {
    /** 回復的消息內容(換行:在content中能夠換行,微信客戶端就支持換行顯示) */
    private String Content;
}

step03 創建一個com.xunyji.xunyjitest.comm.enums.weixin.MessageTypeEnum枚舉類來存放各種消息類型

@Getter
public enum MessageTypeEnum {
    //    接收普通消息類型【0開頭表示接收的消息類型】 start
    /** 被動回復文本消息 */
    RECEIVE_MESSAGE_TEXT(001, "text"),
    RECEIVE_MESSAGE_IMAGE(002, "image"),
    RECEIVE_MESSAGE_VOICE(003, "voice"),
    RECEIVE_MESSAGE_LOCATION(004, "location"),
    RECEIVE_MESSAGE_LINK(005, "link"),
    RECEIVE_MESSAGE_SHORTVIDEO(06, "shortvideo"),
    RECEIVE_MESSAGE_VIDEO(007, "video"),
//    接收普通消息類型【0開頭表示接收的消息類型】 end
    ;
    /** 消息類型編號 */
    private Integer code;
    /** 消息類型(和微信文檔中保持一致) */
    private String type;

    MessageTypeEnum(Integer code, String type) {
        this.code = code;
        this.type = type;
    }
}

step04 創建一個com.xunyji.xunyjitest.comm.util.weixin.MessageUtils類作為各種消息封裝類

  step0401 創建com.xunyji.xunyjitest.comm.util.weixin.MessageUtils#replyTextMessageToXml方法實現將ReplyTextMessage 轉化成 XML

    /**
     * ReplyTextMessage 轉化成 XML
     * @param replyTextMessage
     * @return
     */
    private String replyTextMessageToXml(ReplyTextMessage replyTextMessage) {
        XStream xStream = new XStream();
        xStream.alias("xml", replyTextMessage.getClass());
        return xStream.toXML(replyTextMessage);
    }

  step0402 創建com.xunyji.xunyjitest.comm.util.weixin.MessageUtils#initReplyTextMessage方法實現封裝回復文本消息時所需的XML格式字符串

    /**
     * 封裝XML格式的"發送文本消息"
     * @param fromUserName 粉絲appId
     * @param toUserName 公眾號appId
     * @param content XML格式的字符串
     * @return
     */
    public String initReplyTextMessage(String fromUserName, String toUserName, String content) {
        ReplyTextMessage text = new ReplyTextMessage();
        text.setToUserName(fromUserName);
        text.setFromUserName(toUserName);
        text.setMsgType(MessageTypeEnum.RECEIVE_MESSAGE_TEXT.getType());
        long time = System.currentTimeMillis();
        text.setCreateTime(String.valueOf(time));
        text.setContent("逆向公眾號發送了:" + content);
        return replyTextMessageToXml(text);
    }

step05 重構com.xunyji.xunyjitest.web.weixin.WeixinController#receiveMessage方法實現接收文本消息時回復文本消息,其他消息不做任何處理

  step0501 從封裝了請求數據的map集合中獲取公眾號appid(toUserName)、粉絲appid(fromUserName)、接收消息類型(msgType)

  step0502 判斷接收消息類型並做相應處理,此處以接收到的消息類型為文本消息為例

    如果是文本消息就獲取文本內容,然后封裝響應數據即可

  step0503 必須對響應數據進行非空處理,因為如果響應數據為null就會出現一個錯誤,很影響用戶體驗

    @PostMapping
    public void receiveMessage(HttpServletRequest request, HttpServletResponse response) throws IOException, DocumentException {
//        01 請求、響應編碼格式設定
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

//        02 獲取輸出對象
        PrintWriter out = response.getWriter();
//        03 獲取微信平台傳過來的請求參數【PS:默認是XML格式的,這里轉化成了Mapl類型】
        Map<String, String> receiveMap = TransformUtils.xml2Map(request);
        log.info("接收微信消息時獲取到的信息為:" + receiveMap);

//        04 從Map對象中獲取單個數據
        String fromUserName = receiveMap.get("FromUserName");
        String toUserName = receiveMap.get("ToUserName");
        String msgType = receiveMap.get("MsgType");

//        05 用於存放String類型的XML格式響應數據
        String message = null;
//        06 如果接收的消息類型是text類型的處理邏輯
        if (MessageTypeEnum.RECEIVE_MESSAGE_TEXT.getType().equals(msgType)) {
            String content = receiveMap.get("Content");
            message = new MessageUtils().initReplyTextMessage(fromUserName, toUserName, content);
        }
//        07 響應對象非空處理,如果返回null會報異常(影響用戶體驗)
        if (message == null) {
            message = "";
        }
//        08 打印XML格式的響應消息
        log.info("被動回復消息的XML格式為:" + message);
//        09 響應XML格式數據給微信服務器
        out.print(message);

    }
View Code

 step06 啟動項目並向公眾號發送文本消息,效果如圖所示

 

3.4 代碼重構

  應該根據不同的消息類型調用不同的服務層方法來實現業務邏輯,不應該將所有業務邏輯都放到controller層中

step01 引入fastjson依賴,因為需要將Map轉化成Bean

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.54</version>
        </dependency>

step02 創建com.xunyji.xunyjitest.service.ReceiveMessageService接口用於定義處理各種接收到的消息

step03 創建com.xunyji.xunyjitest.service.ReceiveMessageServiceImpl實現了實現處理各種接收到的消息

step04 創建com.xunyji.xunyjitest.comm.TransformUtils#parseMap2Object方法用於將Map轉化成Bean

    /**
     * Map類型轉化成指定類型
     * @param paramMap 待轉化的Map對象
     * @param clazz 目標類型的類類型
     * @param <T> 目標類型
     * @return
     */
    public static <T> T parseMap2Object(Map<String, String> paramMap, Class<T> clazz) {
        return JSONObject.parseObject(JSONObject.toJSONString(paramMap), clazz);
    }

step05 創建com.xunyji.xunyjitest.service.ReceiveMessageServiceImpl#textMessageHandler方法用於處理文本類型消息

    @Override
    public String textMessageHandler(Map<String, String> receiveParam) {
//        01 用於存放封裝好的回復文本消息的XML數據
        String message = null;
//        02 將Map類型參數轉化成ReceiveTextMessage類型
        ReceiveTextMessage receiveTextMessage = TransformUtils.parseMap2Object(receiveParam, ReceiveTextMessage.class);
        log.info("接收到的text消息請求參數為:" + receiveTextMessage);

//        03 獲取文本內容和雙方信息
//        0301 粉絲appId
        String fromUserName = receiveTextMessage.getFromUserName();
//        0302 公眾號appId
        String toUserName = receiveTextMessage.getToUserName();
//        0303 接收到的文本內容
        String content = receiveTextMessage.getContent();
        content = content.trim();

//        04 根據文本內容響應不同的數據 TODO: 應該將接收到的消息信息存儲到數據庫或者緩存中
        if ("1".equals(content)) {
            message = messageUtils.initReplyTextMessage(fromUserName, toUserName, messageUtils.firstMenu());
        } else if ("2".equals(content)) {
            message = messageUtils.initReplyTextMessage(fromUserName, toUserName, messageUtils.secondMenu());
        } else if ("?".equals(content) || "?".equals(content)) {
            message = messageUtils.initReplyTextMessage(fromUserName, toUserName, messageUtils.menuText());
        } else {
            message = messageUtils.initReplyTextMessage(fromUserName, toUserName, content);
        }

        return message;
    }
View Code

step06 在com.xunyji.xunyjitest.web.weixin.WeixinController#receiveMessage方法中,如果是文本消息類型就調用com.xunyji.xunyjitest.service.ReceiveMessageService#textMessageHandler實現業務處理

step07 啟動應用並以此發送 1、2、?、?,效果圖如下:

 

 

4 接入百度翻譯功能

4.1 百度翻譯開放平台

  官網地址:http://api.fanyi.baidu.com/api/trans/product/index

  說明:進入到百度翻譯平台官網過后需要注冊一個開發者賬號,注冊的時候填入相關信息即可

4.2 通用翻譯API技術文檔

  官網文檔地址:http://api.fanyi.baidu.com/api/trans/product/apidoc

  技巧01:百度通用翻譯API提供了URL,開發者只需要根據文檔說明訪問這個URL即可

step01 通用翻譯API的地址:http://api.fanyi.baidu.com/api/trans/vip/translate  或者  https://fanyi-api.baidu.com/api/trans/vip/translate

step02 可以向兩個url地址發送GET請求或者POST請求,但是必須攜帶如下參數(PS:是指請求參數,即url后面跟的那種參數)

  技巧01:為保證翻譯質量,請將單次請求長度控制在 6000 bytes以內。(漢字約為2000個)

字段名 類型 必填參數 描述 備注
q TEXT Y 請求翻譯query UTF-8編碼
from TEXT Y 翻譯源語言 語言列表(可設置為auto)
to TEXT Y 譯文語言 語言列表(不可設置為auto)
appid INT Y APP ID 可在管理控制台查看
salt INT Y 隨機數  
sign TEXT Y 簽名 appid+q+salt+密鑰 的MD5值

step03 簽名生成規則

  step0301 將請求參數中的 APPID(appid), 翻譯query(q, 注意為UTF-8編碼), 隨機數(salt), 以及平台分配的密鑰(可在管理控制台查看)

按照 appid+q+salt+密鑰 的順序拼接得到字符串1。

  step0302 對字符串1做md5,得到32位小寫的sign(PS:簽名是為了保證調用安全,使用MD5算法生成的一段字符串,生成的簽名長度為 32位,簽名中的英文字符均為小寫格式)

step04 注意事項

  step0401 請先將需要翻譯的文本轉換為UTF-8編碼

  step0402 在發送HTTP請求之前需要對各字段做URL encode

  step0403 在生成簽名拼接 appid+q+salt+密鑰 字符串時,q不需要做URL encode,在生成簽名之后,發送HTTP請求之前才需要對要發送的待翻譯文本字段q做URL encode。

step05 響應的JSON格式說明

字段名 類型 描述
from TEXT 翻譯源語言
to TEXT 譯文語言
trans_result MIXED LIST 翻譯結果
src TEXT 原文
dst TEXT 譯文

4.3 官方Demo實現

step01 官方demo下載地址:https://fanyiapp.cdn.bcebos.com/api/demo/java.zip ,官方demo文件說明如下圖所示

step02 將這個三個文件拷貝到項目中

step03 測試官方提供的demo

4.4 自定義翻譯demo

  說明:百度翻譯官方提供的demo中使用的是java提供的HttpURLConnection進行遠程調用的,而我比較喜歡用RestTemplate實現第三方的服務調用;該系列文章之后的文章中調用你微信公眾號平台的相關url時也是使用RestTemplate進行調用,所以這里創建一個由RestTemplate實現的HTTP工具類

step01 創建一個com.xunyji.xunyjitest.config.CreatBeanConfig類來創建項目所需的Bean

  技巧01:需要在類級別添加 @Configuration 來指明該類是一個配置類,@Configuration 標注的類相當於一個XML配置類

step02 創建com.xunyji.testdemo.comm.config.CreatBeanConfig#restTemplate方法來創建RestTemplate對應的Bean

  技巧01:注意亂碼問題,參考博文 -> https://blog.csdn.net/papamilk/article/details/80000683

  坑01:解決亂碼問題時需要使用到HttpClient相關的jar包

        <!--httpclient start-->
        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.6</version>
        </dependency>
        <!--httpclient end-->

 

step03 在application-dev.yml文件中配置百度翻譯所需的賬號和url信息

step04 創建相關實體類來讀取step03里面配置的信息,這里的配置有三層,所以需要兩個百度翻譯相關的配置實體類

 

step05 創建MD5加密工具類com.xunyji.xunyjitest.comm.util.Md5Utils

package com.xunyji.testdemo.util;

import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @author AltEnter
 * @create 2019-01-09 10:13
 * @desc MD5編碼工具類
 **/
public class Md5Utils {

    // 首先初始化一個字符數組,用來存放每個16進制字符
    private static final char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
            'e', 'f' };

    /**
     * 獲得一個字符串的MD5值
     * @param input 輸入的字符串
     * @return 輸入字符串的MD5值
     *
     */
    public static String md5(String input) {
        if (input == null) {
            return null;
        }

        try {
            // 拿到一個MD5轉換器(如果想要SHA1參數換成”SHA1”)
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            // 輸入的字符串轉換成字節數組
            byte[] inputByteArray = input.getBytes("utf-8");
            // inputByteArray是輸入字符串轉換得到的字節數組
            messageDigest.update(inputByteArray);
            // 轉換並返回結果,也是字節數組,包含16個元素
            byte[] resultByteArray = messageDigest.digest();
            // 字符數組轉換成字符串返回
            return byteArrayToHex(resultByteArray);
        } catch (NoSuchAlgorithmException e) {
            return null;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 獲取文件的MD5值
     *
     * @param file
     * @return
     */
    public static String md5(File file) {
        try {
            if (!file.isFile()) {
                System.err.println("文件" + file.getAbsolutePath() + "不存在或者不是文件");
                return null;
            }

            FileInputStream in = new FileInputStream(file);

            String result = md5(in);

            in.close();

            return result;

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 獲取一個輸入流的MD5值
     * @param in
     * @return
     */
    public static String md5(InputStream in) {

        try {
            MessageDigest messagedigest = MessageDigest.getInstance("MD5");

            byte[] buffer = new byte[1024];
            int read = 0;
            while ((read = in.read(buffer)) != -1) {
                messagedigest.update(buffer, 0, read);
            }

            in.close();

            String result = byteArrayToHex(messagedigest.digest());

            return result;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 獲取一個字節數組的MD5值
     * @param byteArray
     * @return
     */
    private static String byteArrayToHex(byte[] byteArray) {
        // new一個字符數組,這個就是用來組成結果字符串的(解釋一下:一個byte是八位二進制,也就是2位十六進制字符(2的8次方等於16的2次方))
        char[] resultCharArray = new char[byteArray.length * 2];
        // 遍歷字節數組,通過位運算(位運算效率高),轉換成字符放到字符數組中去
        int index = 0;
        for (byte b : byteArray) {
            resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];
            resultCharArray[index++] = hexDigits[b & 0xf];
        }

        // 字符數組組合成字符串返回
        return new String(resultCharArray);

    }

}
Md5Utils.java

step06 創建HTTP請求方法工具類com.xunyji.xunyjitest.comm.util.HttpMethodUtils

package com.xunyji.xunyjitest.comm.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;

/**
 * @author AltEnter
 * @create 2019-01-10 21:20
 * @desc HTTP請求方法工具類
 **/
@Component
@Slf4j
public class HttpMethodUtils {
    @Autowired
    private RestTemplate restTemplate;

    /**
     * get請求方法封裝【利用RestTemplate實現】
     * @param url
     * @return
     */
    public String doGetStrByRestTemplate(String url) {
        String result = null;
        result = restTemplate.getForObject(url, String.class);
        return result;
    }

    /**
     * get請求方法封裝【利用RestTemplate實現】
     * @param url
     * @return
     */
    public Map doGetMapByRestTemplate(String url) {
        Map result = null;
//        RestTemplate restTemplate = new RestTemplate();
        result = restTemplate.getForObject(url, Map.class);
        return result;
    }


    /**
     * get請求方法封裝【利用RestTemplate實現】
     * @param url 請求路徑【不帶參數的和帶參數的url都可以】
     * @param params 請求路徑參數
     * @return
     */
    public String doGetStrWithMapParamByRestTemplate(String url, Map<String, String> params) throws UnsupportedEncodingException {
        String result = null;

        String query = URLEncoder.encode(params.get("q"), "UTF-8");

        log.info("加密前請求參數為:" + params);

//        封裝get請求的完整url
        String sendUrl = getUrlWithQueryString(url, params);
        log.info("參數加密后的請求URL為:" + sendUrl);
        result = restTemplate.getForObject(sendUrl, String.class);

        return result;
    }

    /**
     * get請求方法封裝【利用RestTemplate實現】
     * @param url
     * @return
     */
    public Map doGetMapWithMapByRestTemplate(String url, Map<String, String> params) throws UnsupportedEncodingException {

        Map result = null;

        String query = URLEncoder.encode(params.get("q"), "UTF-8");

        log.info("加密前請求參數為:" + params);

//        封裝get請求的完整url
        String sendUrl = getUrlWithQueryString(url, params);
        log.info("加密后請求參數為:" + sendUrl);
        result = restTemplate.getForObject(sendUrl, Map.class);
        return result;
    }

    /**
     * 將不帶參數的url和Map類型的參數封裝成一個帶參數的url
     * @param url
     * @param params
     * @return
     */
    private 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);
            // 過濾空的key
            if (value == null) {
                continue;
            }

            if (i != 0) {
                builder.append('&');
            }

            builder.append(key);
            builder.append('=');
//            builder.append(encode(value)); // 如果使用RestTemplate請求時就不需要進行UrlEncode進行加密了,加密了反而會報錯
            builder.append(value);

            i++;
        }

        return builder.toString();
    }

    /**
     * 對輸入的字符串進行URL編碼, 即轉換為%20這種形式
     *
     * @param input 原文
     * @return URL編碼. 如果編碼失敗, 則返回原文
     */
    public static String encode(String input) {
        if (input == null) {
            return "";
        }

        try {
            return URLEncoder.encode(input, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return input;
    }
}
HttpMethodUtils.java

step07 創建對象互轉工具類 com.xunyji.xunyjitest.comm.util.TransformUtils

package com.xunyji.xunyjitest.comm.util;

import com.alibaba.fastjson.JSONObject;

import java.util.Map;

/**
 * @author AltEnter
 * @create 2019-01-07 8:37
 * @desc 各種類型轉化工具類
 **/
public class TransformUtils {
    /**
     * Map類型轉化成指定類型
     * @param paramMap 待轉化的Map對象
     * @param clazz 目標類型的類類型
     * @param <T> 目標類型
     * @return
     */
    public static <T> T parseMap2Object(Map<String, String> paramMap, Class<T> clazz) {
        return JSONObject.parseObject(JSONObject.toJSONString(paramMap), clazz);
    }

    /**
     * String類型轉化成指定類型
     * @param str 帶轉化的String對象
     * @param clazz 目標類型的類類型
     * @param <T> 目標類型
     * @return
     */
    public static <T> T parseStr2Object(String str, Class<T> clazz) {
        return JSONObject.parseObject(str, clazz);
    }

    /**
     * unicode 2 utf
     * @param theString
     * @return String
     */
    public static String unicodeToUtf8(String theString) {
        char aChar;
        int len = theString.length();
        StringBuffer outBuffer = new StringBuffer(len);
        for (int x = 0; x < len;) {
            aChar = theString.charAt(x++);
            if (aChar == '\\') {
                aChar = theString.charAt(x++);
                if (aChar == 'u') {
                    // Read the xxxx
                    int value = 0;
                    for (int i = 0; i < 4; i++) {
                        aChar = theString.charAt(x++);
                        switch (aChar) {
                            case '0':
                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                value = (value << 4) + aChar - '0';
                                break;
                            case 'a':
                            case 'b':
                            case 'c':
                            case 'd':
                            case 'e':
                            case 'f':
                                value = (value << 4) + 10 + aChar - 'a';
                                break;
                            case 'A':
                            case 'B':
                            case 'C':
                            case 'D':
                            case 'E':
                            case 'F':
                                value = (value << 4) + 10 + aChar - 'A';
                                break;
                            default:
                                throw new IllegalArgumentException(
                                        "Malformed   \\uxxxx   encoding.");
                        }
                    }
                    outBuffer.append((char) value);
                } else {
                    if (aChar == 't')
                        aChar = '\t';
                    else if (aChar == 'r')
                        aChar = '\r';
                    else if (aChar == 'n')
                        aChar = '\n';
                    else if (aChar == 'f')
                        aChar = '\f';
                    outBuffer.append(aChar);
                }
            } else
                outBuffer.append(aChar);
        }
        return outBuffer.toString();
    }


}
TransformUtils.java

step08 創建百度翻譯響應實體類com.xunyji.xunyjitest.model.baidu.TranslationResponse  com.xunyji.xunyjitest.model.baidu.TransResult

package com.xunyji.xunyjitest.model.baidu;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author AltEnter
 * @create 2019-01-09 16:07
 * @desc 翻譯請求響應數據封裝實體類
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TranslationResponse {
    /** 翻譯源語言 */
    private String from;
    /** 譯文語言 */
    private String to;
    /** 翻譯結果 */
    private TransResult[] trans_result;
}
TranslationResponse.java
package com.xunyji.xunyjitest.model.baidu;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author AltEnter
 * @create 2019-01-09 16:09
 * @desc 翻譯結果
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TransResult {
    /** 翻譯源文本 */
    private String src;
    /** 譯文文本 */
    private String dst;
}
TransResult.java

step09 創建百度翻譯API封裝類com.xunyji.xunyjitest.comm.util.BaiduTransApi

package com.xunyji.xunyjitest.comm.util;

import com.xunyji.xunyjitest.config.baidu.BaiduBaseConfig;
import com.xunyji.xunyjitest.model.baidu.TransResult;
import com.xunyji.xunyjitest.model.baidu.TranslationResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author AltEnter
 * @create 2019-01-09 10:28
 * @desc 百度翻譯API封裝
 **/
@Component
@Slf4j
public class BaiduTransApi {

    @Autowired
    private HttpMethodUtils httpMethodUtils;

    @Autowired
    private BaiduBaseConfig baiduBaseConfig;

    /**
     * 發送get請求進行翻譯
     * @param query
     * @param from
     * @param to
     * @return
     */
    public String getTransStrResult(String query, String from, String to) throws UnsupportedEncodingException {
        Map<String, String> params = buildParams(query, from, to);
        // 調用自定義的get方法
        String restStr = httpMethodUtils.doGetStrWithMapParamByRestTemplate(baiduBaseConfig.getTranslation().getTransApiHost(), params);
        String result = TransformUtils.unicodeToUtf8(restStr);
        TranslationResponse translationResponse = TransformUtils.parseStr2Object(result, TranslationResponse.class);
        log.info("翻譯請求結果為:" + translationResponse.toString());
        TransResult transResult = translationResponse.getTrans_result()[0];
        return String.format("%s -> %s", transResult.getSrc(), transResult.getDst());
        // 調用官方提供的get方法
//        return HttpGet.get(baiduBaseConfig.getTranslation().getTransApiHost(), params);
    }

    public Map<String, String> getTransMapResult(String query, String from, String to) throws UnsupportedEncodingException {
        Map<String, String> params = buildParams(query, from, to);
        // 調用自定義的get方法
        Map<String, String> restMap = httpMethodUtils.doGetMapWithMapByRestTemplate(baiduBaseConfig.getTranslation().getTransApiHost(), params);
        String trans_result = restMap.get("trans_result");
        return restMap;
        // 調用官方提供的get方法
//        return HttpGet.get(baiduBaseConfig.getTranslation().getTransApiHost(), params);
    }



    /**
     * 構建請求參數
     * @param query
     * @param from
     * @param to
     * @return
     */
    private Map<String, String> buildParams(String query, String from, String to) {

        String appid = baiduBaseConfig.getTranslation().getAppId();
        String securityKey = baiduBaseConfig.getTranslation().getSecurityKey();

//        String appid = "20190109000255665";
//        String securityKey = "iNPVhM9qtM3Kb0ZTesI9";

        Map<String, String> params = new HashMap<String, String>();
        params.put("q", query);
        params.put("from", from);
        params.put("to", to);
        params.put("appid", appid);

        // 隨機數
        String salt = String.valueOf(System.currentTimeMillis());
        params.put("salt", salt);

        // 簽名
        String src = appid + query + salt + securityKey; // 加密前的原文
        log.info("加密前的簽名:" + src);
        String sign = Md5Utils.md5(src);
        params.put("sign", sign);
        log.info("加密后的簽名:" + sign);

        return params;
    }



}
BaiduTransApi.java

step10  調用com.xunyji.xunyjitest.comm.util.BaiduTransApi#getTransStrResult進行測試即可

  坑01:利用restTemplate調用百度翻譯平台的url是不需要對參數進行urlEncoder加密,否則會報錯:sign錯誤

 4.5 接入百度翻譯

step01 翻譯文本格式說明 ->需要翻譯的內容也是text類型額數據,翻譯文本內容的格式如下

    en翻譯足球 -> 表示將'足球'翻譯成英文

    zh翻譯football -> 表示將'football'翻譯成中文

    zh翻譯 -> 調出此菜單

    en翻譯 -> 調出此菜單

step02 創建com.xunyji.testdemo.util.weixin.MessageUtil#threeMenu方法作為翻譯格式的提示信息封裝方法

step03 創建com.xunyji.testdemo.util.weixin.BaiduTransApi#getTransStrResult方法來對百度翻譯api進行再一次封裝

step04 重構com.xunyji.xunyjitest.service.ReceiveMessageServiceImpl#textMessageHandler中的邏輯來實現翻譯功能

step05 啟動應用,測試效果如下

掃碼獲取源代碼

 

 


免責聲明!

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



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