微信将用户发送的消息分成两种,一种是普通消息,另一种是事件推送消息。其中普通消息又有8种类型,分别是文本,图片,语音,视频,小视频,地理位置,链接消息。
1 普通消息
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。这句话对理解微信开发很重要,你还记得微信服务器什么时候会发送GET请求到URL上吗?没错,就是在服务器配置哪里。
微信服务器要么发get请求,要么发post请求给我的服务器,所以我的服务器中只需要分别重载HttpServlet的doGet和doPost方法即可,如下图所示:
doGet方法,用来验证是否正确接入微信服务器。
doPost方法,用来处理用户发来的请求。
2 消息交互流程图
这是一张微信官方的消息交互流程图,说明了开发者服务器接受消息的过程。
再配合下面这样更直观的图,相信你已经有所领悟了。
微信服务器与我的服务器之间的数据都需要二次加工的,即数据被包装成固定的 xml格式。
注意:![CDATA[ ]]>是什么意思?(由于我现在使用的markdown编辑器,!左边的小括号我写不出来,会被转义)
答案: ![CDATA[ ]]>里面的语句不会被解析器解析,防止语句中出现转义字符会被转义。
3 java代码实现text消息前后端交互案例(根据用户发送消息,回复消息)
3.1 重载的doPost方法:
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
String responseMessage = coreService.processRequest(req);//工具类 coreService的processRequest方法处理用户请求
PrintWriter out = resp.getWriter();
out.print(responseMessage);
out.close();
}
3.2 工具类coreServlet:
public class coreService {
public static String processRequest(HttpServletRequest request) {
String responseContent = "初始化信息";
String responseMessage = "success";//ֱ保证微信服务器5秒内能接受到回复
try {
Map<String, String> map = messageUtil.xmlToMap(request);//利用写好的工具类将微信服务器发来的xml格式消息解析到map里
//从map中拿到相应参数ֵ
String fromUserName = map.get("FromUserName");
String toUserName = map.get("ToUserName");
String msgType = map.get("MsgType");
System.out.println("用户发送的消息类型:"+msgType);
if (messageUtil.resp_message_type_text.equals(msgType)) {//如果用户发送的是text类型的消息
if ("A".equals(map.get("Content").toUpperCase())){
responseContent="模拟用户发送A后,服务器推送相应的内容";
}
else if ("B".equals(map.get("Content").toUpperCase())) {
responseContent="模拟用户发送B后,服务器推送相应的内容";
}
else if ("?".equals(map.get("Content"))) {
responseContent="?让我不知错所";
}
else {
responseContent="请老老实实发送A,B或者英文格式的?";
}
}
else if (messageUtil.resp_message_type_event.equals(msgType)) {//如果用户发送的是event类型的消息
System.out.println(map);
if ("subscribe".equals(map.get("Event"))) {
responseContent="很荣幸,您订阅了此公众号!\n发送A,查看A菜单写信息。\n发送B,查看B菜单写信息。\n发送?,我们将指引你前行。";
}
else if ("unsubscribe".equals(map.get("Event"))) {
responseContent="很遗憾,你取消了本公众号!";
}
}
//再拼装xml格式的返回消息,发送给微信服务器
textMessage text = new textMessage();
text.setFromUserName(toUserName);
text.setToUserName(fromUserName);
text.setCreateTime(new Date().getTime());
text.setMsgType(messageUtil.resp_message_type_text);
text.setContent(responseContent);
System.out.println("消息接收方="+text.getToUserName()+",发送方="+text.getFromUserName()+",消息内容="+text.getContent());
responseMessage = messageUtil.mapToXml(text);//利用写好的工具类将text类型消息拼装成微信服务器接受的xml格式
System.out.println("回复给微信服务器的text消息:\n"+responseMessage);
}
catch (Exception e) {
e.printStackTrace();
}
return responseMessage;
}
}
3.3 工具类messageUtil
package zk.util;
import zk.entity.textMessage;
其他包省略,自行包入
public class messageUtil {
public final static String resp_message_type_text = "text";
public final static String resp_message_type_event = "event";
public static Map<String, String> xmlToMap(HttpServletRequest request) throws Exception {
Map<String, String> map = new HashMap<String,String>();
InputStream inputStream = request.getInputStream();
SAXReader reader = new SAXReader();
Document read = reader.read(inputStream);
Element rootElement = read.getRootElement();
List<Element> elements = rootElement.elements();
System.out.println("*******************************");
for (Element element : elements) {
System.out.println(element.getName()+":"+element.getText());
map.put(element.getName(), element.getText());
}
System.out.println("*******************************");
inputStream.close();
return map;
}
public static String mapToXml(textMessage text){
XStream stream = new XStream();
System.out.println(stream.toXML(text));//全类名<zk.entity.textMessage>
stream.alias("xml",text.getClass());//首尾全类名改成<xml>
return stream.toXML(text);
}
}
注意:
mapToXml方法,stream.toXML(text)的输出结果格式为:
修改类型别名stream.alias(“xml”,text.getClass())后的输出格式才能被微信服务器识别:
4 测试text类型消息
1)开启natapp.exe
2)开启后台服务器(Tomcat)
3)手机微信关注测试公众号之后给公众号发送text消息