1. 程式人生 > >微信公眾號02 接收文字訊息、回覆文字訊息、接入百度翻譯功能

微信公眾號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 接入百度翻譯功能

  待定更新時間:2019年1月10日23:23:02

掃碼獲取原始碼