Java开发微信公众号(三)---微信服务器请求消息,响应消息,事件消息以及工具处理类的封装

时间:2021-09-04 00:22:48

在前面几篇文章我们讲了微信公众号环境的配置 和微信公众号服务的接入,接下来我们来说一下微信服务器请求消息,响应消息以及事件消息的相关内容,首先我们来分析一下消息类型和返回xml格式及实体类的封装。

(一)封装请求信息

首先打开微信提供的开发者文档:http://mp.weixin.qq.com/wiki/home/ ,点击左侧的“消息管理”----“接收普通消息”,在右侧我们可以看到微信普通消息类型大致有:文本消息、图片消息、语音消息、视频消息、小视频消息、地理位置消息、链接消息;通过查看开发者文档,我们可以发现消息类型的格式为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>

当我们接收消息的时候,微信将向我们发送Post请求,并以XML的格式发送与接收数据。那么此时我们就需要一个工具类来处理XML格式的文件:MessageType.parseXml()

 package com.webchat.util.weixin;

 import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.webchat.entity.PageData; public class MessageType {
/*
* 文本消息
*/
public static final String TEXT_MESSAGE = "text";
/*
* 图片消息
*/
public static final String IMAGE_MESSAGE = "image";
/*
* 语音消息
*/
public static final String VOICE_MESSAGE = "voice";
/*
* 视频消息
*/
public static final String VIDEO_MESSAGE = "video";
/*
* 小视频消息消息
*/
public static final String SHORTVIDEO_MESSAGE = "shortvideo";
/*
* 地理位置消息
*/
public static final String POSOTION_MESSAGE = "location";
/*
* 链接消息
*/
public static final String LINK_MESSAGE = "link";
/*
* 音乐消息
*/
public static final String MUSIC_MESSAGE = "music";
/*
* 图文消息
*/
public static final String IMAGE_TEXT_MESSAGE = "news";
/*
* 请求消息类型:事件推送
*/
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";
/*
* 事件类型:scan(用户已关注时的扫描带参数二维码)
*/
public static final String EVENT_TYPE_SCAN = "scan";
/*
* 事件类型:LOCATION(上报地理位置)
*/
public static final String EVENT_TYPE_LOCATION = "location";
/*
* 事件类型:CLICK(自定义菜单)
*/
public static final String EVENT_TYPE_CLICK = "click"; /*
* 响应消息类型:文本
*/
public static final String RESP_MESSAGE_TYPE_TEXT = "text";
/*
* 响应消息类型:图片
*/
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 RESP_MESSAGE_TYPE_MUSIC = "music";
/*
* 响应消息类型:图文
*/
public static final String RESP_MESSAGE_TYPE_NEWS = "news"; /**
* @Title parseXml
* @Description 将用户的xml消息提取成map key value 类型
* @param request
* @param response
* @return
* @throws Exception
*/
public static Map<String, String> parseXml(HttpServletRequest request, HttpServletResponse response)
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;
}
}

通过对开发文档的分析我们可以发现这些消息类型中,都会传回来这些公共的字段如:

ToUserName(开发者微信号);

FromUserName(发送方帐 号,OPEN_ID);

CreateTime(消息的创建时间);

MsgType(消息类型);

MsgId(消息ID)。

我们把这些封装成一个基类,然后 不同的部分,分别封装为各自的类然后继承这个基类,提高代码的重用性。

(一)消息实体基础类 -- BaseMessage

 package com.webchat.entity.message;

 /**
* 请求消息的公共字段类
*
* @author Administrator
*
*/
public abstract class BaseMessage {
// 开发者微信号
private String ToUserName;
// 发送方帐号(一个OpenID)
private String FromUserName;
// 消息创建时间 (整型)
private long CreateTime;
// 消息id,64位整型
private long MsgId;
/**
* 获取 消息类型
*
* @return 消息类型
*/
public abstract String getMsgType(); 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 long getMsgId() {
return MsgId;
} public void setMsgId(long msgId) {
MsgId = msgId;
}
}

(二)普通消息类

1,文本消息

 package com.webchat.entity.message;

 import com.webchat.util.weixin.MessageType;

 /**
* 文本消息
* @author Administrator
*
*/
public class TextMessage extends BaseMessage {
//文本消息内容
private String Content; public String getContent() {
return Content;
} public void setContent(String content) {
Content = content;
} @Override
public String getMsgType() {
return MessageType.TEXT_MESSAGE.toString();
} }

