http://mobile.51cto.com/aprogram-389672.htm

http://www.qiyadeng.com/category/open-platform/

开始微信公众平台的开发,我们首先要了解微信平台可以帮助我们做哪些事情?
使用您的公众账号登陆http://mp.weixin.qq.com/,选择菜单--高级功能-开发模式--查看文档,即能看到微信公众平台目前所能开发的功能。


一、通讯机制

appid 微信开发工具 微信平台app开发_xml

公众平台的主要内容是

  • 接受用户发送给您公众账号的消息
  • 给您的用户回复消息

需要特别说明的是,发送消息和回复消失是一个连贯的过程,只能在一个对话中完成。也就是说您的用户不找您说话,您是不能主动发送消息给你的客户(群发是另外一种情况,有次数限制。你也可以申请付费使用微信CRM平台)。所有的发送消息和接受消息,都需要微信平台进行中转。


二、消息类型

下面介绍用户能给您发送的消息类型,也就是目前接受到的消息类型。

1.接受消息类型

1.1文本消息:

这也是我们平时碰到最多的,可以根据文本中提到的一些关键字,进行判断,判断用户的含义,并进行回复。

1.2图片消息:

目前通过图片理解用户想表达的意思,还是有较大难度,因此多数的公众账号,会选择忽略图片信息或选择由人工来处理。只能说一句:图片很美,但是我看不懂。

1.3地理位置消息:

用户把他的位置发给您,这对大多数公众账号来说,是一个重要的信息。可以提供一些基于位置信息的服务,比如酒店预订公众账号,可以给你推荐你周边的酒店。 另外一个补充是,可以在文本消息中分析出位置信息,并加以利用。比如用户输入“南京路步行街”,可以提供用户南京路步行街的相关商户。

1.4链接消息:

目前还没有看到开发模式中特别有效的使用方法。使用比较多的可能会是购物时或是咨询时,对所谈论的对象进行明确。

1.5事件推送消息:

当用户进入到和你对话的过程中,可以先和用户打招呼等。这个消息目前只支持4.5版本,且暂时还没有开发。后续可想想的空间很大,比如用户进入到会话之后,摇一摇会发生什么呢?

2.回复消息类型

  2.1文本消息
   这是我们平时发送最多的一类消息,当只需要简单的文字即可回答用户的消息时,可用文本消息。文本消息中可以带有链接地址。

appid 微信开发工具 微信平台app开发_xml_02

 2.2图文消息
    图文消息,这是我们在推送消息中经常看到的消息格式。每项内容可以点击查看更详细信息(当然你也可以把链接设置为空,使其不能跳转)

appid 微信开发工具 微信平台app开发_java_03

   2.3音乐消息
   在你的答复中给用户一个语音消息或是音乐,可以获得不少用户的亲睐。
了解了公众平台的通讯机制和消息类型,接下来,我们开始准备开发环境了

 

1.设置成为开发者模式

登录微信工作平台,选择高级功能-进入开发模式,成为开发者。需要做如下图配置。URL配置的信息是指,微信的后台服务器把您的用户消息发送到该URL处理。Token是你和微信之间的一个密码,用来验证消息是否是从微信的服务发送而来,而不是其他来攻击你的系统。

现在你还不能设置,在设置时微信会GET请求你设置的URL,已检测接口是否可以使用。只有等你准备好GET方法之后才可以进行设置。

appid 微信开发工具 微信平台app开发_微信_04

2.实现GET方法

从文档中知道,我们需要实现POST和GET方法,GET方法用于验证微信和你的通讯验证,POST用于消息处理。

新建Servlet HelloWeChat,先实现其中的GET方法

  1. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  2. // TODO 为了简单起见,先不对消息来源进行校验 
  3. "text/html;charset=UTF-8"); 
  4.         PrintWriter pw = response.getWriter(); 
  5. "echostr"); 
  6. new String(echo.getBytes("ISO-8859-1"),"UTF-8"); 
  7.         pw.println(echo); 
  8.     } 

可以在本地使用http://localhost:8080/QiyadengWeb/HelloWeChat?echostr=hello中文,先进行测试,如果没有问题,可以部署到服务器上,然后在微信公众平台进行设置了。

3.实现POST方法

POST方法首先接收到微信公众平台传送过来的XML,从中提取消息发送人和消息内容。更加消息发送内容,你可以增加自己的处理逻辑,最后拼装成回复消息XML,返回给微信公众平台。

  1. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  2. "text/html;charset=UTF-8"); 
  3.         PrintWriter pw = response.getWriter(); 
  4. "utf-8"); 
  5. null; 
  6. try { 
  7.             textMsg = getWeChatTextMessage(wxMsgXml); 
  8. catch (Exception e) { 
  9.             e.printStackTrace(); 
  10.         } 
  11. new StringBuffer(); 
  12. if(textMsg != null){ 
  13. //增加你所需要的处理逻辑,这里只是简单重复消息 
  14. "您给我的消息是:"); 
  15.             replyMsg.append(textMsg.getContent()); 
  16.         } 
  17. else{ 
  18. ":)不是文本的消息,我暂时看不懂"); 
  19.         } 
  20.         String returnXml = getReplyTextMessage(replyMsg.toString(), textMsg.getFromUserName()); 
  21.         pw.println(returnXml); 
  22.     } 

