開始微信公眾平臺的開發(fā),我們首先要了解微信平臺可以幫助我們做哪些事情?
使用您的公眾賬號登陸http://mp.weixin.qq.com/,選擇菜單--高級功能-開發(fā)模式--查看文檔,即能看到微信公眾平臺目前所能開發(fā)的功能。
一、通訊機制
公眾平臺的主要內(nèi)容是
接受用戶發(fā)送給您公眾賬號的消息
給您的用戶回復(fù)消息
需要特別說明的是,發(fā)送消息和回復(fù)消失是一個連貫的過程,只能在一個對話中完成。也就是說您的用戶不找您說話,您是不能主動發(fā)送消息給你的客戶(群發(fā)是另外一種情況,有次數(shù)限制。你也可以申請付費使用微信CRM平臺)。所有的發(fā)送消息和接受消息,都需要微信平臺進行中轉(zhuǎn)。
二、消息類型
下面介紹用戶能給您發(fā)送的消息類型,也就是目前接受到的消息類型。
1.接受消息類型
1.1文本消息:
這也是我們平時碰到最多的,可以根據(jù)文本中提到的一些關(guān)鍵字,進行判斷,判斷用戶的含義,并進行回復(fù)。
1.2圖片消息:
目前通過圖片理解用戶想表達的意思,還是有較大難度,因此多數(shù)的公眾賬號,會選擇忽略圖片信息或選擇由人工來處理。只能說一句:圖片很美,但是我看不懂。
1.3地理位置消息:
用戶把他的位置發(fā)給您,這對大多數(shù)公眾賬號來說,是一個重要的信息??梢蕴峁┮恍┗谖恢眯畔⒌姆?wù),比如酒店預(yù)訂公眾賬號,可以給你推薦你周邊的酒店。 另外一個補充是,可以在文本消息中分析出位置信息,并加以利用。比如用戶輸入“南京路步行街”,可以提供用戶南京路步行街的相關(guān)商戶。
1.4鏈接消息:
目前還沒有看到開發(fā)模式中特別有效的使用方法。使用比較多的可能會是購物時或是咨詢時,對所談?wù)摰膶ο筮M行明確。
1.5事件推送消息:
當用戶進入到和你對話的過程中,可以先和用戶打招呼等。這個消息目前只支持4.5版本,且暫時還沒有開發(fā)。后續(xù)可想想的空間很大,比如用戶進入到會話之后,搖一搖會發(fā)生什么呢?
2.回復(fù)消息類型
? 2.1文本消息
?? 這是我們平時發(fā)送最多的一類消息,當只需要簡單的文字即可回答用戶的消息時,可用文本消息。文本消息中可以帶有鏈接地址。
?2.2圖文消息
????圖文消息,這是我們在推送消息中經(jīng)??吹降南⒏袷?。每項內(nèi)容可以點擊查看更詳細信息(當然你也可以把鏈接設(shè)置為空,使其不能跳轉(zhuǎn))
?? 2.3音樂消息
?? 在你的答復(fù)中給用戶一個語音消息或是音樂,可以獲得不少用戶的親睞。
了解了公眾平臺的通訊機制和消息類型,接下來,我們開始準備開發(fā)環(huán)境了
1.設(shè)置成為開發(fā)者模式
登錄微信工作平臺,選擇高級功能-進入開發(fā)模式,成為開發(fā)者。需要做如下圖配置。URL配置的信息是指,微信的后臺服務(wù)器把您的用戶消息發(fā)送到該URL處理。Token是你和微信之間的一個密碼,用來驗證消息是否是從微信的服務(wù)發(fā)送而來,而不是其他來攻擊你的系統(tǒng)。
現(xiàn)在你還不能設(shè)置,在設(shè)置時微信會GET請求你設(shè)置的URL,已檢測接口是否可以使用。只有等你準備好GET方法之后才可以進行設(shè)置。
2.實現(xiàn)GET方法
從文檔中知道,我們需要實現(xiàn)POST和GET方法,GET方法用于驗證微信和你的通訊驗證,POST用于消息處理。
新建Servlet HelloWeChat,先實現(xiàn)其中的GET方法
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO 為了簡單起見,先不對消息來源進行校驗 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中文,先進行測試,如果沒有問題,可以部署到服務(wù)器上,然后在微信公眾平臺進行設(shè)置了。
3.實現(xiàn)POST方法
POST方法首先接收到微信公眾平臺傳送過來的XML,從中提取消息發(fā)送人和消息內(nèi)容。更加消息發(fā)送內(nèi)容,你可以增加自己的處理邏輯,最后拼裝成回復(fù)消息XML,返回給微信公眾平臺。
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){ //增加你所需要的處理邏輯,這里只是簡單重復(fù)消息 replyMsg.append("您給我的消息是:"); replyMsg.append(textMsg.getContent()); } else{ replyMsg.append(":)不是文本的消息,我暫時看不懂"); } String returnXml = getReplyTextMessage(replyMsg.toString(), textMsg.getFromUserName()); pw.println(returnXml); }
關(guān)于調(diào)試,這里推薦一個工具Fiddler,你可以模擬微信的POST消息到你的本地,而不必每次部署到服務(wù)器上進行調(diào)試。關(guān)于Fiddler的POST數(shù)據(jù)使用方法,可以參考下圖標注內(nèi)容。
4.部署并測試
完成第一步,并和你的公眾帳號好進行對話,回復(fù)消息沒有問題的話,那就恭喜你了。
5.依賴庫
使用maven的同學,添加以下依賴即可。非maven用戶,找到這些庫添加到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 為了簡單起見,先不對消息來源進行校驗 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){ //增加你所需要的處理邏輯,這里只是簡單重復(fù)消息 replyMsg.append("您給我的消息是:"); replyMsg.append(textMsg.getContent()); } else{ replyMsg.append(":)不是文本的消息,我暫時看不懂"); } 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 你的公眾帳號微信號 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; } }
位置識別這是實際應(yīng)用經(jīng)常應(yīng)用的消息,特別是很多商家,通過了解用戶位置,給用戶提供特別的產(chǎn)品或是商場的推薦。其中用戶可能發(fā)送兩種類型的消息:
1.微信地理位置信息
2.路名、標志性建筑或是商場名稱
1.微信地理位置消息
認識一下,微信地理位置消息,包含一些什么信息
<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中描述的位置信息,提供給用戶對應(yīng)的服務(wù)。也可根據(jù)用戶的經(jīng)度緯度信息,提供你最近的產(chǎn)品或是有地域性的產(chǎn)品。
首先根據(jù)微信的地理位置信息,定義WeChatLocationMessage類,并能把Xml轉(zhuǎn)換為WeChatLocationMessage對象
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>中國工商銀行東長安街支行</name> <location> <lat>39.915891</lat> <lng>116.41867</lng> </location> <address>東城區(qū)東長安街1號東方廣場西三辦公樓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>
接下來,把百度地圖反映出來的最近位置信息,以圖文消息的格式展示給微信用戶
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.路名、標志性建筑或是商場名稱
對路名、標志性建筑等信息,方法還是通過第三方地圖信息,確定輸入的位置信息的經(jīng)度緯度。
本文使用百度地圖API,確定所查找的位置的經(jīng)度和緯度。
確定了經(jīng)度和緯度,問題就變成和第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; }
更多微信公眾平臺開發(fā)系列?相關(guān)文章請關(guān)注PHP中文網(wǎng)!

熱AI工具

Undress AI Tool
免費脫衣服圖片

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

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

Clothoff.io
AI脫衣機

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的代碼編輯器

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

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

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

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