2,图片消息

 package com.webchat.entity.message;

 import com.webchat.util.weixin.MessageType;
/**
* 图片消息
* @author Administrator
*
*/
public class ImageMessage extends BaseMessage{
// 图片链接
private String PicUrl;
//图片消息媒体id,可以调用多媒体文件下载接口拉取数据。
private String MediaId; public String getPicUrl() {
return PicUrl;
} public void setPicUrl(String picUrl) {
PicUrl = picUrl;
} public String getMediaId() {
return MediaId;
} public void setMediaId(String mediaId) {
MediaId = mediaId;
} @Override
public String getMsgType() {
return MessageType.IMAGE_MESSAGE.toString();
} }

3,语音消息

 package com.webchat.entity.message;

 import com.webchat.util.weixin.MessageType;

 /**
* 语音消息
*
* @author Administrator
*
*/
public class VoiceMessage extends BaseMessage {
// 语音消息媒体id,可以调用多媒体文件下载接口拉取数据。
private String MediaId;
// 语音格式,如amr,speex等
private String Format;
// 语音识别结果,使用UTF8编码
private String Recognition; public String getMediaId() {
return MediaId;
} public void setMediaId(String mediaId) {
MediaId = mediaId;
} public String getFormat() {
return Format;
} public void setFormat(String format) {
Format = format;
} public String getRecognition() {
return Recognition;
} public void setRecognition(String recognition) {
Recognition = recognition;
} @Override
public String getMsgType() {
return MessageType.VOICE_MESSAGE.toString();
} }

4,视频消息

 package com.webchat.entity.message;

 import com.webchat.util.weixin.MessageType;
/**
* 视频消息
* @author Administrator
*
*/
public class VideoMessage extends BaseMessage {
// 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。
private String MediaId;
// 视频消息 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
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 getMsgType() {
return MessageType.VIDEO_MESSAGE.toString();
} }

5,小视频消息

 package com.webchat.entity.message;

 import com.webchat.util.weixin.MessageType;
/**
* 小视频消息
* @author Administrator
*
*/
public class ShortVideoInputMessage extends BaseMessage {
// 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。
private String MediaId;
// 视频消息 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
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 getMsgType() {
return MessageType.SHORTVIDEO_MESSAGE.toString();
}
}

6,地理位置消息

 package com.webchat.entity.message;

 import com.webchat.util.weixin.MessageType;

 /**
* 地理位置消息
*
* @author Administrator
*
*/
public class LocationMessage extends BaseMessage {
// 地理位置维度
private String Location_X;
// 地理位置经度
private String Location_Y;
// 地图缩放大小
private Long 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 Long getScale() {
return Scale;
} public void setScale(Long scale) {
Scale = scale;
} public String getLabel() {
return Label;
} public void setLabel(String label) {
Label = label;
} @Override
public String getMsgType() {
return MessageType.POSOTION_MESSAGE.toString();
} }

7,链接消息

 package com.webchat.entity.message;

 import com.webchat.util.weixin.MessageType;

 /**
* 链接消息
*
* @author Administrator
*
*/
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 getMsgType() {
return MessageType.LINK_MESSAGE.toString();
} }

(二)封装事件

点击左侧的“消息管理”----“接收事件推送”,在右侧我们可以看到微信接收事件推送的目录:关注/取消关注事件、扫描带参数二维码事件、上报地理位置事件、自定义菜单事件、点击菜单拉取消息时的事件推送、点击菜单跳转链接时的事件推送;推送XML数据包 和消息文本的类似,详情参考开发者文档

提取公共字段创建基础类

 package com.webchat.entity.event;

 /**
* 事件消息
*
* @author Administrator
*
*/
public abstract class BaseEvent {
// 开发者微信号
private String ToUserName;
// 发送方帐号(一个OpenID)
private String FromUserName;
// 消息创建时间 (整型)
private long CreateTime;
// 消息类型
private String MsgType;
// 事件类型
private String Event; public String getEvent() {
return Event;
} public void setEvent(String event) {
Event = event;
} 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;
}
}

事件封装

1,关注/取消事件

 package com.webchat.entity.event;
/**
* 关注取消事件
* @author Administrator
*
*/
public class SubscribeEvent extends BaseEvent{ }

