使用您的公众账号登陆http://mp.weixin.qq.com/,选择菜单--高级功能-开发模式--查看文档,即能看到微信公众平台目前所能开发的功能。
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); }
可以在本地使用http://localhost:8080/QiyadengWeb/HelloWeChat?echostr=hello中文,先进行测试,如果没有问题,可以部署到服务器上,然后在微信公众平台进行设置了。
3.实现POST方法
POST方法首先接收到微信公众平台传送过来的XML,从中提取消息发送人和消息内容。更加消息发送内容,你可以增加自己的处理逻辑,最后拼装成回复消息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){ //增加你所需要的处理逻辑,这里只是简单重复消息 replyMsg.append("您给我的消息是:"); replyMsg.append(textMsg.getContent()); } else{ replyMsg.append(":)不是文本的消息,我暂时看不懂"); } String returnXml = getReplyTextMessage(replyMsg.toString(), textMsg.getFromUserName()); pw.println(returnXml); }
关于调试,这里推荐一个工具Fiddler,你可以模拟微信的POST消息到你的本地,而不必每次部署到服务器上进行调试。关于Fiddler的POST数据使用方法,可以参考下图标注内容。
5.依赖库
使用maven的同学,添加以下依赖即可。非maven用户,找到这些库添加到buider path中即可。
joda-time joda-time 2.2 org.apache.commons commons-io 1.3.2 com.thoughtworks.xstream xstream 1.4.3
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){ //增加你所需要的处理逻辑,这里只是简单重复消息 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; } }
位置识别这是实际应用经常应用的消息,特别是很多商家,通过了解用户位置,给用户提供特别的产品或是商场的推荐。其中用户可能发送两种类型的消息:
1.微信地理位置信息
2.路名、标志性建筑或是商场名称
认识一下,微信地理位置消息,包含一些什么信息
1351776360 23.134521 113.358803 20 1234567890123456
包含的主要信息有经度纬度和Label的位置。可以根据label中描述的位置信息,提供给用户对应的服务。也可根据用户的经度纬度信息,提供你最近的产品或是有地域性的产品。
首先根据微信的地理位置信息,定义WeChatLocationMessage类,并能把Xml转换为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); ResponseHandlerresponseHandler = 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; }
输出的结果
OK 中国工商银行东长安街支行 东城区东长安街1号东方广场西三办公楼1楼 39.915891 116.41867 a025683c73033c35a21de987 http://api.map.baidu.com/place/detail?uid=a025683c73033c35a21de987&output=html&source=placeapi 银行,王府井/东单
接下来,把百度地图反映出来的最近位置信息,以图文消息的格式展示给微信用户
public static String getWeChatReplyNewsMessageByBaiduPlace(ListplaceList, double lat, double lng,String userName, int size){ WeChatReplyNewsMessage newsMessage = new WeChatReplyNewsMessage(); List - items = new ArrayList
- (); 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
2.路名、标志性建筑或是商场名称
对路名、标志性建筑等信息,方法还是通过第三方地图信息,确定输入的位置信息的经度纬度。
本文使用百度地图API,确定所查找的位置的经度和纬度。
确定了经度和纬度,问题就变成和第1种消息类型一致了,根据经度纬度去做相应处理。
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); ResponseHandlerresponseHandler = 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; } 更多微信公众平台开发系列 相关文章请关注!