微信公眾號開發(fā)教程(二)消息接收與響應(yīng)處理

作者:陳惠,叩丁狼教育高級講師摇零。原創(chuàng)文章推掸,轉(zhuǎn)載請注明出處。

上一篇文章我們已經(jīng)實(shí)現(xiàn)了URL接入驻仅,接下來就可以利用微信官方的開發(fā)文檔來實(shí)現(xiàn)不同的案例终佛。(注意:若還沒有進(jìn)行接入操作,請參考開發(fā)教程(一))

實(shí)現(xiàn)思路

接下來我們先打開微信的開發(fā)文檔雾家,選擇“消息管理”模塊中的”接收普通消息“铃彰。

文檔.png

文檔中已經(jīng)告訴我們,當(dāng)普通微信用戶向公眾賬號發(fā)送消息時芯咧,微信服務(wù)器會把該消息封裝成XML數(shù)據(jù)包通過POST的方式發(fā)送到開發(fā)者填寫的URL上牙捉。我們設(shè)置的URL僅僅只有一個,上篇文章中是用來做接入驗(yàn)證的敬飒,當(dāng)時是微信服務(wù)器發(fā)送GET請求過來邪铲,而現(xiàn)在是用來做消息處理的,此時微信服務(wù)器發(fā)送的是POST請求无拗,因此想要區(qū)分開來應(yīng)該做什么事情带到,只需要根據(jù)請求方式來判斷即可。

因此英染,我們需要再創(chuàng)建一個handleMessage方法來做消息處理揽惹。

方法簽名.png

觀察圖中的兩個方法,其實(shí)就是請求路徑相同四康,但請求方式不同搪搏,一個是GET方式一個是POST方式。

參數(shù)理解

現(xiàn)在我們再來看下開發(fā)文檔闪金,當(dāng)用戶發(fā)送普通消息到公眾號疯溺,微信服務(wù)器發(fā)送的XML數(shù)據(jù)中會包含下面的參數(shù)。

普通消息*.png

如果是圖片消息會包含下面的參數(shù)

圖片消息.png

實(shí)際上哎垦,用戶可發(fā)送的類型還有很多囱嫩,比如語音,視頻漏设,地理位置等等墨闲。
我們對比一下不同類型的xml數(shù)據(jù)包中的參數(shù),ToUserName愿题,F(xiàn)romUserName损俭,CreateTime蛙奖,MsgType,MsgId這五個是公共的杆兵,所有類型都會帶上這些參數(shù)雁仲。

接下來,我們需要來了解這5個參數(shù)的具體意義琐脏。

ToUserName:文檔上描述的是開發(fā)者微信號攒砖,實(shí)際上,直接把它當(dāng)做你的公眾號的微信號即可日裙,表示的是發(fā)到那個公眾號的意思吹艇。
FromUserName:與ToUserName相反,這是代表是由哪個用戶發(fā)過來的昂拂,同一個用戶發(fā)多條信息過來受神,F(xiàn)romUserName都是不變的。但這并不是用戶的微信號格侯,而是一個OpenID鼻听。
那什么是OpenID呢:當(dāng)用戶和公眾號發(fā)生了交互,微信服務(wù)器會為每個用戶針對每個公眾號產(chǎn)生一個OpenID(也就是指該OpenID是利用兩個因素:用戶和公眾號來產(chǎn)生的联四,也就意味著如果該用戶跟另外一個公眾號交互撑碴,產(chǎn)生的OpenID也是不同的,這樣安全性會比較高)朝墩,如果一個公司有多個公眾號醉拓,并且需要在多公眾號、移動應(yīng)用之間做用戶共通收苏,則需要使用UnionID亿卤,前往微信開放平臺,將這些公眾號和應(yīng)用綁定到一個開放平臺賬號下倒戏,綁定后怠噪,一個用戶雖然對多個公眾號和應(yīng)用有多個不同的OpenID,但他對所有這些同一開放平臺賬號下的公眾號和應(yīng)用杜跷,只有一個UnionID,可以在用戶管理-獲取用戶基本信息(UnionID機(jī)制)文檔了解詳情矫夷。
CreateTime:消息創(chuàng)建時間葛闷,這個沒什么好說的了。
MsgType:用戶發(fā)送的消息的類型双藕,如text代表文本消息淑趾,image代表圖片消息等。
MsgId:用戶發(fā)送的每個消息都有自己的id忧陪,可以用于消息排重扣泊,比如微信服務(wù)器把xml消息包發(fā)送到URL了近范,但是五秒內(nèi)微信服務(wù)器沒有收到我們的響應(yīng),則會重新發(fā)起請求延蟹,總共重試三次评矩。如果不做消息排重,那么用戶可能就收到多條相同的響應(yīng)消息了阱飘。

