微信開發交流羣:148540125html
系列文章參考地址 極速開發微信公衆號java
歡迎留言、轉發、打賞
項目源碼參考地址 點我點我--歡迎Startgit
前幾篇文章已講完如何導入項目,如何啓動配置項目,如何成爲開發者(若是前三項不會的看這裏 極速開發微信公衆號。這篇文章就來說講若是實現消息交互web
總所周知Jfinal
開發中配置很是簡單隻要在web.xml
中添加以下代碼就能夠將全部的請求交由Jfianl
處理瀏覽器
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <filter> <filter-name>jfinal</filter-name> <filter-class>com.jfinal.core.JFinalFilter</filter-class> <async-supported>true</async-supported> <init-param> <param-name>configClass</param-name> <param-value>com.javen.common.APPConfig</param-value> </init-param> </filter> <filter-mapping> <filter-name>jfinal</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
能夠看到com.javen.common.APPConfig
是項目的核心配置文件,他是繼承自JFinalConfig
實現了以下方法微信
以上配置詳細介紹參考官方文檔
成爲開發者模式這篇文章中講到過消息交互都是由WeixinMsgController
接管的,微信開發
上面有講到消息交互都是由WeixinMsgController
接管的,她是繼承自MsgControllerAdapter
又繼承自 MsgController
裏面有個index
方法其中上面的攔截器MsgInterceptor
是進行加密驗證的(成爲開發者模式),驗證沒有問題就執行index
方法,以下圖app
能夠看出接收消息並返回一個InMsg,以後根據信息類型調用對應的抽象方法交給實現方式實現消息的處理。微信公衆平臺
那麼問題來了:
一、如何接收微信交互的xml
二、如何處理微信的各類消息
三、如何響應微信的各類消息async
成功開發者(get請求)以後,全部的消息接收處理都交由開發者url處理(post請求)因此就有一下方法獲取xml
@Before({NotAction.class}) public String getInMsgXml() { if(this.inMsgXml == null) { this.inMsgXml = HttpKit.readData(this.getRequest()); if(ApiConfigKit.getApiConfig().isEncryptMessage()) { this.inMsgXml = MsgEncryptKit.decrypt(this.inMsgXml, this.getPara("timestamp"), this.getPara("nonce"), this.getPara("msg_signature")); } } if(StrKit.isBlank(this.inMsgXml)) { throw new RuntimeException("請不要在瀏覽器中請求該鏈接,調試請查看WIKI:http://git.oschina.net/jfinal/jfinal-weixin/wikis/JFinal-weixin-demo%E5%92%8C%E8%B0%83%E8%AF%95"); } else { return this.inMsgXml; } }
解析微信的各類消息
@Before({NotAction.class}) public InMsg getInMsg() { if(this.inMsg == null) { this.inMsg = InMsgParser.parse(this.getInMsgXml()); } return this.inMsg; }
能夠看到this.inMsg
爲null時會解析InMsgParser.parse(this.getInMsgXml());
獲取到的xml
public static InMsg parse(String xml) { XmlHelper xmlHelper = XmlHelper.of(xml); return doParse(xmlHelper); }
靜態方法 經過xml 實例化一個XmlHelper
(主要提供一些經常使用類型數據的獲取方法) 再交給doParse
方法處理 text消息
image消息
voice消息
vide消息
shortvideo消息
location消息
link消息
eveen消息
private static InMsg doParse(XmlHelper xmlHelper) { String toUserName = xmlHelper.getString("//ToUserName"); String fromUserName = xmlHelper.getString("//FromUserName"); Integer createTime = Integer.valueOf(xmlHelper.getNumber("//CreateTime").intValue()); String msgType = xmlHelper.getString("//MsgType"); if("text".equals(msgType)) { return parseInTextMsg(xmlHelper, toUserName, fromUserName, createTime, msgType); } else if("image".equals(msgType)) { return parseInImageMsg(xmlHelper, toUserName, fromUserName, createTime, msgType); } else if("voice".equals(msgType)) { return parseInVoiceMsgAndInSpeechRecognitionResults(xmlHelper, toUserName, fromUserName, createTime, msgType); } else if("video".equals(msgType)) { return parseInVideoMsg(xmlHelper, toUserName, fromUserName, createTime, msgType); } else if("shortvideo".equals(msgType)) { return parseInShortVideoMsg(xmlHelper, toUserName, fromUserName, createTime, msgType); } else if("location".equals(msgType)) { return parseInLocationMsg(xmlHelper, toUserName, fromUserName, createTime, msgType); } else if("link".equals(msgType)) { return parseInLinkMsg(xmlHelper, toUserName, fromUserName, createTime, msgType); } else if("event".equals(msgType)) { return parseInEvent(xmlHelper, toUserName, fromUserName, createTime, msgType); } else { LogKit.error("沒法識別的消息類型 " + msgType + ",請查閱微信公衆平臺開發文檔"); return parseInNotDefinedMsg(toUserName, fromUserName, createTime, msgType); } }
解析出來消息類型以後就調用對應的解析方法並返回InMsg
。
消息類型不少避免重複造輪子,因此就誕生了消息的封裝這個東西。
查看全部普通消息的xml格式找規律進行封裝 官方文檔 能夠發現都包含有ToUserName
FromUserName
CreateTime
MsgId
不一樣的是 MsgType
以及 各個類型對應的消息內容。
這裏是接收消息以及響應消息的截圖
以解析 text消息
爲栗子講解
接收到的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>
解析text消息
private static InMsg parseInTextMsg(XmlHelper xmlHelper, String toUserName, String fromUserName, Integer createTime, String msgType) { InTextMsg msg = new InTextMsg(toUserName, fromUserName, createTime, msgType); msg.setContent(xmlHelper.getString("//Content")); msg.setMsgId(xmlHelper.getString("//MsgId")); return msg; }
封裝text消息
public class InTextMsg extends InMsg { private String content; private String msgId; public InTextMsg(String toUserName, String fromUserName, Integer createTime, String msgType) { super(toUserName, fromUserName, createTime, msgType); } public String getContent() { return this.content; } public void setContent(String content) { this.content = content; } public String getMsgId() { return this.msgId; } public void setMsgId(String msgId) { this.msgId = msgId; } }
接收消息的公用部分
public abstract class InMsg { protected String toUserName; protected String fromUserName; protected Integer createTime; protected String msgType; public InMsg(String toUserName, String fromUserName, Integer createTime, String msgType) { this.toUserName = toUserName; this.fromUserName = fromUserName; this.createTime = createTime; this.msgType = msgType; } public String getToUserName() { return this.toUserName; } public void setToUserName(String toUserName) { this.toUserName = toUserName; } public String getFromUserName() { return this.fromUserName; } public void setFromUserName(String fromUserName) { this.fromUserName = fromUserName; } public Integer getCreateTime() { return this.createTime; } public void setCreateTime(Integer createTime) { this.createTime = createTime; } public String getMsgType() { return this.msgType; } public void setMsgType(String msgType) { this.msgType = msgType; } }
由上分析能夠知道,消息處理完成後都是交由抽象方法的實現方法處理消息。MsgControllerAdapter
主要是適配各類消息的抽象類。
下面 text消息
爲例子說明
接收到text消息
以後會調用 WeixinMsgController
中的protected void processInTextMsg(InTextMsg inTextMsg)
方法,能夠經過InTextMsg
對象獲取text消息
protected void processInTextMsg(InTextMsg inTextMsg) { String msgContent = inTextMsg.getContent().trim(); // 幫助提示 if ("help".equalsIgnoreCase(msgContent) || "幫助".equals(msgContent)) { OutTextMsg outMsg = new OutTextMsg(inTextMsg); outMsg.setContent(helpStr); render(outMsg); }else { renderOutTextMsg("你發的內容爲:"+msgContent); //轉發給多客服PC客戶端 // OutCustomMsg outCustomMsg = new OutCustomMsg(inTextMsg); // render(outCustomMsg); } }
以上能夠看到響應消息有兩種實現方式
第一種render一個消息對象
OutTextMsg outMsg = new OutTextMsg(inTextMsg); outMsg.setContent(helpStr); render(outMsg);
第二種直接傳一個String
renderOutTextMsg("你發的內容爲:"+msgContent);
如下是具體的實現:
一、將對象轉化爲xml outMsg.toXml()
二、若是是開發模式輸出調試的xml
三、若是是加密模式,就將消息加密
四、經過Jfinal 的renderText()
方法應用xml
public void render(OutMsg outMsg) { String outMsgXml = outMsg.toXml(); if(ApiConfigKit.isDevMode()) { System.out.println("發送消息:"); System.out.println(outMsgXml); System.out.println("--------------------------------------------------------------------------------\n"); } if(ApiConfigKit.getApiConfig().isEncryptMessage()) { outMsgXml = MsgEncryptKit.encrypt(outMsgXml, this.getPara("timestamp"), this.getPara("nonce")); } this.renderText(outMsgXml, "text/xml"); }
而renderOutTextMsg(String content)
方法就是調用的render(outMsg)
方法
public void renderOutTextMsg(String content) { OutTextMsg outMsg = new OutTextMsg(this.getInMsg()); outMsg.setContent(content); this.render(outMsg); }
歡迎留言、轉發、打賞
項目源碼參考地址 點我點我--歡迎Start