2,扫描参数带二维码事件

 package com.webchat.entity.event;

 /**
* 扫描带参数二维码事件
*
* @author Administrator
*
*/
public class QRCodeEvent extends BaseEvent {
// 事件KEY值
private String EventKey;
// 用于换取二维码图片
private String Ticket; public String getEventKey() {
return EventKey;
} public void setEventKey(String eventKey) {
EventKey = eventKey;
} public String getTicket() {
return Ticket;
} public void setTicket(String ticket) {
Ticket = ticket;
} }

3,上报地理位置事件

 package com.webchat.entity.event;

 /**
* 上报地理位置事件
*
* @author Administrator
*
*/
public class LocationEvent extends BaseEvent {
// 地理位置纬度
private String Latitude;
// 地理位置经度
private String Longitude;
// 地理位置精度
private String Precision; public String getLatitude() {
return Latitude;
} public void setLatitude(String latitude) {
Latitude = latitude;
} public String getLongitude() {
return Longitude;
} public void setLongitude(String longitude) {
Longitude = longitude;
} public String getPrecision() {
return Precision;
} public void setPrecision(String precision) {
Precision = precision;
} }

4,自定义菜单事件

 package com.webchat.entity.event;

 /**
* 自定义菜单事件
* @author Administrator
*
*/
public class MenuEvent extends BaseEvent {
// 事件KEY值,与自定义菜单接口中KEY值对应
private String EventKey; public String getEventKey() {
return EventKey;
} public void setEventKey(String eventKey) {
EventKey = eventKey;
} }

(三)回复消息的分类及实体的封装

点击左侧的“消息管理”----“被动回复用户消息”,当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。

微信服务器在将用户的消息发给公众号的开发者服务器地址(开发者中心处配置)后,微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次,如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。关于重试的消息排重,有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime 排重。详情请查看开发者文档

同样,把消息回复中定义的所有消息都有的字段提取出来,封装成一个公共类,

响应消息的基类BaseOutMessage

 package com.webchat.entity.output;

 /**
* 回复消息的公共字段类
*
* @author Administrator
*
*/
public abstract class BaseOutMessage {
// 接收方帐号(收到的OpenID)
private String ToUserName;
// 开发者微信号
private String FromUserName;
// 消息创建时间 (整型)
private long CreateTime; // 获取消息类型
public abstract String getMsgType(); 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;
} }

普通消息回复实体实现

1,回复文本消息

 package com.webchat.entity.output;

 import com.webchat.util.weixin.MessageType;

 /**
* 文本回复消息
*
* @author Administrator
*
*/
public class TextMessage extends BaseOutMessage {
// 文本消息
private String Content; public String getContent() {
return Content;
} public void setContent(String content) {
Content = content;
} @Override
public String getMsgType() {
return MessageType.RESP_MESSAGE_TYPE_TEXT.toString();
}
}

2,回复图片消息

 package com.webchat.entity.output;

 /**
* 图片回复消息
* @author Administrator
*
*/
public class Image{
//通过上传多媒体文件,得到的id
private String MediaId; public String getMediaId() {
return MediaId;
} public void setMediaId(String mediaId) {
MediaId = mediaId;
}
}
 package com.webchat.entity.output;

 import com.webchat.util.weixin.MessageType;
/**
* 图片输出内容
* @author Administrator
*
*/
public class ImageOutputMessage extends BaseOutMessage{
private Image Image;
public Image getImage() {
return Image;
}
public void setImage(Image image) {
Image = image;
}
@Override
public String getMsgType() {
return MessageType.RESP_MESSAGE_TYPE_IMAGE.toString();
}
}

3,回复语音消息

 package com.webchat.entity.output;
/**
* 语音model
* @author Administrator
*
*/
public class Voice {
// 媒体文件id
private String MediaId; public String getMediaId() {
return MediaId;
} public void setMediaId(String mediaId) {
MediaId = mediaId;
} }
 package com.webchat.entity.output;

 import com.webchat.util.weixin.MessageType;
/**
* 语音回复消息
* @author Administrator
*
*/
public class VoiceOutputMessage extends BaseOutMessage{
private Voice voice; public Voice getVoice() {
return voice;
} public void setVoice(Voice voice) {
this.voice = voice;
} @Override
public String getMsgType() {
return MessageType.RESP_MESSAGE_TYPE_VOICE.toString();
}
}

4,回复视频消息

 package com.webchat.entity.output;
