一.请求消息的封装
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
各消息类型的推送XML数据包结构如下:
文本消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
</xml>
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | text |
Content | 文本消息内容 |
MsgId | 消息id,64位整型 |
图片消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<PicUrl><![CDATA[this is a url]]></PicUrl>
<MediaId><![CDATA[media_id]]></MediaId>
<MsgId>1234567890123456</MsgId>
</xml>
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | image |
PicUrl | 图片链接(由系统生成) |
MediaId | 图片消息媒体id,可以调用多媒体文件下载接口拉取数据。 |
MsgId | 消息id,64位整型 |
语音消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1357290913</CreateTime>
<MsgType><![CDATA[voice]]></MsgType>
<MediaId><![CDATA[media_id]]></MediaId>
<Format><![CDATA[Format]]></Format>
<MsgId>1234567890123456</MsgId>
</xml>
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | 语音为voice |
MediaId | 语音消息媒体id,可以调用多媒体文件下载接口拉取数据。 |
Format | 语音格式,如amr,speex等 |
MsgId | 消息id,64位整型 |
视频消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1357290913</CreateTime>
<MsgType><![CDATA[video]]></MsgType>
<MediaId><![CDATA[media_id]]></MediaId>
<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>
<MsgId>1234567890123456</MsgId>
</xml>
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | 视频为video |
MediaId | 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。 |
ThumbMediaId | 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。 |
MsgId | 消息id,64位整型 |
小视频消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1357290913</CreateTime>
<MsgType><![CDATA[shortvideo]]></MsgType>
<MediaId><![CDATA[media_id]]></MediaId>
<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>
<MsgId>1234567890123456</MsgId>
</xml>
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | 小视频为shortvideo |
MediaId | 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。 |
ThumbMediaId | 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。 |
MsgId | 消息id,64位整型 |
地理位置消息
<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>
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | location |
Location_X | 地理位置维度 |
Location_Y | 地理位置经度 |
Scale | 地图缩放大小 |
Label | 地理位置信息 |
MsgId | 消息id,64位整型 |
链接消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1351776360</CreateTime>
<MsgType><![CDATA[link]]></MsgType>
<Title><![CDATA[公众平台官网链接]]></Title>
<Description><![CDATA[公众平台官网链接]]></Description>
<Url><![CDATA[url]]></Url>
<MsgId>1234567890123456</MsgId>
</xml>
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | 消息类型,link |
Title | 消息标题 |
Description | 消息描述 |
Url | 消息链接 |
MsgId | 消息id,64位整型 |
下面需要做的就是将这些消息封装成Java对象
像ToUserName,FromUserName ,CreateTime ,MsgType 所有的消息中都有所以可以将其封装成一个基类,然后分别让具体其他消息类去继承。
package org.sm.message.req;
/**
* 消息基类(普通用户 -> 公众帐号)
*
* @author sunming
* @date 2017-08-01
*/
public class BaseMessage {
// 开发者微信号
private String ToUserName;
// 发送方帐号(一个OpenID)
private String FromUserName;
// 消息创建时间 (整型)
private long CreateTime;
// 消息类型(text/image/location/link)
private String MsgType;
// 消息id,64位整型
private long MsgId;
public String getToUserName() {
return ToUserName;
}
public void setToUserName(String toUserName) {
ToUserName = toUserName;
}
public String getFromUserName() {
return FromUserName;
}
public void setFromUserName(String fromUserName) {
FromUserName = fromUserName;
}
public long getCreateTime() {
return CreateTime;
}
public void setCreateTime(long createTime) {
CreateTime = createTime;
}
public String getMsgType() {
return MsgType;
}
public void setMsgType(String msgType) {
MsgType = msgType;
}
public long getMsgId() {
return MsgId;
}
public void setMsgId(long msgId) {
MsgId = msgId;
}
}
文本消息:
package org.sm.message.req;
/**
* 文本消息
*
* @author sunming
* @date 2017-08-01
*/
public class TextMessage extends BaseMessage {
// 消息内容
private String Content;
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("TextMessage [Content=");
builder.append(Content);
builder.append("]");
return builder.toString();
}
}
图片消息:
package org.sm.message.req;
/**
* 图片消息
*
* @author sunming
* @date 2017-08-01
*/
public class ImageMessage extends BaseMessage {
// 图片链接
private String PicUrl;
public String getPicUrl() {
return PicUrl;
}
public void setPicUrl(String picUrl) {
PicUrl = picUrl;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ImageMessage [PicUrl=");
builder.append(PicUrl);
builder.append("]");
return builder.toString();
}
}
链接消息:
package org.sm.message.req;
/**
* 链接消息
*
* @author sunming
* @date 2017-08-01
*/
public class LinkMessage extends BaseMessage {
// 消息标题
private String Title;
// 消息描述
private String Description;
// 消息链接
private String Url;
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public String getUrl() {
return Url;
}
public void setUrl(String url) {
Url = url;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("LinkMessage [Title=");
builder.append(Title);
builder.append(", Description=");
builder.append(Description);
builder.append(", Url=");
builder.append(Url);
builder.append("]");
return builder.toString();
}
}
位置消息:
package org.sm.message.req;
/**
* 地理位置消息
*
* @author sunming
* @date 2017-08-01
*/
public class LocationMessage extends BaseMessage {
// 地理位置维度
private String Location_X;
// 地理位置经度
private String Location_Y;
// 地图缩放大小
private String Scale;
// 地理位置信息
private String Label;
public String getLocation_X() {
return Location_X;
}
public void setLocation_X(String location_X) {
Location_X = location_X;
}
public String getLocation_Y() {
return Location_Y;
}
public void setLocation_Y(String location_Y) {
Location_Y = location_Y;
}
public String getScale() {
return Scale;
}
public void setScale(String scale) {
Scale = scale;
}
public String getLabel() {
return Label;
}
public void setLabel(String label) {
Label = label;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("LocationMessage [Location_X=");
builder.append(Location_X);
builder.append(", Location_Y=");
builder.append(Location_Y);
builder.append(", Scale=");
builder.append(Scale);
builder.append(", Label=");
builder.append(Label);
builder.append("]");
return builder.toString();
}
}
语言消息
package org.sm.message.req;
/**
* 语音消息
*
* @author sunming
* @date 2017-08-01
*/
public class VoiceMessage extends BaseMessage {
// 媒体ID
private String MediaId;
// 语音格式
private String Format;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
public String getFormat() {
return Format;
}
public void setFormat(String format) {
Format = format;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("VoiceMessage [MediaId=");
builder.append(MediaId);
builder.append(", Format=");
builder.append(Format);
builder.append("]");
return builder.toString();
}
}
视频消息:
package org.sm.message.req;
public class VideoMessage extends BaseMessage {
private String MediaId;
private String ThumbMediaId;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
public String getThumbMediaId() {
return ThumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
ThumbMediaId = thumbMediaId;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("VideoMessage [MediaId=");
builder.append(MediaId);
builder.append(", ThumbMediaId=");
builder.append(ThumbMediaId);
builder.append("]");
return builder.toString();
}
}
二.请求消息的解析
微信用户向公众账号发消息时发送的是XML消息包,所以我们需要将XML解析成我们需要的东西,解析XML我们使用dom4j,首先引入jar包dom4j-1.6.1.jar
然后写一个解析XML工具类
package org.sm.util;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* 消息工具类
*
* @author sunming
* @date 2017-08-01
*/
public class MessageUtil {
/**
* 解析微信发来的请求(XML)
*
* @param request
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
// 将解析结果存储在HashMap中
Map<String, String> map = new HashMap<String, String>();
// 从request中取得输入流
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List<Element> elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
inputStream = null;
return map;
}
}
我们来看看解析的效果,在ServiceServlet的post方法中加一些东西
/**
* 处理微信服务器发来的消息
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
Map<String, String> map = null;
try {
map = MessageUtil.parseXml(request);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(map);
}
用手机向公众发送一句话看看控制台能否打印出map来
{Content=你好, CreateTime=1502288237, ToUserName=gh_5f5e0f3dd11c, FromUserName=oSIie1JNtmbUBG-6F6BTC9tDytO0, MsgType=text, MsgId=6452278847529990076}
说明解析ok了,那公众号该给用户回复点啥呢,下次再说