接下來斥杜,我們可以創(chuàng)建一個封裝消息的實(shí)體類,把所有可接收到的參數(shù)都放進(jìn)入沥匈,其他類型的暫時不演示蔗喂,所以只在最后加入了文本和圖片的參數(shù)。

@Setter
@Getter
public class InMsgEntity {
    // 開發(fā)者微信號
    protected String FromUserName;
    // 發(fā)送方帳號(一個OpenID)
    protected String ToUserName;
    // 消息創(chuàng)建時間
    protected Long CreateTime;
    /**
     * 消息類型
     * text 文本消息
     * image 圖片消息
     * voice 語音消息
     * video 視頻消息
     * music 音樂消息
     */
    protected String MsgType;
    // 消息id
    protected Long MsgId;
    // 文本內(nèi)容
    private String Content;
    // 圖片鏈接(由系統(tǒng)生成)
    private String PicUrl;
    // 圖片消息媒體id高帖,可以調(diào)用多媒體文件下載接口拉取數(shù)據(jù)
    private String MediaId;
}

這時候大家可能會有個疑問缰儿,為什么字段名稱都是大寫開頭呢?
因?yàn)槲⑿欧?wù)器傳過來的xml數(shù)據(jù)包中的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>

因?yàn)閤ml解析是大小寫敏感的乖阵,所以為了方便封裝,我直接把字段名設(shè)置為大寫開頭爪飘。
當(dāng)然义起,如果還是想要小寫開頭的字段,也是可以的师崎,我們待會再說處理方式默终。

接收消息

實(shí)體已經(jīng)建好之后,我們就可以開始接收微信傳過來的xml數(shù)據(jù)了犁罩。
第1步:在handleMessage方法的形參上添加InMsgEntity類型的參數(shù)齐蔽,并且貼上@RequestBody注解,如下代碼所示:

    /**
     * 微信消息處理
     */
    @RequestMapping(value = "/weChat", method = RequestMethod.POST)
    @ResponseBody
    public Object handleMessage(@RequestBody InMsgEntity msg) {
        return null;
    }

@RequestBody 該注解用于讀取request請求的body部分?jǐn)?shù)據(jù)床估,根據(jù)Content-Type來判斷把數(shù)據(jù)當(dāng)做什么類型來解析含滴,然后把相應(yīng)的數(shù)據(jù)綁定到參數(shù)上。

第2步:需要配合JAXB的注解來解析xml丐巫。
在 InMsgEntity 上添加以下兩個注解:

@XmlRootElement(name="xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class InMsgEntity {
     ......
}

@XmlRootElement是一個類級別注解谈况,主要屬性為name,意為指定根節(jié)點(diǎn)的名字递胧。
往上面看前面舉了個微信傳過來的xml數(shù)據(jù)的例子里碑韵,里面的根節(jié)點(diǎn)就是"xml",所以這里就直接設(shè)置name="xml"

@XmlAccessorType用于定義這個類中的何種類型需要映射到XML中
XmlAccessType.PROPERTY:代表映射這個類中的屬性(get/set方法)到XML
XmlAccessType.FIELD:代表映射這個類中的所有字段到XML(我選用的缎脾,現(xiàn)在的字段名剛好是大寫開頭了)

另外祝闻,剛才說到如果字段名是小寫,怎么解決封裝問題遗菠?
在每個字段或?qū)傩陨咸砑覢XmlElement注解來指定名稱映射
如:

@XmlElement(name="FromUserName")
protected String fromUserName;

JAXB還有非常多的注解和類型联喘,這里只介紹我所用到的华蜒,如需了解其他請自行百度。

現(xiàn)在我們可以掃描自己的公眾號二維碼來測試發(fā)送消息后臺服務(wù)器是否能接收到豁遭。

通過debug可知叭喜,微信傳過來的xml消息包已經(jīng)成功轉(zhuǎn)換為我們的java對象了。


圖片.png

響應(yīng)消息

現(xiàn)在我們可以先來嘗試回復(fù)一條相同的內(nèi)容給用戶堤框。

打開微信開發(fā)文檔域滥,選擇"被動回復(fù)消息"。

發(fā)送被動消息其實(shí)不是一種接口蜈抓,而是對微信服務(wù)器發(fā)過來消息的一次回復(fù)启绰。

