微信公众平台开发(2)-消息封装
作者:luckystar
日期:
消息包括文本、图片、语音、视频、音乐、图文,消息格式参考http://mp.weixin.qq.com/wiki/index.php?title=发送被动响应消息
在接入接口时指定了回调URL,在保存时微信会以GET方式调用此URL,并将signature,timestamp,nonce,echostr添加到URL上
因此在我们的微信处理的Controller中需要有执行上面URL的GET方法。
那么,发送和接收消息怎么来实现呢?
这个是通过以POST方式调用上述URL来实现的。
用户发送的数据通过微信包装以后POST到上面的URL,微信包装的各个类型的消息结构如下:
http://mp.weixin.qq.com/wiki/index.php?title=接收普通消息
比如, 用户通过微信发送一段文本,那么我们可以从输入流中拿到微信服务器发送的数据。
比如:
<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>
这样,就可以知道用户发送的是什么内容了。
那么,如果响应用户呢?
http://mp.weixin.qq.com/wiki/index.php?title=发送被动响应消息
上面定义了响应各个类型消息的结构
组装响应结构的xml数据,并写到输出流,微信就会解析,并发送给用户了。
比如回复文本,如:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content>
</xml>
ToUserName,FromUserName通过接受用户的消息就知道了,那么再组装一下其他内容就可以了。
首先呢,通过解析输入流可以拿到XML的各个节点内容,然后放到Map中。
这里使用dom4j来解析,代码参考后面的MessageUtil.parseXml()方法。
响应时,我们按照文档中给的XML结构组装XML就可以了。
当然,你用字符串来拼当然可以,但是这样很麻烦。我们可以通过xstream来实现Bean到Xml的转换。
说到Bean呢,观察一下响应的各个类型的消息的XML结构,发现有一些属性是共有的。
那么将这些共有的属性组装成一个基类BaseMessage,其他各个类型的消息继承BaseMessage,如下:
import java.io.Serializable;
public class BaseMessage implements Serializable {
private String ToUserName;
private String FromUserName;
private Long CreateTime;
private String MsgType;
private Long MsgId;
/**
* @return the toUserName
*/
public String getToUserName() {
return ToUserName;
}
/**
* @param toUserName the toUserName to set
*/
public void setToUserName(String toUserName) {
ToUserName = toUserName;
}
/**
* @return the fromUserName
*/
public String getFromUserName() {
return FromUserName;
}
/**
* @param fromUserName the fromUserName to set
*/
public void setFromUserName(String fromUserName) {
FromUserName = fromUserName;
}
/**
* @return the createTime
*/
public Long getCreateTime() {
return CreateTime;
}
/**
* @param createTime the createTime to set
*/
public void setCreateTime(Long createTime) {
CreateTime = createTime;
}
/**
* @return the msgType
*/
public String getMsgType() {
return MsgType;
}
/**
* @param msgType the msgType to set
*/
public void setMsgType(String msgType) {
MsgType = msgType;
}
/**
* @return the msgId
*/
public Long getMsgId() {
return MsgId;
}
/**
* @param msgId the msgId to set
*/
public void setMsgId(Long msgId) {
MsgId = msgId;
}
}
然后是文本消息:
public class TextMessage extends BaseMessage {
private String Content;
/**
* @return the content
*/
public String getContent() {
return Content;
}
/**
* @param content the content to set
*/
public void setContent(String Content) {
this.Content = Content;
}
}
图片消息:
public class ImageMessage extends BaseMessage {
/**
* 通过上传多媒体文件,得到的id。
*/
private String MediaId;
}
音乐消息:
public class MusicMessage extends BaseMessage {
private Music Music;
/**
* @return the music
*/
public Music getMusic() {
return Music;
}
/**
* @param music the music to set
*/
public void setMusic(Music music) {
this.Music = music;
}
}
public class Music {
/**
* 音乐标题
*/
private String Title;
/**
* 音乐描述
*/
private String Description;
/**
* 音乐链接
*/
private String MusicUrl;
/**
* 高质量音乐链接,WIFI环境优先使用该链接播放音乐
*/
private String HQMusicUrl;
/**
* 缩略图的媒体id,通过上传多媒体文件,得到的id
*/
private String ThumbMediaId;
/**
* @return the title
*/
public String getTitle() {
return Title;
}
/**
* @param title the title to set
*/
public void setTitle(String title) {
Title = title;
}
/**
* @return the description
*/
public String getDescription() {
return Description;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
Description = description;
}
/**
* @return the musicUrl
*/
public String getMusicUrl() {
return MusicUrl;
}
/**
* @param musicUrl the musicUrl to set
*/
public void setMusicUrl(String musicUrl) {
MusicUrl = musicUrl;
}
/**
* @return the hQMusicUrl
*/
public String getHQMusicUrl() {
return HQMusicUrl;
}
/**
* @param musicUrl the hQMusicUrl to set
*/
public void setHQMusicUrl(String musicUrl) {
HQMusicUrl = musicUrl;
}
/**
* @return the thumbMediaId
*/
public String getThumbMediaId() {
return ThumbMediaId;
}
/**
* @param thumbMediaId the thumbMediaId to set
*/
public void setThumbMediaId(String thumbMediaId) {
ThumbMediaId = thumbMediaId;
}
}
语音消息:
public class VoiceMessage extends BaseMessage {
/**
* 通过上传多媒体文件,得到的id
*/
private String MediaId;
/**
* @return the mediaId
*/
public String getMediaId() {
return MediaId;
}
/**
* @param mediaId the mediaId to set
*/
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
}
视频消息:
public class VideoMessage extends BaseMessage {
/**
* 通过上传多媒体文件,得到的id
*/
private String MediaId;
/**
* 视频消息的标题
*/
private String Title;
/**
* 视频消息的描述
*/
private String Description;
/**
* @return the mediaId
*/
public String getMediaId() {
return MediaId;
}
/**
* @param mediaId the mediaId to set
*/
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
/**
* @return the title
*/
public String getTitle() {
return Title;
}
/**
* @param title the title to set
*/
public void setTitle(String title) {
Title = title;
}
/**
* @return the description
*/
public String getDescription() {
return Description;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
Description = description;
}
}
图文消息:
public class NewsMessage extends BaseMessage {
/**
* 图文消息个数,限制为10条以内
*/
private int ArticleCount;
/**
* 多条图文消息信息,默认第一个item为大图,注意,如果图文数超过10,则将会无响应
*/
private List<Articles> Articles;
/**
* @return the articleCount
*/
public int getArticleCount() {
return ArticleCount;
}
/**
* @param articleCount the articleCount to set
*/
public void setArticleCount(int articleCount) {
ArticleCount = articleCount;
}
/**
* @return the articles
*/
public List<Articles> getArticles() {
return Articles;
}
/**
* @param articles the articles to set
*/
public void setArticles(List<Articles> articles) {
Articles = articles;
}
}
public class Articles implements Serializable {
/**
* 图文消息标题
*/
private String Title;
/**
* 图文消息描述
*/
private String Description;
/**
* 图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200
*/
private String PicUrl;
/**
* 点击图文消息跳转链接
*/
private String Url;
/**
* @return the title
*/
public String getTitle() {
return Title;
}
/**
* @param title the title to set
*/
public void setTitle(String title) {
Title = title;
}
/**
* @return the description
*/
public String getDescription() {
return Description;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
Description = description;
}
/**
* @return the picUrl
*/
public String getPicUrl() {
return PicUrl;
}
/**
* @param picUrl the picUrl to set
*/
public void setPicUrl(String picUrl) {
PicUrl = picUrl;
}
/**
* @return the url
*/
public String getUrl() {
return Url;
}
/**
* @param url the url to set
*/
public void setUrl(String url) {
Url = url;
}
}
然后将各个类型的消息Bean到XML的转换方法写到一个工具类中。 因为XML结构中的内容都包含CDATA,因此需要使xstream支持cdata。 整个微信消息工具类如下:
import java.io.IOException;
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 org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.company.project.model.resp.Articles;
import com.company.project.model.resp.ImageMessage;
import com.company.project.model.resp.MusicMessage;
import com.company.project.model.resp.NewsMessage;
import com.company.project.model.resp.TextMessage;
import com.company.project.model.resp.VideoMessage;
import com.company.project.model.resp.VoiceMessage;
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;
public class MessageUtil {
public static final Logger log = Logger.getLogger(MessageUtil.class);
public static final String MESSAGG_TYPE_TEXT = "text";
public static final String MESSAGG_TYPE_IMAGE = "image";
public static final String MESSAGG_TYPE_VOICE = "voice";
public static final String MESSAGG_TYPE_VIDEO = "video";
public static final String MESSAGG_TYPE_LOCATION = "location";
public static final String MESSAGG_TYPE_LINK = "link";
public static final String MESSAGG_TYPE_MUSIC = "music";
public static final String MESSAGG_TYPE_NEWS = "news";
public static final String MESSAGG_TYPE_EVENT = "event";
// 关注
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
// 取消关注
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
/**
* 扩展XStream,使其支持CDATA
*/
private static XStream xStream = new XStream(new XppDriver() {
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有的XML节点增加CDATA标记
boolean cdata = true;
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);
}
}
};
}
});
/**
* 解析微信发过来的请求(XML)
*
* @author qincd
* @date Nov 4, 2014 11:03:55 AM
*/
public static Map<String,String> parseXml(HttpServletRequest request) throws IOException, DocumentException {
Map<String,String> map = new HashMap<String,String>();
InputStream input = request.getInputStream();
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(input);
Element root = document.getRootElement();
List<Element> eles = root.elements();
for (Element ele:eles) {
log.info(ele.getName() + ":" + ele.getText());
map.put(ele.getName(), ele.getText());
}
input.close();
input = null;
return map;
}
public static String textMessageToXml(TextMessage textMessage) {
xStream.alias("xml", textMessage.getClass());
return xStream.toXML(textMessage);
}
public static String ImageMessageToXml(ImageMessage imageMessage) {
xStream.alias("xml", imageMessage.getClass());
return xStream.toXML(imageMessage);
}
public static String MusicMessageToXml(MusicMessage musicMessage) {
xStream.alias("xml", musicMessage.getClass());
return xStream.toXML(musicMessage);
}
public static String NewsMessageToXml(NewsMessage newsMessage) {
xStream.alias("xml", newsMessage.getClass());
xStream.alias("item", new Articles().getClass());
return xStream.toXML(newsMessage);
}
public static String videoMessageToXml(VideoMessage videoMessage) {
xStream.alias("xml", videoMessage.getClass());
return xStream.toXML(videoMessage);
}
public static String voiceMessageToXml(VoiceMessage voiceMessage) {
xStream.alias("xml", voiceMessage.getClass());
return xStream.toXML(voiceMessage);
}
}
这些公共的东西可以打成一个Jar包
出处:http://qincidong.github.io/blog/2014/11/26/weixin-develop-2nd.html
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。