微信公眾號開發小記(三)識別文字訊息
經過上一篇的講解,我們已經將自己的伺服器與微信伺服器完成對接,現在,如果你在微信公眾號上發訊息,就會產生一個請求,而這個請求就會由我們寫的CoreServlet來處理。
這次要實現的功能是,微信公眾號可以識別你傳送的文字訊息型別,比如你回覆個"你好",微信公眾號會回覆給你一句“你傳送的是文字訊息:你好”,就類似這樣的功能,我們來看該怎麼實現。
首先你要知道的是,你向微信公眾號傳送一個文字訊息,這樣會產生一個post請求給微信伺服器,而微信伺服器會將這個請求轉發給我們的伺服器,準確來說是交給我們的CoreServlet來處理。
要處理這塊我們需要檢視官方技術文件,也就是這塊---接收普通訊息

image
這個需要你自己去仔細看看,然後我們會發現我們傳送的訊息最終是一個XML資料包,看官方的一句解釋
當普通微信使用者向公眾賬號發訊息時,微信伺服器將POST訊息的XML資料包到開發者填寫的URL上。
文字訊息的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>
這裡麵包含一些引數如下
ToUserName | 開發者微訊號 |
---|---|
FromUserName | 傳送方帳號(一個OpenID) |
CreateTime | 訊息建立時間 (整型) |
MsgType | text |
Content | 文字訊息內容 |
MsgId | 訊息id,64位整型 |
也就是說,現在你往微信公眾號上傳送一段文字,然後最終會形成一個XML資料包,我們通過我們的CoreServlet去處理這個資料包,也就是這些資料包含在request當中。
那接下來的重點就是去解析request中的XML資料包了,那麼該如何解析,觀察XML資料,可以將資料存放在Map集合中,然後將XML中的資料對映成一個object物件,這其中用到了一些開源庫,首先我們需要建立一個Javabean對應著我們的文字訊息XML資料結構中的那些引數
public class TextMessage { // 開發者微訊號 private String ToUserName; // 傳送方帳號(一個OpenID) private String FromUserName; // 訊息建立時間 (整型) private long CreateTime; // 訊息型別(text/image/location/link) private String MsgType; // 訊息id,64位整型 private long MsgId; // 訊息內容 private String Content; public String getToUserName() { return ToUserName; } public void setToUserName(String toUserName) { ToUserName = toUserName; } public String getFromUserName() { return FromUserName; } public void setFromUserName(String fromUserName) { FromUserName = fromUserName; } public long getCreateTime() { return CreateTime; } public void setCreateTime(long createTime) { CreateTime = createTime; } public String getMsgType() { return MsgType; } public void setMsgType(String msgType) { MsgType = msgType; } public long getMsgId() { return MsgId; } public void setMsgId(long msgId) { MsgId = msgId; } public String getContent() { return Content; } public void setContent(String content) { Content = content; } }
接下來的重點就是要去解析我們的請求,將xml資料對映成JavaBean,我們新建一個CoreService去處理我們的請求,在C哦熱Servlet中這樣操作請求
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 將請求、響應的編碼均設定為UTF-8(防止中文亂碼) req.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8"); PrintWriter out = resp.getWriter(); CoreService coreService = new CoreService(); String s = coreService.parseWxRequest(req); // 響應訊息,將相應的xml資料轉發給微信伺服器 out.print(s); System.out.println("訊息:"+s); out.close(); }
也就是將微信請求交給CoreService去解析,到這裡要知道就是微信請求中是XML資料格式,所以我們返回給微信伺服器的也應該是Xml資料,因此,這個parseWxRequest返回的應該是一個字串,但是這個字串是一個XML資料,下面看具體的如何解析請求,下面是CoreService的具體寫法
public class CoreService { public static String parseWxRequest(HttpServletRequest request) { // xml格式的訊息資料 String respXml = null; // 預設返回的文字訊息內容 String respContent = "未知的訊息型別!"; try { // 呼叫parseXml方法解析請求訊息 Map<String, String> requestMap = MessageUtil.parseXml(request); // 傳送方帳號,一個openID String fromUserName = requestMap.get("FromUserName"); // 開發者微訊號 String toUserName = requestMap.get("ToUserName"); // 訊息型別 String msgType = requestMap.get("MsgType"); // 接收使用者傳送的文字訊息內容 String content = requestMap.get("Content"); //回覆文字訊息 TextMessage textMessage = new TextMessage(); textMessage.setToUserName(fromUserName); textMessage.setFromUserName(toUserName); textMessage.setCreateTime(System.currentTimeMillis()); textMessage.setMsgType(MessageUtil.REQ_MESSAGE_TYPE_TEXT); // 文字訊息 if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) { respContent = "你回覆的是文字訊息:"+content; textMessage.setContent(respContent); String xml = MessageUtil.messageToXml(textMessage); respXml = xml; } } catch (Exception e) { e.printStackTrace(); } return respXml; } }
可以看出這裡只是對解析後的訊息做一個響應,通過
MessageUtil.parseXml(request);
將請求中的XML資料解析出來放在Map集合當中,然後從集合中拿出資料生成一個具體的TextMessage類供我們使用,那麼具體的是如何將請求中的XML資料解析成一個Map集合呢
public class MessageUtil { // 請求訊息型別:文字 public static final String REQ_MESSAGE_TYPE_TEXT = "text"; /** * 解析微信發來的請求(XML) * * @param request * @return Map<String, String> * @throws Exception */ @SuppressWarnings("unchecked") public static Map<String, String> parseXml(HttpServletRequest request) throws Exception { // 將解析結果儲存在HashMap中 Map<String, String> map = new HashMap<String, String>(); // 從request中取得輸入流 InputStream inputStream = request.getInputStream(); // 讀取輸入流 SAXReader reader = new SAXReader(); Document document = reader.read(inputStream); // 得到xml根元素 Element root = document.getRootElement(); // 得到根元素的所有子節點 List<Element> elementList = root.elements(); // 遍歷所有子節點 for (Element e : elementList){ map.put(e.getName(), e.getText()); } // 釋放資源 inputStream.close(); inputStream = null; return map; } /** * 擴充套件xstream使其支援CDATA */ private static XStream xstream = new XStream(new XppDriver() { @Override public HierarchicalStreamWriter createWriter(Writer out) { return new PrettyPrintWriter(out) { // 對所有xml節點的轉換都增加CDATA標記 boolean cdata = true; @Override @SuppressWarnings("unchecked") public void startNode(String name, Class clazz) { super.startNode(name, clazz); } @Override protected void writeText(QuickWriter writer, String text) { if (cdata) { writer.write("<![CDATA["); writer.write(text); writer.write("]]>"); } else { writer.write(text); } } }; } }); /** * 文字訊息物件轉換成xml * * @param textMessage 文字訊息物件 * @return xml */ public static String messageToXml(TextMessage textMessage) { xstream.alias("xml", textMessage.getClass()); return xstream.toXML(textMessage); } }
我們知道微信請求是一個XML格式的資料,這個類可以將XML的資料解析成Java物件,當然也提供方法將Java物件再次轉換成XML,以便我們作為響應資料返回給微信伺服器。
這個類主要用到了dom4j和XStream,感興趣的可以研究一下,不然這塊看起來還是有點小難度的。
接下來將我們的專案打包上傳到伺服器,上傳成功之後可以在公眾號回覆一個文字測試,如下

image
未完待續