关于调试,这里推荐一个工具Fiddler,你可以模拟微信的POST消息到你的本地,而不必每次部署到服务器上进行调试。关于Fiddler的POST数据使用方法,可以参考下图标注内容。

appid 微信开发工具 微信平台app开发_appid 微信开发工具_05

4.部署并测试

完成第一步,并和你的公众帐号好进行对话,回复消息没有问题的话,那就恭喜你了

appid 微信开发工具 微信平台app开发_微信_06


appid 微信开发工具 微信平台app开发_xml_07

5.依赖库

使用maven的同学,添加以下依赖即可。非maven用户,找到这些库添加到buider path中即可。

  1. <dependency> 
  2.     <groupId>joda-time</groupId> 
  3.     <artifactId>joda-time</artifactId> 
  4. 2.2</version> 
  5. </dependency> 
  6. <dependency> 
  7.     <groupId>org.apache.commons</groupId> 
  8.     <artifactId>commons-io</artifactId> 
  9. 1.3.2</version> 
  10. </dependency> 
  11. <dependency> 
  12.     <groupId>com.thoughtworks.xstream</groupId> 
  13.     <artifactId>xstream</artifactId> 
  14. 1.4.3</version> 
  15. </dependency> 

6.完整的代码

  1. package com.qiyadeng.wechat; 
  2. import java.io.IOException; 
  3. import java.io.PrintWriter; 
  4. import java.util.Date; 
  5. import javax.servlet.ServletException; 
  6. import javax.servlet.http.HttpServlet; 
  7. import javax.servlet.http.HttpServletRequest; 
  8. import javax.servlet.http.HttpServletResponse; 
  9. import org.apache.commons.io.IOUtils; 
  10. import com.thoughtworks.xstream.XStream; 
  11. import com.thoughtworks.xstream.io.xml.DomDriver; 
  12. /**
  13.  * Servlet implementation class HelloWeChat
  14.  */ 
  15. public class HelloWeChat extends HttpServlet { 
  16. private static final long serialVersionUID = 1L; 
  17. /**
  18.      * @see HttpServlet#HttpServlet()
  19.      */ 
  20. public HelloWeChat() { 
  21. super(); 
  22.     } 
  23. /**
  24.      * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
  25.      */ 
  26. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  27. // TODO 为了简单起见,先不对消息来源进行校验 
  28. "text/html;charset=UTF-8"); 
  29.         PrintWriter pw = response.getWriter(); 
  30. "echostr"); 
  31. new String(echo.getBytes("ISO-8859-1"),"UTF-8"); 
  32.         pw.println(echo); 
  33.     } 
  34. /**
  35.      * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
  36.      */ 
  37. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  38. "text/html;charset=UTF-8"); 
  39.         PrintWriter pw = response.getWriter(); 
  40. "utf-8"); 
  41. null; 
  42. try { 
  43.             textMsg = getWeChatTextMessage(wxMsgXml); 
  44. catch (Exception e) { 
  45.             e.printStackTrace(); 
  46.         } 
  47. new StringBuffer(); 
  48. if(textMsg != null){ 
  49. //增加你所需要的处理逻辑,这里只是简单重复消息 
  50. "您给我的消息是:"); 
  51.             replyMsg.append(textMsg.getContent()); 
  52.         } 
  53. else{ 
  54. ":)不是文本的消息,我暂时看不懂"); 
  55.         } 
  56.         String returnXml = getReplyTextMessage(replyMsg.toString(), textMsg.getFromUserName()); 
  57.         pw.println(returnXml); 
  58.     } 
  59. private WeChatTextMessage getWeChatTextMessage(String xml){ 
  60. new XStream(new DomDriver()); 
  61. "xml", WeChatTextMessage.class); 
  62. "ToUserName", WeChatTextMessage.class, "toUserName"); 
  63. "FromUserName", WeChatTextMessage.class, "fromUserName"); 
  64. "CreateTime", WeChatTextMessage.class, "createTime"); 
  65. "MsgType", WeChatTextMessage.class, "messageType"); 
  66. "Content", WeChatTextMessage.class, "content"); 
  67. "MsgId", WeChatTextMessage.class, "msgId"); 
  68.         WeChatTextMessage wechatTextMessage = (WeChatTextMessage)xstream.fromXML(xml);  
  69. return wechatTextMessage; 
  70.     } 
  71. private String getReplyTextMessage(String content, String weChatUser){ 
  72. new WeChatReplyTextMessage(); 
  73. "text"); 
  74. "0"); 
  75. new Long(new Date().getTime()).toString()); 
  76.         we.setContent(content); 
  77.         we.setToUserName(weChatUser); 
  78. "shanghaiweather");//TODO 你的公众帐号微信号 
  79. new XStream(new DomDriver());  
  80. "xml", WeChatReplyTextMessage.class); 
  81. "ToUserName", WeChatReplyTextMessage.class, "toUserName"); 
  82. "FromUserName", WeChatReplyTextMessage.class, "fromUserName"); 
  83. "CreateTime", WeChatReplyTextMessage.class, "createTime"); 
  84. "MsgType", WeChatReplyTextMessage.class, "messageType"); 
  85. "Content", WeChatReplyTextMessage.class, "content"); 
  86. "FuncFlag", WeChatReplyTextMessage.class, "funcFlag"); 
  87.         String xml =xstream.toXML(we); 
  88. return xml; 
  89.     } 

 

 

 