圖片.png

我們可以看到文檔里面接收的普通文本回復(fù)的格式和接收的格式基本是一樣的,但是圖片消息或其他消息的還是有些區(qū)別沟使。

<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的元素,所以我們需要再創(chuàng)建一個類來封裝響應(yīng)的xml消息腊嗡。
這里我是把所有類型的屬性統(tǒng)一放到OutMsgEntity類中着倾,大家也可以抽取一個父類,不同的消息創(chuàng)建不同的子類也可以燕少。

@XmlRootElement(name="xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class OutMsgEntity {
    // 發(fā)送方的賬號
    protected String FromUserName;
    // 接收方的賬號(OpenID)
    protected String ToUserName;
    // 消息創(chuàng)建時間
    protected Long CreateTime;
    /**
     * 消息類型
     * text 文本消息
     * image 圖片消息
     * voice 語音消息
     * video 視頻消息
     * music 音樂消息
     * news 圖文消息
     */
    protected String MsgType;
    // 圖片消息媒體id卡者,可以調(diào)用多媒體文件下載接口拉取數(shù)據(jù)
    @XmlElementWrapper(name="Image")
    private String[] MediaId ;
    // 文本內(nèi)容
    private String Content;
}

@XmlElementWrapper注解可以在原xml結(jié)點(diǎn)上再包裝一層xml,但僅允許出現(xiàn)在數(shù)組或集合屬性上客们。

實(shí)際上崇决,我們現(xiàn)在的需求比較簡單,用戶給我們發(fā)什么底挫,我們就回復(fù)什么恒傻,只需要把接收到 InMsgEntity 的內(nèi)容設(shè)置到 OutMsgEntity 上,并且把ToUserName與FormUserName的值設(shè)置為相反即可建邓。

代碼如下:

 /**
     * 微信消息處理
     */
    @RequestMapping(value = "/weChat", method = RequestMethod.POST)
    @ResponseBody
    public Object handleMessage(@RequestBody InMsgEntity msg) {
        //創(chuàng)建消息響應(yīng)對象
        OutMsgEntity out = new OutMsgEntity();
        //把原來的發(fā)送方設(shè)置為接收方
        out.setToUserName(msg.getFromUserName());
        //把原來的接收方設(shè)置為發(fā)送方
        out.setFromUserName(msg.getToUserName());
        //獲取接收的消息類型
        String msgType = msg.getMsgType();
        //設(shè)置消息的響應(yīng)類型
        out.setMsgType(msgType);
        //設(shè)置消息創(chuàng)建時間
        out.setCreateTime(new Date().getTime());
        //根據(jù)類型設(shè)置不同的消息數(shù)據(jù)
        if("text".equals(msgType)){
            out.setContent(msg.getContent());
        }else if("image".equals(msgType)){
            out.setMediaId(new String[]{msg.getMediaId()});
        }
        return out;
    }

測試效果:

圖片.png

到此盈厘,我們已經(jīng)實(shí)現(xiàn)了對消息的接收和響應(yīng)簡單操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末官边,一起剝皮案震驚了整個濱河市沸手,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌注簿,老刑警劉巖罐氨,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滩援,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)塔嬉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門玩徊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來租悄,“玉大人,你說我怎么就攤上這事恩袱∑澹” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵畔塔,是天一觀的道長潭辈。 經(jīng)常有香客問我,道長澈吨,這世上最難降的妖魔是什么把敢? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮谅辣,結(jié)果婚禮上修赞,老公的妹妹穿的比我還像新娘。我一直安慰自己桑阶,他們只是感情好柏副,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蚣录,像睡著了一般割择。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上萎河,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天荔泳,我揣著相機(jī)與錄音,去河邊找鬼公壤。 笑死换可,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的厦幅。 我是一名探鬼主播沾鳄,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼确憨!你這毒婦竟也來了译荞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤休弃,失蹤者是張志新(化名)和其女友劉穎吞歼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體塔猾,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡篙骡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糯俗。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡尿褪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出得湘,到底是詐尸還是另有隱情杖玲,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布淘正,位于F島的核電站摆马,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鸿吆。R本人自食惡果不足惜囤采,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伞剑。 院中可真熱鬧斑唬,春花似錦、人聲如沸黎泣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抒倚。三九已至褐着,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間托呕,已是汗流浹背含蓉。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留项郊,地道東北人馅扣。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像着降,于是被迫代替她去往敵國和親差油。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容