開始微信大眾平台的開發,我們首先要了解微信平台可以幫助我們做哪些事?
使用您的公眾帳號登陸http://mp.weixin.qq.com/,選擇選單--高級功能-開發模式--查看文檔,即能看到微信公眾平台目前所能開發的功能。
公眾平台的主要內容是
接受用戶傳送給您公眾帳號的訊息
給您的用戶回覆訊息
#需要特別說明的是,發送訊息和回覆消失是一個連貫的過程,只能在一個對話中完成。也就是說您的用戶不找您說話,您是不能主動發送訊息給你的客戶(群發是另一種情況,有次數限制。你也可以申請付費使用微信CRM平台)。所有的發送訊息和接受訊息,都需要微信平台進行中轉。
以下介紹使用者能傳送給您的訊息類型,也就是目前接受到的訊息類型。
1.1文字訊息:
這也是我們平常碰到最多的,可以根據文字中提到的一些關鍵字,進行判斷,判斷使用者的意義,並進行回覆。
1.2圖片訊息:
目前透過圖片理解使用者想表達的意思,還是有較大難度,因此多數的公眾帳號,會選擇忽略圖片資訊或選擇由人工來處理。只能說一句:圖片很美,但我看不懂。
1.3地理位置訊息:
用戶把他的位置寄給您,這對大多數公眾帳號來說,是一個重要的訊息。可以提供一些基於位置資訊的服務,例如飯店預訂公眾帳號,可以給你推薦你周邊的飯店。 另外一個補充是,可以在文字訊息中分析出位置訊息,並加以利用。例如用戶輸入“南京路步行街”,可以提供用戶南京路步行街的相關商家。
1.4連結訊息:
目前還沒有看到開發模式中特別有效的使用方法。使用比較多的可能會是購物時或是諮詢時,對所談論的對象進行明確。
1.5事件推播訊息:
當使用者進入和你對話的過程中,可以先和使用者打招呼等。這個消息目前只支援4.5版本,暫時還沒有開發。後續可想想的空間很大,例如使用者進入到會話之後,搖一搖會發生什麼事?
2.1文字訊息
這是我們平時發送最多的一類訊息,當只需要簡單的文字即可回答用戶的訊息時,可用文本消息。文字訊息中可以帶有連結地址。
2.2圖文訊息
圖文訊息,這是我們在推播訊息中經常看到的訊息格式。每項內容可以點擊查看更詳細資訊(當然你也可以把連結設為空,使其不能跳轉)
2.3音樂訊息
在你的答覆中給用戶一個語音訊息或是音樂,可以獲得不少用戶的親青睞。
了解了公眾平台的通訊機制和訊息類型,接下來,我們開始準備開發環境了
#1.設定成為開發者模式
##登入微信工作平台,選擇進階功能-進入開發模式,成為開發者。需要做如下圖配置。 URL配置的資訊是指,微信的後台伺服器會將您的用戶訊息傳送到該URL處理。 Token是你和微信之間的密碼,用來驗證訊息是否是從微信的服務發送而來,而不是其他來攻擊你的系統。 現在你還不能設置,在設定時微信會GET請求你設定的URL,已偵測介面是否可以使用。只有等你準備好GET方法之後才可以進行設定。2.實作GET方法
#從文件中知道,我們需要實作POST和GET方法,GET方法用來驗證微信和你的通訊驗證,POST用於訊息處理。 新Servlet HelloWeChat,先實作其中的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); }
can be used locally at http://localhost:8080/QiyadengWeb/HelloWeChat?echostr=hello Chinese. Test it first. If there are no problems, you can deploy it to the server and then set it up on the WeChat public platform.
3. Implement the POST method
The POST method first receives the XML sent from the WeChat public platform and extracts the message sender and message content. For more message sending content, you can add your own processing logic, and finally assemble it into a reply message XML and return it to the WeChat public platform.
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){ //增加你所需要的处理逻辑,这里只是简单重复消息 replyMsg.append("您给我的消息是:"); replyMsg.append(textMsg.getContent()); } else{ replyMsg.append(":)不是文本的消息,我暂时看不懂"); } String returnXml = getReplyTextMessage(replyMsg.toString(), textMsg.getFromUserName()); pw.println(returnXml); }
Regarding debugging, here is a tool Fiddler recommended. You can simulate WeChat POST messages to your local area without having to deploy to the server for debugging every time. Regarding how to use Fiddler's POST data, you can refer to the content marked in the figure below.
4. Deploy and test
Complete the first step and have a conversation with your public account. There is no reply to the message. If you have any questions, congratulations.
5. Dependency library
For students who use maven, just add the following dependencies. Non-maven users can find these libraries and add them to the builder 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. Complete code
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){ //增加你所需要的处理逻辑,这里只是简单重复消息 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; } }
Location identification is a message that is often used in practical applications, especially many merchants, which provide users with special information by understanding their location. products or recommendations from shopping malls. Users may send two types of messages:
1. WeChat geographical location information
2. Road names, landmark buildings or shopping mall names
Get to know what information WeChat location message contains
<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>
The main information included is longitude, latitude and the location of the Label. Corresponding services can be provided to users based on the location information described in the label. You can also provide your latest products or regional products based on the user's longitude and latitude information.
First define the WeChatLocationMessage class based on WeChat’s geographical location information, and convert Xml into a WeChatLocationMessage object
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 }
This article uses Baidu’s map API to find Take the nearest bank as an example.
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; }
Output results
<PlaceSearchResponse> <status>OK</status> <results> <result> <name>中国工商银行东长安街支行</name> <location> <lat>39.915891</lat> <lng>116.41867</lng> </location> <address>东城区东长安街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>
Next, the recent location information reflected by Baidu Map is displayed to WeChat users in the format of graphic messages
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); }
For information such as road names, landmark buildings, etc., the method is to determine the longitude and latitude of the input location information through third-party map information.
This article uses Baidu Map API to determine the longitude and latitude of the location being searched.
After determining the longitude and latitude, the problem becomes the same as the first message type, and the corresponding processing is done according to the longitude and latitude.
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; }
For more related articles in the WeChat public platform development series, please pay attention to the PHP Chinese website!