位置识别这是实际应用经常应用的消息,特别是很多商家,通过了解用户位置,给用户提供特别的产品或是商场的推荐。其中用户可能发送两种类型的消息:

1.微信地理位置信息

2.路名、标志性建筑或是商场名称

1.微信地理位置消息

认识一下,微信地理位置消息,包含一些什么信息

  1. <xml> 
  2. <ToUserName><![CDATA[toUser]]></ToUserName> 
  3. <FromUserName><![CDATA[fromUser]]></FromUserName> 
  4. <CreateTime>1351776360</CreateTime> 
  5. <MsgType><![CDATA[location]]></MsgType> 
  6. <Location_X>23.134521</Location_X> 
  7. <Location_Y>113.358803</Location_Y> 
  8. <Scale>20</Scale> 
  9. <Label><![CDATA[位置信息]]></Label> 
  10. <MsgId>1234567890123456</MsgId> 
  11. </xml>  

包含的主要信息有经度纬度和Label的位置。可以根据label中描述的位置信息,提供给用户对应的服务。也可根据用户的经度纬度信息,提供你最近的产品或是有地域性的产品。

appid 微信开发工具 微信平台app开发_java_08

首先根据微信的地理位置信息,定义WeChatLocationMessage类,并能把Xml转换为WeChatLocationMessage对象

  1. public class WeChatLocationMessage { 
  2. private String toUserName; 
  3. private String fromUserName; 
  4. private String createTime; 
  5. private String msgType; 
  6. private String locationx; 
  7. private String localtiony; 
  8. private String scale; 
  9. private String label; 
  10. private String msgId; 
  11. public static WeChatLocationMessage getWeChatLocationMessage(String xml){ 
  12. new XStream(new DomDriver()); 
  13. null; 
  14. "xml", WeChatLocationMessage.class); 
  15. "ToUserName", WeChatLocationMessage.class, "toUserName"); 
  16. "FromUserName", WeChatLocationMessage.class, "fromUserName"); 
  17. "CreateTime", WeChatLocationMessage.class, "createTime"); 
  18. "MsgType", WeChatLocationMessage.class, "msgType"); 
  19. "Location_X", WeChatLocationMessage.class, "locationx"); 
  20. "Location_Y", WeChatLocationMessage.class, "localtiony"); 
  21. "Scale", WeChatLocationMessage.class, "scale"); 
  22. "Label", WeChatLocationMessage.class, "label"); 
  23. "MsgId", WeChatLocationMessage.class, "msgId"); 
  24.         message = (WeChatLocationMessage)xstream.fromXML(xml); 
  25. return message; 
  26.     } 
  27. //getter and setter 

