微信公众号开发教程(二)消息接收与响应处理
作者:陳惠,叩丁狼教育高級講師。原創文章,轉載請注明出處。
上一篇文章我們已經實現了URL接入,接下來就可以利用微信官方的開發文檔來實現不同的案例。(注意:若還沒有進行接入操作,請參考開發教程(一))
實現思路
接下來我們先打開微信的開發文檔,選擇“消息管理”模塊中的”接收普通消息“。
文檔中已經告訴我們,當普通微信用戶向公眾賬號發送消息時,微信服務器會把該消息封裝成XML數據包通過POST的方式發送到開發者填寫的URL上。我們設置的URL僅僅只有一個,上篇文章中是用來做接入驗證的,當時是微信服務器發送GET請求過來,而現在是用來做消息處理的,此時微信服務器發送的是POST請求,因此想要區分開來應該做什么事情,只需要根據請求方式來判斷即可。
因此,我們需要再創建一個handleMessage方法來做消息處理。
觀察圖中的兩個方法,其實就是請求路徑相同,但請求方式不同,一個是GET方式一個是POST方式。
參數理解
現在我們再來看下開發文檔,當用戶發送普通消息到公眾號,微信服務器發送的XML數據中會包含下面的參數。
如果是圖片消息會包含下面的參數
實際上,用戶可發送的類型還有很多,比如語音,視頻,地理位置等等。
我們對比一下不同類型的xml數據包中的參數,ToUserName,FromUserName,CreateTime,MsgType,MsgId這五個是公共的,所有類型都會帶上這些參數。
接下來,我們需要來了解這5個參數的具體意義。
ToUserName:文檔上描述的是開發者微信號,實際上,直接把它當做你的公眾號的微信號即可,表示的是發到那個公眾號的意思。
FromUserName:與ToUserName相反,這是代表是由哪個用戶發過來的,同一個用戶發多條信息過來,FromUserName都是不變的。但這并不是用戶的微信號,而是一個OpenID。
那什么是OpenID呢:當用戶和公眾號發生了交互,微信服務器會為每個用戶針對每個公眾號產生一個OpenID(也就是指該OpenID是利用兩個因素:用戶和公眾號來產生的,也就意味著如果該用戶跟另外一個公眾號交互,產生的OpenID也是不同的,這樣安全性會比較高),如果一個公司有多個公眾號,并且需要在多公眾號、移動應用之間做用戶共通,則需要使用UnionID,前往微信開放平臺,將這些公眾號和應用綁定到一個開放平臺賬號下,綁定后,一個用戶雖然對多個公眾號和應用有多個不同的OpenID,但他對所有這些同一開放平臺賬號下的公眾號和應用,只有一個UnionID,可以在用戶管理-獲取用戶基本信息(UnionID機制)文檔了解詳情。
CreateTime:消息創建時間,這個沒什么好說的了。
MsgType:用戶發送的消息的類型,如text代表文本消息,image代表圖片消息等。
MsgId:用戶發送的每個消息都有自己的id,可以用于消息排重,比如微信服務器把xml消息包發送到URL了,但是五秒內微信服務器沒有收到我們的響應,則會重新發起請求,總共重試三次。如果不做消息排重,那么用戶可能就收到多條相同的響應消息了。
接下來,我們可以創建一個封裝消息的實體類,把所有可接收到的參數都放進入,其他類型的暫時不演示,所以只在最后加入了文本和圖片的參數。
@Setter @Getter public class InMsgEntity {// 開發者微信號protected String FromUserName;// 發送方帳號(一個OpenID)protected String ToUserName;// 消息創建時間protected Long CreateTime;/*** 消息類型* text 文本消息* image 圖片消息* voice 語音消息* video 視頻消息* music 音樂消息*/protected String MsgType;// 消息idprotected Long MsgId;// 文本內容private String Content;// 圖片鏈接(由系統生成)private String PicUrl;// 圖片消息媒體id,可以調用多媒體文件下載接口拉取數據private String MediaId; }這時候大家可能會有個疑問,為什么字段名稱都是大寫開頭呢?
因為微信服務器傳過來的xml數據包中的xml元素都是大寫開頭的,如下所示:
因為xml解析是大小寫敏感的,所以為了方便封裝,我直接把字段名設置為大寫開頭。
當然,如果還是想要小寫開頭的字段,也是可以的,我們待會再說處理方式。
接收消息
實體已經建好之后,我們就可以開始接收微信傳過來的xml數據了。
第1步:在handleMessage方法的形參上添加InMsgEntity類型的參數,并且貼上@RequestBody注解,如下代碼所示:
@RequestBody?該注解用于讀取request請求的body部分數據,根據Content-Type來判斷把數據當做什么類型來解析,然后把相應的數據綁定到參數上。
第2步:需要配合JAXB的注解來解析xml。
在 InMsgEntity 上添加以下兩個注解:
@XmlRootElement是一個類級別注解,主要屬性為name,意為指定根節點的名字。
往上面看前面舉了個微信傳過來的xml數據的例子里,里面的根節點就是”xml”,所以這里就直接設置name=”xml”
@XmlAccessorType用于定義這個類中的何種類型需要映射到XML中
XmlAccessType.PROPERTY:代表映射這個類中的屬性(get/set方法)到XML
XmlAccessType.FIELD:代表映射這個類中的所有字段到XML(我選用的,現在的字段名剛好是大寫開頭了)
另外,剛才說到如果字段名是小寫,怎么解決封裝問題?
在每個字段或屬性上添加@XmlElement注解來指定名稱映射
如:
JAXB還有非常多的注解和類型,這里只介紹我所用到的,如需了解其他請自行百度。
現在我們可以掃描自己的公眾號二維碼來測試發送消息后臺服務器是否能接收到。
通過debug可知,微信傳過來的xml消息包已經成功轉換為我們的java對象了。
響應消息
現在我們可以先來嘗試回復一條相同的內容給用戶。
打開微信開發文檔,選擇”被動回復消息”。
發送被動消息其實不是一種接口,而是對微信服務器發過來消息的一次回復。
我們可以看到文檔里面接收的普通文本回復的格式和接收的格式基本是一樣的,但是圖片消息或其他消息的還是有些區別。
<xml> <ToUserName>< ![CDATA[toUser] ]></ToUserName> <FromUserName>< ![CDATA[fromUser] ]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType>< ![CDATA[image] ]></MsgType> <Image><MediaId>< ![CDATA[media_id] ]></MediaId> </Image> </xml>如上例子,比之前多了Image的元素,所以我們需要再創建一個類來封裝響應的xml消息。
這里我是把所有類型的屬性統一放到OutMsgEntity類中,大家也可以抽取一個父類,不同的消息創建不同的子類也可以。
@XmlElementWrapper注解可以在原xml結點上再包裝一層xml,但僅允許出現在數組或集合屬性上。
實際上,我們現在的需求比較簡單,用戶給我們發什么,我們就回復什么,只需要把接收到 InMsgEntity 的內容設置到 OutMsgEntity 上,并且把ToUserName與FormUserName的值設置為相反即可。
代碼如下:
/*** 微信消息處理*/@RequestMapping(value = "/weChat", method = RequestMethod.POST)@ResponseBodypublic Object handleMessage(@RequestBody InMsgEntity msg) {//創建消息響應對象OutMsgEntity out = new OutMsgEntity();//把原來的發送方設置為接收方out.setToUserName(msg.getFromUserName());//把原來的接收方設置為發送方out.setFromUserName(msg.getToUserName());//獲取接收的消息類型String msgType = msg.getMsgType();//設置消息的響應類型out.setMsgType(msgType);//設置消息創建時間out.setCreateTime(new Date().getTime());//根據類型設置不同的消息數據if("text".equals(msgType)){out.setContent(msg.getContent());}else if("image".equals(msgType)){out.setMediaId(new String[]{msg.getMediaId()});}return out;}測試效果:
到此,我們已經實現了對消息的接收和響應簡單操作。
總結
以上是生活随笔為你收集整理的微信公众号开发教程(二)消息接收与响应处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tableau 中国最美八条骑行线路(三
- 下一篇: tableau的骑行路线地理数据可视化