/**
* 视频model
* @author Administrator
*
*/
public class Video {
// 媒体文件id
private String MediaId;
// 缩略图的媒体id
private String ThumbMediaId;
//视频消息的标题
private String Title;
//视频消息的描述
private String Description;
public String getMediaId() {
return MediaId;
} public void setMediaId(String mediaId) {
MediaId = mediaId;
} public String getThumbMediaId() {
return ThumbMediaId;
} public void setThumbMediaId(String thumbMediaId) {
ThumbMediaId = thumbMediaId;
} public String getTitle() {
return Title;
} public void setTitle(String title) {
Title = title;
} public String getDescription() {
return Description;
} public void setDescription(String description) {
Description = description;
} }
 package com.webchat.entity.output;

 import com.webchat.util.weixin.MessageType;

 /**
* 回复视频消息
*
* @author Administrator
*
*/
public class VideoOutPutMessage extends BaseOutMessage {
private Video Video; public Video getVideo() {
return Video;
} public void setVideo(Video video) {
Video = video;
} @Override
public String getMsgType() {
return MessageType.RESP_MESSAGE_TYPE_VIDEO.toString();
}
}

5,回复音乐消息

 package com.webchat.entity.output;
/**
* 回复音乐消息中的音乐对象
* @author Administrator
*
*/
public class Music {
// 音乐标题
private String Title;
// 音乐描述
private String Description;
// 音乐链接
private String MusicUrl;
// 高质量音乐链接,WIFI环境优先使用该链接播放音乐
private String HQMusicUrl;
// 缩略图的媒体id,通过上传多媒体文件得到的id
private String ThumbMediaId; 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 getMusicUrl() {
return MusicUrl;
} public void setMusicUrl(String musicUrl) {
MusicUrl = musicUrl;
} public String getHQMusicUrl() {
return HQMusicUrl;
} public void setHQMusicUrl(String hQMusicUrl) {
HQMusicUrl = hQMusicUrl;
} public String getThumbMediaId() {
return ThumbMediaId;
} public void setThumbMediaId(String thumbMediaId) {
ThumbMediaId = thumbMediaId;
} }
 package com.webchat.entity.output;

 import com.webchat.util.weixin.MessageType;
/**
* 回复音乐消息
* @author Administrator
*
*/
public class MusicOutputMessage extends BaseOutMessage {
private Music Music; public Music getMusic() {
return Music;
} public void setMusic(Music music) {
Music = music;
} @Override
public String getMsgType() {
return MessageType.RESP_MESSAGE_TYPE_MUSIC.toString();
}
}

6,回复图文消息

 package com.webchat.entity.output;
/**
* 图文消息实体类对象
* @author Administrator
*
*/
public class Articles {
private String Title;
// 图文消息描述
private String Description;
// 图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80
private String PicUrl;
// 点击图文消息跳转链接
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 getPicUrl() {
return PicUrl;
} public void setPicUrl(String picUrl) {
PicUrl = picUrl;
} public String getUrl() {
return Url;
} public void setUrl(String url) {
Url = url;
}
}
 package com.webchat.entity.output;

 import java.util.List;
import com.webchat.util.weixin.MessageType; /**
* 提供了获取多条图文消息信息
*
* @author Administrator
*
*/
public class NewsOutputMessage extends BaseOutMessage {
// 图文消息个数,限制为10条以内
private int ArticleCount;
// 多条图文消息信息,默认第一个item为大图
private List<Articles> Articles; public int getArticleCount() {
return ArticleCount;
} public void setArticleCount(int articleCount) {
ArticleCount = articleCount;
} public List<Articles> getArticles() {
return Articles;
} public void setArticles(List<Articles> articles) {
Articles = articles;
} @Override
public String getMsgType() {
return MessageType.RESP_MESSAGE_TYPE_NEWS.toString();
}
}

至此,我们所有的内容已经封装完成

Java开发微信公众号(三)---微信服务器请求消息,响应消息,事件消息以及工具处理类的封装

接下来会更新:微信服务器 post 消息体的接收及消息处理的内容

如果在操作过程中有问题,欢迎随时讨论^.^

百度云链接:https://pan.baidu.com/s/1xQIAl14_9JKJi1BsFe7yvw    密码:ybnv

备注:我的是maven项目,此链接只为分享封装的实体类,如果项目中出现错误,可不用理会,只拿自己想要的东西即可

其他文章关联

(一)Java开发微信公众号(一)---初识微信公众号以及环境搭建

(二)Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发

(三)Java开发微信公众号(三)---微信服务器请求消息,响应消息,事件消息以及工具处理类的封装

(四)Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理