概述
开始微信公众平台的开发,我们首先要了解微信平台可以帮助我们做哪些事情?
使用您的公众账号登陆http://mp.weixin.qq.com/,选择菜单--高级功能-开发模式--查看文档,即能看到微信公众平台目前所能开发的功能。
一、通讯机制
公众平台的主要内容是
接受用户发送给您公众账号的消息
给您的用户回复消息
需要特别说明的是,发送消息和回复消失是一个连贯的过程,只能在一个对话中完成。也就是说您的用户不找您说话,您是不能主动发送消息给你的客户(群发是另外一种情况,有次数限制。你也可以申请付费使用微信CRM平台)。所有的发送消息和接受消息,都需要微信平台进行中转。
二、消息类型
下面介绍用户能给您发送的消息类型,也就是目前接受到的消息类型。
1.接受消息类型
1.1文本消息:
这也是我们平时碰到最多的,可以根据文本中提到的一些关键字,进行判断,判断用户的含义,并进行回复。
1.2图片消息:
目前通过图片理解用户想表达的意思,还是有较大难度,因此多数的公众账号,会选择忽略图片信息或选择由人工来处理。只能说一句:图片很美,但是我看不懂。
1.3地理位置消息:
用户把他的位置发给您,这对大多数公众账号来说,是一个重要的信息。可以提供一些基于位置信息的服务,比如酒店预订公众账号,可以给你推荐你周边的酒店。 另外一个补充是,可以在文本消息中分析出位置信息,并加以利用。比如用户输入“南京路步行街”,可以提供用户南京路步行街的相关商户。
1.4链接消息:
目前还没有看到开发模式中特别有效的使用方法。使用比较多的可能会是购物时或是咨询时,对所谈论的对象进行明确。
1.5事件推送消息:
当用户进入到和你对话的过程中,可以先和用户打招呼等。这个消息目前只支持4.5版本,且暂时还没有开发。后续可想想的空间很大,比如用户进入到会话之后,摇一摇会发生什么呢?
2.回复消息类型
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);
}
登录后复制
可以在本地使用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数据使用方法,可以参考下图标注内容。
4.部署并测试
完成第一步,并和你的公众帐号好进行对话,回复消息没有问题的话,那就恭喜你了。
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){
//增加你所需要的处理逻辑,这里只是简单重复消息
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.路名、标志性建筑或是商场名称
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>
登录后复制
包含的主要信息有经度纬度和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);
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;
}
登录后复制
输出的结果
<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>
登录后复制
接下来,把百度地图反映出来的最近位置信息,以图文消息的格式展示给微信用户
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.路名、标志性建筑或是商场名称
对路名、标志性建筑等信息,方法还是通过第三方地图信息,确定输入的位置信息的经度纬度。
本文使用百度地图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);
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;
}
登录后复制
立即学习全程直播 + 实战授课 + 边学 + 边练 + 边辅导
最后
以上就是独特白云为你收集整理的微信公众平台开发系列 的全部内容,希望文章能够帮你解决微信公众平台开发系列 所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复