首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 開發微信公眾號:接收消息與自動回復完整指南

     編輯:Java 相關知識

微信公眾號消息交互模型

微信服務器將用戶發送的消息以 HTTP POST 方式推送到開發者配置的 URL。開發者需在 5 秒內響應(否則微信斷開並重試)。消息類型分為:

接收消息類型

  • 文本消息
  • 圖片消息
  • 語音消息
  • 視頻消息
  • 小視頻消息
  • 地理位置消息
  • 鏈接消息

回復消息類型

  • 文本消息
  • 圖片消息
  • 語音消息
  • 視頻消息
  • 音樂消息
  • 圖文消息

消息 XML 結構解析

接收報文示例(文本)

<xml>
  <ToUserName><![CDATA[gh_xxxxx]]></ToUserName>
  <FromUserName><![CDATA[openid_xxx]]></FromUserName>
  <CreateTime>1348831860</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[用戶發送的文本]]></Content>
  <MsgId>1234567890123456</MsgId>
</xml>

通用字段:ToUserName(公眾號)、FromUserName(用戶 OpenID)、CreateTime(時間戳)、MsgType(類型)、MsgId(消息 ID)。各類型另有專有字段(如圖片的 PicUrl、MediaId)。

回復報文示例(文本)

<xml>
  <ToUserName><![CDATA[openid_xxx]]></ToUserName>
  <FromUserName><![CDATA[gh_xxxxx]]></FromUserName>
  <CreateTime>1348831860</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[回復給用戶的文本]]></Content>
</xml>

注意:回復的 ToUserName = 接收的 FromUserName,回復的 FromUserName = 接收的 ToUserName。

核心 Servlet 實現

@WebServlet("/wechat")
public class WechatServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        // 驗證服務器配置:signature、timestamp、nonce、echostr
        if (verifySignature(req)) {
            resp.getWriter().write(req.getParameter("echostr"));
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        
        try {
            Map<String, String> msgMap = parseXml(req);
            String respXml = buildResponse(msgMap);
            resp.getWriter().write(respXml);
        } catch (Exception e) {
            log.error("處理微信消息異常", e);
        }
    }

    private Map<String, String> parseXml(HttpServletRequest req) throws Exception {
        Map<String, String> map = new HashMap<>();
        InputStream is = req.getInputStream();
        SAXReader reader = new SAXReader();
        Document doc = reader.read(is);
        Element root = doc.getRootElement();
        for (Element e : root.elements()) {
            map.put(e.getName(), e.getText());
        }
        is.close();
        return map;
    }

    private String buildResponse(Map<String, String> msg) {
        String msgType = msg.get("MsgType");
        String from = msg.get("FromUserName");
        String to = msg.get("ToUserName");
        long now = System.currentTimeMillis() / 1000;

        // 簡單邏輯:收到文本「文本」回復文本,收到「圖片」回復圖片...
        if ("text".equals(msgType)) {
            String content = msg.get("Content");
            if ("文本".equals(content)) return buildTextMsg(from, to, now, "這是文本回復");
            if ("圖片".equals(content)) return buildImageMsg(from, to, now, "media_id_xxx");
            if ("音樂".equals(content)) return buildMusicMsg(from, to, now, "標題", "描述", "music_url", "hq_url");
            if ("圖文".equals(content)) return buildNewsMsg(from, to, now, List.of(
                new Article("標題1", "描述1", "pic_url", "url"),
                new Article("標題2", "描述2", "pic_url", "url")
            ));
            // 默認回復
            return buildTextMsg(from, to, now, "收到: " + content);
        }
        // 其他類型消息默認回復
        return buildTextMsg(from, to, now, "收到非文本消息");
    }

    // 各類構建方法省略...
    private String buildTextMsg(String to, String from, long time, String content) {
        return String.format(
            "<xml><ToUserName><![CDATA[%s]]></ToUserName>" +
            "<FromUserName><![CDATA[%s]]></FromUserName>" +
            "<CreateTime>%d</CreateTime>" +
            "<MsgType><![CDATA[text]]></MsgType>" +
            "<Content><![CDATA[%s]]></Content></xml>",
            to, from, time, content
        );
    }
}

關鍵技術點

  1. XML 解析:使用 Dom4j SAXReader 直接讀取 InputStream,避免字符串轉換導致的 "Premature end of file" 錯誤。
  2. CDATA 區塊:所有文本字段必須包裹在 <![CDATA[...]]> 中,防止特殊字符破壞 XML 結構。
  3. 5 秒響應限制:耗時邏輯(如 AI 處理、外部 API 調用)必須異步化,立即返回 "success" 或空字符串,異步通過客服消息接口主動推送結果。
  4. 簽名驗證:doGet 階段驗證 signature = SHA1(sort(token, timestamp, nonce)),確保請求來自微信服務器。
  5. 素材管理:圖片/語音/視頻/縮略圖需先上傳素材獲取 media_id,回復時引用。

進階架構建議

  • 使用 WxJava 或 WeChat-Pay-Java 成熟 SDK,封裝了消息解析、簽名驗證、素材管理、客服消息、模板消息等所有接口。
  • 採用「消息路由」模式:根據 MsgType、Event、關鍵詞分發到不同 Handler,保持 Controller 輕量。
  • 引入 Redis 緩存 Access Token、JSAPI Ticket、用戶會話上下文。
  • 異步處理:@Async + 線程池,或接入消息隊列(RabbitMQ/Kafka)削峰填谷。

總結

微信公眾號開發核心是「XML 解析 → 業務邏輯 → XML 構建」。掌握消息類型對應關係、CDATA 使用、5秒響應限制、素材管理,配合成熟 SDK 可快速構建穩健的公眾號後端。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved