開(kāi)始微信公眾平臺(tái)的開(kāi)發(fā),我們首先要了解微信平臺(tái)可以幫助我們做哪些事情?
使用您的公眾賬號(hào)登陸http://mp.weixin.qq.com/,選擇菜單--高級(jí)功能-開(kāi)發(fā)模式--查看文檔,即能看到微信公眾平臺(tái)目前所能開(kāi)發(fā)的功能。
一、通訊機(jī)制
公眾平臺(tái)的主要內(nèi)容是
接受用戶發(fā)送給您公眾賬號(hào)的消息
給您的用戶回復(fù)消息
需要特別說(shuō)明的是,發(fā)送消息和回復(fù)消失是一個(gè)連貫的過(guò)程,只能在一個(gè)對(duì)話中完成。也就是說(shuō)您的用戶不找您說(shuō)話,您是不能主動(dòng)發(fā)送消息給你的客戶(群發(fā)是另外一種情況,有次數(shù)限制。你也可以申請(qǐng)付費(fèi)使用微信CRM平臺(tái))。所有的發(fā)送消息和接受消息,都需要微信平臺(tái)進(jìn)行中轉(zhuǎn)。
二、消息類型
下面介紹用戶能給您發(fā)送的消息類型,也就是目前接受到的消息類型。
1.接受消息類型
1.1文本消息:
這也是我們平時(shí)碰到最多的,可以根據(jù)文本中提到的一些關(guān)鍵字,進(jìn)行判斷,判斷用戶的含義,并進(jìn)行回復(fù)。
1.2圖片消息:
目前通過(guò)圖片理解用戶想表達(dá)的意思,還是有較大難度,因此多數(shù)的公眾賬號(hào),會(huì)選擇忽略圖片信息或選擇由人工來(lái)處理。只能說(shuō)一句:圖片很美,但是我看不懂。
1.3地理位置消息:
用戶把他的位置發(fā)給您,這對(duì)大多數(shù)公眾賬號(hào)來(lái)說(shuō),是一個(gè)重要的信息??梢蕴峁┮恍┗谖恢眯畔⒌姆?wù),比如酒店預(yù)訂公眾賬號(hào),可以給你推薦你周邊的酒店。 另外一個(gè)補(bǔ)充是,可以在文本消息中分析出位置信息,并加以利用。比如用戶輸入“南京路步行街”,可以提供用戶南京路步行街的相關(guān)商戶。
1.4鏈接消息:
目前還沒(méi)有看到開(kāi)發(fā)模式中特別有效的使用方法。使用比較多的可能會(huì)是購(gòu)物時(shí)或是咨詢時(shí),對(duì)所談?wù)摰膶?duì)象進(jìn)行明確。
1.5事件推送消息:
當(dāng)用戶進(jìn)入到和你對(duì)話的過(guò)程中,可以先和用戶打招呼等。這個(gè)消息目前只支持4.5版本,且暫時(shí)還沒(méi)有開(kāi)發(fā)。后續(xù)可想想的空間很大,比如用戶進(jìn)入到會(huì)話之后,搖一搖會(huì)發(fā)生什么呢?
2.回復(fù)消息類型
? 2.1文本消息
?? 這是我們平時(shí)發(fā)送最多的一類消息,當(dāng)只需要簡(jiǎn)單的文字即可回答用戶的消息時(shí),可用文本消息。文本消息中可以帶有鏈接地址。
?2.2圖文消息
????圖文消息,這是我們?cè)谕扑拖⒅薪?jīng)??吹降南⒏袷?。每項(xiàng)內(nèi)容可以點(diǎn)擊查看更詳細(xì)信息(當(dāng)然你也可以把鏈接設(shè)置為空,使其不能跳轉(zhuǎn))
?? 2.3音樂(lè)消息
?? 在你的答復(fù)中給用戶一個(gè)語(yǔ)音消息或是音樂(lè),可以獲得不少用戶的親睞。
了解了公眾平臺(tái)的通訊機(jī)制和消息類型,接下來(lái),我們開(kāi)始準(zhǔn)備開(kāi)發(fā)環(huán)境了
1.設(shè)置成為開(kāi)發(fā)者模式
登錄微信工作平臺(tái),選擇高級(jí)功能-進(jìn)入開(kāi)發(fā)模式,成為開(kāi)發(fā)者。需要做如下圖配置。URL配置的信息是指,微信的后臺(tái)服務(wù)器把您的用戶消息發(fā)送到該URL處理。Token是你和微信之間的一個(gè)密碼,用來(lái)驗(yàn)證消息是否是從微信的服務(wù)發(fā)送而來(lái),而不是其他來(lái)攻擊你的系統(tǒng)。
現(xiàn)在你還不能設(shè)置,在設(shè)置時(shí)微信會(huì)GET請(qǐng)求你設(shè)置的URL,已檢測(cè)接口是否可以使用。只有等你準(zhǔn)備好GET方法之后才可以進(jìn)行設(shè)置。
2.實(shí)現(xiàn)GET方法
從文檔中知道,我們需要實(shí)現(xiàn)POST和GET方法,GET方法用于驗(yàn)證微信和你的通訊驗(yàn)證,POST用于消息處理。
新建Servlet HelloWeChat,先實(shí)現(xiàn)其中的GET方法
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO 為了簡(jiǎn)單起見(jiàn),先不對(duì)消息來(lái)源進(jìn)行校驗(yàn) response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); String echo = request.getParameter("echostr"); echo = new String(echo.getBytes("ISO-8859-1"),"UTF-8"); pw.println(echo); }
可以在本地使用http://localhost:8080/QiyadengWeb/HelloWeChat?echostr=hello中文,先進(jìn)行測(cè)試,如果沒(méi)有問(wèn)題,可以部署到服務(wù)器上,然后在微信公眾平臺(tái)進(jìn)行設(shè)置了。
3.實(shí)現(xiàn)POST方法
POST方法首先接收到微信公眾平臺(tái)傳送過(guò)來(lái)的XML,從中提取消息發(fā)送人和消息內(nèi)容。更加消息發(fā)送內(nèi)容,你可以增加自己的處理邏輯,最后拼裝成回復(fù)消息XML,返回給微信公眾平臺(tái)。
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); String wxMsgXml = IOUtils.toString(request.getInputStream(),"utf-8"); WeChatTextMessage textMsg = null; try { textMsg = getWeChatTextMessage(wxMsgXml); } catch (Exception e) { e.printStackTrace(); } StringBuffer replyMsg = new StringBuffer(); if(textMsg != null){ //增加你所需要的處理邏輯,這里只是簡(jiǎn)單重復(fù)消息 replyMsg.append("您給我的消息是:"); replyMsg.append(textMsg.getContent()); } else{ replyMsg.append(":)不是文本的消息,我暫時(shí)看不懂"); } String returnXml = getReplyTextMessage(replyMsg.toString(), textMsg.getFromUserName()); pw.println(returnXml); }
關(guān)于調(diào)試,這里推薦一個(gè)工具Fiddler,你可以模擬微信的POST消息到你的本地,而不必每次部署到服務(wù)器上進(jìn)行調(diào)試。關(guān)于Fiddler的POST數(shù)據(jù)使用方法,可以參考下圖標(biāo)注內(nèi)容。
4.部署并測(cè)試
完成第一步,并和你的公眾帳號(hào)好進(jìn)行對(duì)話,回復(fù)消息沒(méi)有問(wèn)題的話,那就恭喜你了。
5.依賴庫(kù)
使用maven的同學(xué),添加以下依賴即可。非maven用戶,找到這些庫(kù)添加到buider path中即可。
<dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.3</version> </dependency>
6.完整的代碼
package com.qiyadeng.wechat; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; /** * Servlet implementation class HelloWeChat */ public class HelloWeChat extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public HelloWeChat() { super(); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO 為了簡(jiǎn)單起見(jiàn),先不對(duì)消息來(lái)源進(jìn)行校驗(yàn) response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); String echo = request.getParameter("echostr"); echo = new String(echo.getBytes("ISO-8859-1"),"UTF-8"); pw.println(echo); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); String wxMsgXml = IOUtils.toString(request.getInputStream(),"utf-8"); WeChatTextMessage textMsg = null; try { textMsg = getWeChatTextMessage(wxMsgXml); } catch (Exception e) { e.printStackTrace(); } StringBuffer replyMsg = new StringBuffer(); if(textMsg != null){ //增加你所需要的處理邏輯,這里只是簡(jiǎn)單重復(fù)消息 replyMsg.append("您給我的消息是:"); replyMsg.append(textMsg.getContent()); } else{ replyMsg.append(":)不是文本的消息,我暫時(shí)看不懂"); } String returnXml = getReplyTextMessage(replyMsg.toString(), textMsg.getFromUserName()); pw.println(returnXml); } private WeChatTextMessage getWeChatTextMessage(String xml){ XStream xstream = new XStream(new DomDriver()); xstream.alias("xml", WeChatTextMessage.class); xstream.aliasField("ToUserName", WeChatTextMessage.class, "toUserName"); xstream.aliasField("FromUserName", WeChatTextMessage.class, "fromUserName"); xstream.aliasField("CreateTime", WeChatTextMessage.class, "createTime"); xstream.aliasField("MsgType", WeChatTextMessage.class, "messageType"); xstream.aliasField("Content", WeChatTextMessage.class, "content"); xstream.aliasField("MsgId", WeChatTextMessage.class, "msgId"); WeChatTextMessage wechatTextMessage = (WeChatTextMessage)xstream.fromXML(xml); return wechatTextMessage; } private String getReplyTextMessage(String content, String weChatUser){ WeChatReplyTextMessage we = new WeChatReplyTextMessage(); we.setMessageType("text"); we.setFuncFlag("0"); we.setCreateTime(new Long(new Date().getTime()).toString()); we.setContent(content); we.setToUserName(weChatUser); we.setFromUserName("shanghaiweather");//TODO 你的公眾帳號(hào)微信號(hào) XStream xstream = new XStream(new DomDriver()); xstream.alias("xml", WeChatReplyTextMessage.class); xstream.aliasField("ToUserName", WeChatReplyTextMessage.class, "toUserName"); xstream.aliasField("FromUserName", WeChatReplyTextMessage.class, "fromUserName"); xstream.aliasField("CreateTime", WeChatReplyTextMessage.class, "createTime"); xstream.aliasField("MsgType", WeChatReplyTextMessage.class, "messageType"); xstream.aliasField("Content", WeChatReplyTextMessage.class, "content"); xstream.aliasField("FuncFlag", WeChatReplyTextMessage.class, "funcFlag"); String xml =xstream.toXML(we); return xml; } }
位置識(shí)別這是實(shí)際應(yīng)用經(jīng)常應(yīng)用的消息,特別是很多商家,通過(guò)了解用戶位置,給用戶提供特別的產(chǎn)品或是商場(chǎng)的推薦。其中用戶可能發(fā)送兩種類型的消息:
1.微信地理位置信息
2.路名、標(biāo)志性建筑或是商場(chǎng)名稱
1.微信地理位置消息
認(rèn)識(shí)一下,微信地理位置消息,包含一些什么信息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1351776360</CreateTime> <MsgType><![CDATA[location]]></MsgType> <Location_X>23.134521</Location_X> <Location_Y>113.358803</Location_Y> <Scale>20</Scale> <Label><![CDATA[位置信息]]></Label> <MsgId>1234567890123456</MsgId> </xml>
包含的主要信息有經(jīng)度緯度和Label的位置??梢愿鶕?jù)label中描述的位置信息,提供給用戶對(duì)應(yīng)的服務(wù)。也可根據(jù)用戶的經(jīng)度緯度信息,提供你最近的產(chǎn)品或是有地域性的產(chǎn)品。
首先根據(jù)微信的地理位置信息,定義WeChatLocationMessage類,并能把Xml轉(zhuǎn)換為WeChatLocationMessage對(duì)象
public class WeChatLocationMessage { private String toUserName; private String fromUserName; private String createTime; private String msgType; private String locationx; private String localtiony; private String scale; private String label; private String msgId; public static WeChatLocationMessage getWeChatLocationMessage(String xml){ XStream xstream = new XStream(new DomDriver()); WeChatLocationMessage message = null; xstream.alias("xml", WeChatLocationMessage.class); xstream.aliasField("ToUserName", WeChatLocationMessage.class, "toUserName"); xstream.aliasField("FromUserName", WeChatLocationMessage.class, "fromUserName"); xstream.aliasField("CreateTime", WeChatLocationMessage.class, "createTime"); xstream.aliasField("MsgType", WeChatLocationMessage.class, "msgType"); xstream.aliasField("Location_X", WeChatLocationMessage.class, "locationx"); xstream.aliasField("Location_Y", WeChatLocationMessage.class, "localtiony"); xstream.aliasField("Scale", WeChatLocationMessage.class, "scale"); xstream.aliasField("Label", WeChatLocationMessage.class, "label"); xstream.aliasField("MsgId", WeChatLocationMessage.class, "msgId"); message = (WeChatLocationMessage)xstream.fromXML(xml); return message; } //getter and setter }
本文利用百度的地圖API,查找最近的銀行做為示例。
public String getPalace(String query,String lat,String lng) throws ClientProtocolException, IOException{ HttpClient httpClient = new DefaultHttpClient(); String url = palceRequestUrl(query,lat,lng); logger.log(Level.INFO, url); HttpGet httpget = new HttpGet(url); ResponseHandler<String> responseHandler = new BasicResponseHandler(); String responseBody = httpClient.execute(httpget, responseHandler); logger.log(Level.INFO,"baidu response:"+responseBody); return responseBody; } public String palceRequestUrl(String query,String lat,String lng) throws UnsupportedEncodingException { String url = WeChatConstant.BASEURL + "place/search?query=" + URLEncoder.encode(query,"UTF-8") + "&key=" + WeChatConstant.MAPKEY +"&location="+lat+","+lng +"&radius=2000"+"&output=" + WeChatConstant.OUTPUTFORMAT; return url; }
輸出的結(jié)果
<PlaceSearchResponse> <status>OK</status> <results> <result> <name>中國(guó)工商銀行東長(zhǎng)安街支行</name> <location> <lat>39.915891</lat> <lng>116.41867</lng> </location> <address>東城區(qū)東長(zhǎng)安街1號(hào)東方廣場(chǎng)西三辦公樓1樓</address> <uid>a025683c73033c35a21de987</uid> <detail_url>http://api.map.baidu.com/place/detail?uid=a025683c73033c35a21de987&amp;output=html&amp;source=placeapi </detail_url> <tag>銀行,王府井/東單</tag> </result> </results> </PlaceSearchResponse>
接下來(lái),把百度地圖反映出來(lái)的最近位置信息,以圖文消息的格式展示給微信用戶
public static String getWeChatReplyNewsMessageByBaiduPlace(List<BaiduPlaceResponse> placeList, double lat, double lng,String userName, int size){ WeChatReplyNewsMessage newsMessage = new WeChatReplyNewsMessage(); List<Item> items = new ArrayList<Item>(); StringBuffer strBuf = new StringBuffer(); logger.log(Level.INFO,"placeList count="+placeList.size()); newsMessage.setItems(items); if(placeList.size()>size){ newsMessage.setArticleCount(size); } else{ newsMessage.setArticleCount(placeList.size()); } logger.log(Level.INFO,"article count="+newsMessage.getArticleCount()); newsMessage.setCreateTime(new Date().getTime()+""); newsMessage.setMsgType("news"); newsMessage.setFuncFlag("0"); newsMessage.setToUserName(userName); newsMessage.setFromUserName(WeChatConstant.FROMUSERNAME); for(int i = 0;i <newsMessage.getArticleCount();i++){ BaiduPlaceResponse place = placeList.get(i); Double distance = GeoUtil.DistanceOfTwoPoints(Double.valueOf(place.getLng()), Double.valueOf(place.getLat()), lng, lat, GaussSphere.Beijing54); Item item = new Item(); item.setTitle(place.getName()+"["+distance+"米]"+"\n"+place.getAddress()+"\n"+place.getTelephone()); item.setPicUrl(""); item.setUrl(place.getDetailUrl()); item.setDescription(""); items.add(item); } logger.log(Level.INFO,"newMessage="+newsMessage.toString()); strBuf = strBuf.append(getWeChatNewsMessage(newsMessage)); return strBuf.toString(); } public static String getWeChatNewsMessage(WeChatReplyNewsMessage newsMessage){ XStream xstream = new XStream(new DomDriver()); xstream.alias("xml", WeChatReplyNewsMessage.class); xstream.aliasField("ToUserName", WeChatReplyNewsMessage.class, "toUserName"); xstream.aliasField("FromUserName", WeChatReplyNewsMessage.class, "fromUserName"); xstream.aliasField("CreateTime", WeChatReplyNewsMessage.class, "createTime"); xstream.aliasField("MsgType", WeChatReplyNewsMessage.class, "msgType"); xstream.aliasField("ArticleCount", WeChatReplyNewsMessage.class, "articleCount"); xstream.aliasField("Content", WeChatReplyNewsMessage.class, "content"); xstream.aliasField("FuncFlag", WeChatReplyNewsMessage.class, "funcFlag"); xstream.aliasField("Articles", WeChatReplyNewsMessage.class, "items"); xstream.alias("item", Item.class); xstream.aliasField("Title", Item.class, "title"); xstream.aliasField("Description", Item.class, "description"); xstream.aliasField("PicUrl", Item.class, "picUrl"); xstream.aliasField("Url", Item.class, "url"); return xstream.toXML(newsMessage); }
2.路名、標(biāo)志性建筑或是商場(chǎng)名稱
對(duì)路名、標(biāo)志性建筑等信息,方法還是通過(guò)第三方地圖信息,確定輸入的位置信息的經(jīng)度緯度。
本文使用百度地圖API,確定所查找的位置的經(jīng)度和緯度。
確定了經(jīng)度和緯度,問(wèn)題就變成和第1種消息類型一致了,根據(jù)經(jīng)度緯度去做相應(yīng)處理。
public String getGeoCode(String query) throws ClientProtocolException, IOException{ HttpClient httpClient = new DefaultHttpClient(); String url = geoCodeRequestUrl(query); logger.log(Level.INFO, url); HttpGet httpget = new HttpGet(url); ResponseHandler<String> responseHandler = new BasicResponseHandler(); String responseBody = httpClient.execute(httpget, responseHandler); logger.log(Level.INFO,"baidu response:"+responseBody); return responseBody; } public String geoCodeRequestUrl(String query) throws UnsupportedEncodingException{ String url = WeChatConstant.BASEURL + "geocoder?address=" + URLEncoder.encode(query,"UTF-8") + "&key=" + WeChatConstant.MAPKEY + "&output=" + WeChatConstant.OUTPUTFORMAT; return url; }
更多微信公眾平臺(tái)開(kāi)發(fā)系列?相關(guān)文章請(qǐng)關(guān)注PHP中文網(wǎng)!

熱AI工具

Undress AI Tool
免費(fèi)脫衣服圖片

Undresser.AI Undress
人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover
用于從照片中去除衣服的在線人工智能工具。

Clothoff.io
AI脫衣機(jī)

Video Face Swap
使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的代碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6
視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版
神級(jí)代碼編輯軟件(SublimeText3)