微信公众号开发(二)------封装普通消息和事件
前言
在上一篇博文中我们已经对微信公众号进行了接入,接入了公众号,我们的服务器就要处理很多来自己用户的请求,在这里,我们可以梳理一下公众号的逻辑:
- 首先,用户向微信服务器发送消息
- 微信服务器接受到用户的消息处理之后,通过我们配置的URL和Token来找到我们的服务器,并以
xml
的形式向第三方服务器发送消息. - 第三方服务器获取消息之后,
解析
消息,根绝用户的需求提供对应的服务,然后封装成xml
数据,传回微信服务器 - 微信服务器解析这些xml,并返回给用户对应的数据
在这里我们可以看到,用户的请求其实是被微信的服务器转换成xml的形式来和我们进行通信,因此,我们如果要使用java来开发公众号,就必须要对这些消息的类型创建对应的对象,且要使用方便的工具来提供xml和java对象的转换.
正文
一 消息的封装
通过官方文档,我们可以得知用户向微信发送的消息大概有以下几种:
- 文本消息
- 图片消息
- 语音消息
- 视频消息
- 小视频消息
- 地理位置消息
- 链接消息
这些消息的格式可以查看文档:消息格式
我们对比每种消息的参数,可以发现,有以下参数是相同的:
- ToUserName 开发者微信号
- FromUserName 发送方账号,一个OpendID
- CreateTime 创建时间(秒)
- MsgType 消息类型(text, image, voice, video, shortvideo, location, link)
- MsgId 消息ID
将以上字段封装为一个基类的javaBean,其他的消息类型在此基础上扩展即可.
基类消息体(BaseMessage)
package com.xiaojian.bean.request;
/**
* 请求消息的基类
*/
public class BaseMessage {
/**
* 开发者微信号
*/
private String toUserName;
/**
* 发送方账号
*/
private String fromUserName;
/**
* 消息创建时间
*/
private long createTime;
/**
* 消息类型
*/
private String msgType;
/**
* 消息id
*/
private long msgId;
public BaseMessage() {
}
public String getToUserName() {
return toUserName;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public String getFromUserName() {
return fromUserName;
}
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public long getCreateTime() {
return createTime;
}
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public long getMsgId() {
return msgId;
}
public void setMsgId(long msgId) {
this.msgId = msgId;
}
}
文本消息
package com.xiaojian.bean.request;
/**
* 文本消息
*/
public class TextMessage extends BaseMessage {
/**
* 文本消息内容
*/
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
图片消息
package com.xiaojian.bean.request;
/**
* 图片消息
*/
public class ImageMessage extends BaseMessage{
/**
* 图片链接
*/
private String picUrl;
/**
* 图片消息媒体ID
*/
private String mediaId;
public String getPicUrl() {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
}
语音消息
package com.xiaojian.bean.request;
/**
* 语音消息,未开通语音识别的请求体
*/
public class VoiceMessage extends BaseMessage {
/**
* 媒体ID
*/
private String mediaId;
/**
* 语音格式
*/
private String format;
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
}
视频消息
package com.xiaojian.bean.request;
/**
* 视频消息(和小视频享用同一个实体)
*/
public class VideoMessage extends BaseMessage{
/**
* 媒体ID
*/
private String mediaId;
/**
* 视频缩略图媒体Id
*/
private String thumbMediaId;
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
public String getThumbMediaId() {
return thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
}
地理位置消息
package com.xiaojian.bean.request;
/**
* 地理位置消息
*/
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) {
this.location_X = location_X;
}
public String getLocation_Y() {
return location_Y;
}
public void setLocation_Y(String location_Y) {
this.location_Y = location_Y;
}
public String getScale() {
return scale;
}
public void setScale(String scale) {
this.scale = scale;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}
链接消息
package com.xiaojian.bean.request;
/**
* 链接消息
*/
public class LinkMessage extends BaseMessage{
/**
* 消息标题
*/
private String title;
/**
* 消息描述
*/
private String description;
/**
* 消息链接
*/
private String url;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
二 事件的封装
除了普通的消息,用户在和公众号交互的过程过,有些操作会以事件的方式通知到我们的服务器,总共有以下事件:
- 关注/取消事件
- 扫描带参数二维码事件
- 上报地理位置事件
- 自定义菜单事件
- 点击菜单拉取消息时的事件推送
- 点击菜单跳转链接时的事件推送
同样的,我们可以提取出基类的事件对象
基类事件
package com.xiaojian.bean.request.event;
/**
* 基类事件
*/
public class BaseEvent {
/**
* 开发者微信号
*/
private String toUserName;
/**
* 发送方账号
*/
private String fromUserName;
/**
* 消息创建时间
*/
private long createTime;
/**
* 消息类型
*/
private String msgType;
/**
* 事件类型
*/
private String event;
public String getToUserName() {
return toUserName;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public String getFromUserName() {
return fromUserName;
}
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public long getCreateTime() {
return createTime;
}
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
}
关注/取消事件
package com.xiaojian.bean.request.event;
/**
* 取消/关注事件
*/
public class SubscribeEvent extends BaseEvent{
}
扫描带参数的二维码事件
package com.xiaojian.bean.request.event;
/**
* 扫描带参数的二维码事件
*/
public class QRCodeEvent extends BaseEvent {
/**
* 事件KEY值,qrscene_为前缀,后面为二维码的参数值
*/
private String eventKey;
/**
* ticket,用户换取二维码图片
*/
private String ticket;
public String getEventKey() {
return eventKey;
}
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
}
上报地理位置事件
package com.xiaojian.bean.request.event;
/**
* 上报地理位置事件
*/
public class LocationEvent extends BaseEvent {
/**
* 地理位置维度
*/
private String latitude;
/**
* 地理位置经度
*/
private String longitude;
/**
* 地理位置精度
*/
private String precision;
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public String getPrecision() {
return precision;
}
public void setPrecision(String precision) {
this.precision = precision;
}
}
自定义菜单事件
package com.xiaojian.bean.request.event;
/**
* 自定义菜单事件
*/
public class MenuEvent extends BaseEvent{
/**
* 事件KEY值
*/
private String eventKey;
public String getEventKey() {
return eventKey;
}
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
}
现在请求的各种数据都已经封装好了,下面来封装对应的响应消息.
三 封装响应消息
查看官方文档,当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐).
而微信官方也对响应的消息做了区分,分别有回复文本、图片、语音、视频、音乐、图文这六种,在官方文档也有对应的响应消息的xml格式:响应消息格式
我们同样的提取他们的公共属性来创建响应基类:
响应消息基类
package com.xiaojian.bean.response;
/**
* 响应消息的基类
*/
public class BaseMessageResponse {
/**
* 开发者微信号
*/
private String ToUserName;
/**
* 发送方账号
*/
private String FromUserName;
/**
* 消息创建时间
*/
private long CreateTime;
/**
* 消息类型
*/
private String MsgType;
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;
}
}
回复文本消息
package com.xiaojian.bean.response;
/**
* 文本消息的回复对象
*/
public class TextMessageResponse extends BaseMessageResponse{
/**
* 回复的消息内容
*/
private String Content;
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
}
回复图片消息
package com.xiaojian.bean.commons;
/**
* 对应响应消息中的图片xml
*/
public class Image {
private String MediaId;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
this.MediaId = mediaId;
}
}
package com.xiaojian.bean.response;
import com.xiaojian.bean.commons.Image;
/**
* 图片消息的响应对象
*/
public class ImageMessageResponse extends BaseMessageResponse{
/**
* 图片
*/
private Image Image;
public com.xiaojian.bean.commons.Image getImage() {
return Image;
}
public void setImage(com.xiaojian.bean.commons.Image image) {
Image = image;
}
}
回复语音消息
package com.xiaojian.bean.commons;
/**
* 响应消息中对应的voice model
*/
public class Voice {
/**
* 媒体文件id
*/
private String MediaId;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
this.MediaId = mediaId;
}
}
package com.xiaojian.bean.response;
import com.xiaojian.bean.commons.Voice;
/**
* 语音消息响应体
*/
public class VoiceMessageResponse extends BaseMessageResponse{
/**
* 消息中包含的语音
*/
private Voice Voice;
public Voice getVoice() {
return Voice;
}
public void setVoice(Voice voice) {
this.Voice = voice;
}
}
回复视频消息
package com.xiaojian.bean.commons;
/**
* 响应中对应的视频model
*/
public class Video {
/**
* 媒体id
*/
private String MediaId;
/**
* 视频标题
*/
private String Title;
/**
* 视频描述
*
*/
private String Description;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
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.xiaojian.bean.response;
import com.xiaojian.bean.commons.Video;
/**
* 响应视频消息的model
*/
public class VideoMessageResponse extends BaseMessageResponse{
/**
* 视频
*/
private Video Video;
public Video getVideo() {
return Video;
}
public void setVideo(Video video) {
this.Video = video;
}
}
回复音乐消息
package com.xiaojian.bean.commons;
/**
* 音乐
*/
public class Music {
/**
* 音乐标题
*/
private String Title;
/**
* 音乐描述
*/
private String Description;
/**
* 音乐链接
*/
private String MusicURL;
/**
* 高质量音乐链接
*/
private String HQMusicUrl;
/**
* 媒体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) {
this.HQMusicUrl = HQMusicUrl;
}
public String getThumbMediaId() {
return ThumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
ThumbMediaId = thumbMediaId;
}
}
package com.xiaojian.bean.response;
import com.xiaojian.bean.commons.Music;
/**
* 响应音乐消息
*/
public class MusicMessageResponse extends BaseMessageResponse{
/**
* 音乐
*/
private Music Music;
public Music getMusic() {
return Music;
}
public void setMusic(Music music) {
Music = music;
}
}
回复图文消息
package com.xiaojian.bean.commons;
/**
* 图文消息model
*/
public class Article {
/**
* 图文消息标题
*/
private String Title;
/**
* 图文消息描述
*/
private String Description;
/**
* 图片链接
*/
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.xiaojian.bean.response;
import com.xiaojian.bean.commons.Article;
import java.util.List;
/**
* 图文消息响应model
*/
public class ArticleMessageResponse extends BaseMessageResponse {
/**
* 图文消息个数
*/
private int Articlecount;
/**
* 多条图文消息信息
*/
private List<Article> Articles;
public int getArticlecount() {
return Articlecount;
}
public void setArticlecount(int articlecount) {
Articlecount = articlecount;
}
public List<Article> getArticles() {
return Articles;
}
public void setArticles(List<Article> articles) {
Articles = articles;
}
}
总结
至此,消息的封装就结束了,我们可以使用我们创建的各种javabean来封装请求和回复的消息.在下一篇博文中,我们将实现简单的消息识别和公众号回应.