本文利用百度的地图API,查找最近的银行做为示例。

  1. public String getPalace(String query,String lat,String lng) throws ClientProtocolException, IOException{ 
  2. new DefaultHttpClient(); 
  3.     String url = palceRequestUrl(query,lat,lng); 
  4.     logger.log(Level.INFO, url); 
  5. new HttpGet(url); 
  6. new BasicResponseHandler(); 
  7.     String responseBody = httpClient.execute(httpget, responseHandler); 
  8. "baidu response:"+responseBody); 
  9. return responseBody; 
  10.  
  11. public String palceRequestUrl(String query,String lat,String lng) throws UnsupportedEncodingException { 
  12. "place/search?query=" + URLEncoder.encode(query,"UTF-8") + "&key=" 
  13. "&location="+lat+","+lng +"&radius=2000"+"&output=" + WeChatConstant.OUTPUTFORMAT; 
  14. return url; 

输出的结果

  1. <PlaceSearchResponse> 
  2.     <status>OK</status> 
  3.     <results> 
  4.         <result> 
  5.             <name>中国工商银行东长安街支行</name> 
  6.             <location> 
  7. 39.915891</lat> 
  8. 116.41867</lng> 
  9.             </location> 
  10. 1号东方广场西三办公楼1楼</address> 
  11.             <uid>a025683c73033c35a21de987</uid> 
  12. //api.map.baidu.com/place/detail?uid=a025683c73033c35a21de987&amp;amp;output=html&amp;amp;source=placeapi 
  13.             </detail_url> 
  14.             <tag>银行,王府井/东单</tag> 
  15.         </result> 
  16.       </results> 
  17. </PlaceSearchResponse> 

接下来,把百度地图反映出来的最近位置信息,以图文消息的格式展示给微信用户

  1.     public static String getWeChatReplyNewsMessageByBaiduPlace(List<BaiduPlaceResponse> placeList, double lat, double lng,String userName, int size){ 
  2. new WeChatReplyNewsMessage(); 
  3. new ArrayList<Item>(); 
  4. new StringBuffer(); 
  5. "placeList count="+placeList.size()); 
  6.         newsMessage.setItems(items); 
  7. if(placeList.size()>size){ 
  8.             newsMessage.setArticleCount(size); 
  9.         } 
  10. else{ 
  11.             newsMessage.setArticleCount(placeList.size()); 
  12.         } 
  13. "article count="+newsMessage.getArticleCount()); 
  14. new Date().getTime()+""); 
  15. "news"); 
  16. "0"); 
  17.         newsMessage.setToUserName(userName); 
  18.         newsMessage.setFromUserName(WeChatConstant.FROMUSERNAME); 
  19. for(int i = 0;i <newsMessage.getArticleCount();i++){ 
  20.             BaiduPlaceResponse place = placeList.get(i); 
  21.             Double distance = GeoUtil.DistanceOfTwoPoints(Double.valueOf(place.getLng()), Double.valueOf(place.getLat()), lng, lat, GaussSphere.Beijing54); 
  22. new Item(); 
  23. "["+distance+"米]"+"\n"+place.getAddress()+"\n"+place.getTelephone()); 
  24. ""); 
  25.             item.setUrl(place.getDetailUrl()); 
  26. ""); 
  27.             items.add(item); 
  28.         } 
  29. logger.log(Level.INFO,"newMessage="+newsMessage.toString()); 
  30.         strBuf = strBuf.append(getWeChatNewsMessage(newsMessage)); 
  31. return strBuf.toString(); 
  32.     } 
  33. public static String getWeChatNewsMessage(WeChatReplyNewsMessage newsMessage){ 
  34. new XStream(new DomDriver()); 
  35. "xml", WeChatReplyNewsMessage.class); 
  36. "ToUserName", WeChatReplyNewsMessage.class, "toUserName"); 
  37. "FromUserName", WeChatReplyNewsMessage.class, "fromUserName"); 
  38. "CreateTime", WeChatReplyNewsMessage.class, "createTime"); 
  39. "MsgType", WeChatReplyNewsMessage.class, "msgType"); 
  40. "ArticleCount", WeChatReplyNewsMessage.class, "articleCount"); 
  41. "Content", WeChatReplyNewsMessage.class, "content"); 
  42. "FuncFlag", WeChatReplyNewsMessage.class, "funcFlag"); 
  43. "Articles", WeChatReplyNewsMessage.class, "items"); 
  44. "item", Item.class); 
  45. "Title", Item.class, "title"); 
  46. "Description", Item.class, "description"); 
  47. "PicUrl", Item.class, "picUrl"); 
  48. "Url", Item.class, "url"); 
  49. return xstream.toXML(newsMessage); 
  50.     } 

2.路名、标志性建筑或是商场名称

对路名、标志性建筑等信息,方法还是通过第三方地图信息,确定输入的位置信息的经度纬度。

本文使用百度地图API,确定所查找的位置的经度和纬度。

  1. public String getGeoCode(String query) throws ClientProtocolException, IOException{ 
  2. new DefaultHttpClient(); 
  3.         String url = geoCodeRequestUrl(query); 
  4.         logger.log(Level.INFO, url); 
  5. new HttpGet(url); 
  6. new BasicResponseHandler(); 
  7.         String responseBody = httpClient.execute(httpget, responseHandler); 
  8. "baidu response:"+responseBody); 
  9. return responseBody; 
  10.     } 
  11. public String geoCodeRequestUrl(String query) throws UnsupportedEncodingException{ 
  12. "geocoder?address=" + URLEncoder.encode(query,"UTF-8") + "&key=" 
  13. "&output=" + WeChatConstant.OUTPUTFORMAT; 
  14. return url; 
  15.     } 

确定了经度和纬度,问题就变成和第1种消息类型一致了,根据经度纬度去做相应处理。

appid 微信开发工具 微信平台app开发_appid 微信开发工具_09