文本消息在前面消息的基础上多了一个 Content 属性,因此文本消息继承自 BaseMessage ,再额外添加一个 Content 属性即可。
其他的消息类型也是类似的定义,我就不一一列举了,至于其他消息的格式,大家可以参考微信开放文档(http://1t.click/aPXK)。
消息类型的 Bean 定义完成之后,接下来就是将实体类生成 XML。
首先我们定义一个消息工具类,将常见的消息类型枚举出来:
/**
- 返回消息类型:文本
*/
public static final String RESP_MESSAGE_TYPE_TEXT = “text”;
/**
- 返回消息类型:音乐
*/
public static final String RESP_MESSAGE_TYPE_MUSIC = “music”;
/**
- 返回消息类型:图文
*/
public static final String RESP_MESSAGE_TYPE_NEWS = “news”;
/**
- 返回消息类型:图片
*/
public static final String RESP_MESSAGE_TYPE_Image = “image”;
/**
- 返回消息类型:语音
*/
public static final String RESP_MESSAGE_TYPE_Voice = “voice”;
/**
- 返回消息类型:视频
*/
public static final String RESP_MESSAGE_TYPE_Video = “video”;
/**
- 请求消息类型:文本
*/
public static final String REQ_MESSAGE_TYPE_TEXT = “text”;
/**
- 请求消息类型:图片
*/
public static final String REQ_MESSAGE_TYPE_IMAGE = “image”;
/**
- 请求消息类型:链接
*/
public static final String REQ_MESSAGE_TYPE_LINK = “link”;
/**
- 请求消息类型:地理位置
*/
public static final String REQ_MESSAGE_TYPE_LOCATION = “location”;
/**
- 请求消息类型:音频
*/
public static final String REQ_MESSAGE_TYPE_VOICE = “voice”;
/**
- 请求消息类型:视频
*/
public static final String REQ_MESSAGE_TYPE_VIDEO = “video”;
/**
- 请求消息类型:推送
*/
public static final String REQ_MESSAGE_TYPE_EVENT = “event”;
/**
- 事件类型:subscribe(订阅)
*/
public static final String EVENT_TYPE_SUBSCRIBE = “subscribe”;
/**
- 事件类型:unsubscribe(取消订阅)
*/
public static final String EVENT_TYPE_UNSUBSCRIBE = “unsubscribe”;
/**
- 事件类型:CLICK(自定义菜单点击事件)
*/
public static final String EVENT_TYPE_CLICK = “CLICK”;
/**
- 事件类型:VIEW(自定义菜单 URl 视图)
*/
public static final String EVENT_TYPE_VIEW = “VIEW”;
/**
- 事件类型:LOCATION(上报地理位置事件)
*/
public static final String EVENT_TYPE_LOCATION = “LOCATION”;
/**
- 事件类型:LOCATION(上报地理位置事件)
*/
public static final String EVENT_TYPE_SCAN = “SCAN”;
大家注意这里消息类型的定义,以 RESP 开头的表示返回的消息类型,以 REQ 表示微信服务器发来的消息类型。然后在这个工具类中再定义两个方法,用来将返回的对象转换成 XML:
public static String textMessageToXml(TextMessage textMessage) {
xstream.alias(“xml”, textMessage.getClass());
return xstream.toXML(textMessage);
}
private static XStream xstream = new XStream(new XppDriver() {
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
boolean cdata = true;
@SuppressWarnings(“rawtypes”)
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
}
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write(“<![CDATA[”);
writer.write(text);
writer.write(“]]>”);
} else {
writer.write(text);
}
}
};
}
});
textMessageToXML 方法用来将 TextMessage 对象转成 XML 返回给微信服务器,类似的方法我们还需要定义 imageMessageToXml、voiceMessageToXml 等,不过定义的方式都基本类似,我就不一一列出来了。
由于用户发来的消息可能存在多种情况,我们需要分类进行处理,这个就涉及到返回消息的分发问题。因此我在这里再定义一个返回消息分发的工具类,如下:
public class MessageDispatcher {
public static String processMessage(Map<String, String> map) {
String openid = map.get(“FromUserName”); //用户 openid
String mpid = map.get(“ToUserName”); //公众号原始 ID
if (map.get(“MsgType”).equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
//普通文本消息
TextMessage txtmsg = new TextMessage();
txtmsg.setToUserName(openid);
txtmsg.setFromUserName(mpid);
txtmsg.setCreateTime(new Date().getTime());
txtmsg.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
txtmsg.setContent(“这是返回消息”);
return MessageUtil.textMessageToXml(txtmsg);
}
return null;
}
public String processEvent(Map<String, String> map) {
//在这里处理事件
}
}
这里我们还可以多加几个 elseif 去判断不同的消息类型,我这里因为只有普通文本消息,所以一个 if 就够用了。
在这里返回值我写死了,实际上这里需要根据微信服务端传来的 Content 去数据中查询,将查询结果返回,数据库查询这一套相信大家都能搞定,我这里就不重复介绍了。
最后在消息接收 Controller 中调用该方法,如下:
@PostMapping(value = “/verify_wx_token”,produces = “application/xml;charset=utf-8”)
public String handler(HttpServletRequest request, HttpServletResponse response) throws Exception {
request.setCharacterEncoding(“UTF-8”);
Map<String, String> map = MessageUtil.parseXml(request);
String msgType = map.get(“MsgType”);
if (MessageUtil.REQ_MESSAGE_TYPE_EVENT.equals(msgType)) {
return messageDispatcher.processEvent(map);
}else{
return messageDispatcher.processMessage(map);
}
}
在 Controller 中,我们首先判断消息是否是事件,如果是事件,进入到事件处理通道,如果不是事件,则进入到消息处理通道。
注意,这里需要配置一下返回消息的编码,否则可能会出现中文乱码。
如此之后,我们的服务器就可以给公众号返回消息了。