微信开发手册(2)

2025-12-16 20:12:15

1、工欲善其事必先利其器!本篇内容主要讲解如何将微信公众平台定义的消息及消息相关的操作封装成工具类,方面后期的使用。这里需要明确的是消息其实是由用户发给你的公众帐号的,消息先被微信平台接收到,然后微信平台会将该消息转给你在开发模式接口配置中指定的URL地址。

2、消息推送和消息回复

我们先来了解接口中的“消息推送”指的是“当普通用户向公众帐号发消息时,微信服务器将POST该消息到填写的URL上”,即这里定义的是用户能够发送哪些类型的消息、消息有哪些字段、消息被微信服务器以什么方式转发给我们的公众帐号后台。

微信开发手册(2)

微信开发手册(2)

3、消息的封装

接下来要做的就是将消息推送(请求)、消息回复(响应)中定义的消息进行封装,建立与之对应的Java类(Java是一门面向对象的编程语言,封装后使用起来更方便),下面的请求消息是指消息推送中定义的消息,响应消息指消息回复中定义的消息。

请求消息的基类

把消息推送中定义的所有消息都有的字段提取出来,封装成一个基类,这些公有的字段包括:ToUserName(开发者微信号)、FromUserName(发送方帐号,OPEN_ID)、CreateTime(消息的创建时间)、MsgType(消息类型)、MsgId(消息ID),封装后基类edu.siso.req.BaseMessage的代码如下:

package edu.siso.req;

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;

}  

    

}

4、请求消息之文本消息

package edu.siso.req;

public class TextMessage extends BaseMessage {

// 消息内容  

    private String Content;

public String getContent() {

return Content;

}

public void setContent(String content) {

Content = content;

}  

    

}

5、请求消息之图片消息

package edu.siso.req;

public class ImageMessage extends BaseMessage {

// 图片链接  

    private String PicUrl;

public String getPicUrl() {

return PicUrl;

}

public void setPicUrl(String picUrl) {

PicUrl = picUrl;

    

}

6、请求消息之地理位置消息

package edu.siso.req;

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;

}  

    

}

7、请求消息之链接消息

package edu.siso.req;

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;

}  

    

}

8、请求消息之语音消息

package edu.siso.req;

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;

}  

    

}

9、响应消息的基类

同样,把消息回复中定义的所有消息都有的字段提取出来,封装成一个基类,这些公有的字段包括:ToUserName(接收方帐号,用户的OPEN_ID)、FromUserName(开发者的微信号)、CreateTime(消息的创建时间)、MsgType(消息类型)、FuncFlag(消息的星标标识),封装后基类

edu.siso.resp.BaseMessage的代码如下:

package edu.siso.resp;

public class BaseMessage {

// 接收方帐号(收到的OpenID)  

    private String ToUserName;  

    // 开发者微信号  

    private String FromUserName;  

    // 消息创建时间 (整型)  

    private long CreateTime;  

    // 消息类型(text/music/news)  

    private String MsgType;  

    // 位0x0001被标志时,星标刚收到的消息  

    private int FuncFlag;

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 int getFuncFlag() {

return FuncFlag;

}

public void setFuncFlag(int funcFlag) {

FuncFlag = funcFlag;

    

}

10、响应消息之文本消息

package edu.siso.resp;

public class TextMessage extends BaseMessage {

// 回复的消息内容  

    private String Content;

public String getContent() {

return Content;

}

public void setContent(String content) {

Content = content;

}  

    

}

11、响应消息之音乐消息

package edu.siso.resp;

public class MusicMessage extends BaseMessage {

// 音乐  

    private Music Music;

public Music getMusic() {

return Music;

}

public void setMusic(Music music) {

Music = music;

}  

    

}

音乐消息中Music类的定义

package edu.siso.resp;

public class Music {

// 音乐名称  

    private String Title;  

    // 音乐描述  

    private String Description;  

    // 音乐链接  

    private String MusicUrl;  

    // 高质量音乐链接,WIFI环境优先使用该链接播放音乐  

    private String HQMusicUrl;

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;

}  

    

}

12、响应消息之图文消息

package edu.siso.resp;

import java.util.List;

public class NewsMessage extends BaseMessage {

// 图文消息个数,限制为10条以内  

    private int ArticleCount;  

    // 多条图文消息信息,默认第一个item为大图  

    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;

}  

    

}

图文消息中Article类的定义

package edu.siso.resp;

public class Article {

// 图文消息名称  

    private String Title;  

    // 图文消息描述  

    private String Description;  

    // 图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80,限制图片链接的域名需要与开发者填写的基本资料中的Url一致  

    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;

}  

    

}

13、全部消息封装完成后,Eclipse工程中关于消息部分的结构应该与下图保持一致

微信开发手册(2)

14、如何解析请求消息?

接下来解决请求消息的解析问题。微信服务器会将用户的请求通过doPost方法发送给我们

Post请求有两个参数,request中封装了请求相关的所有内容,可以从request中取出微信服务器发来的消息;而通过response我们可以对接收到的消息进行响应,即发送消息。

那么如何解析请求消息的问题也就转化为如何从request中得到微信服务器发送给我们的xml格式的消息了。这里我们借助于开源框架dom4j去解析xml(这里使用的是dom4j-1.6.1.jar),然后将解析得到的结果存入HashMap,解析请求消息的方法如下:

/**

* 解析微信发来的请求(XML)

*/

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;

}

15、何将响应消息转换成xml返回?

我们先前已经将响应消息封装成了Java类,方便我们在代码中使用。那么,请求接收成功、处理完成后,该如何将消息返回呢?这里就涉及到如何将响应消息转换成xml返回的问题,这里我们将采用开源框架xstream来实现Java类到xml的转换(这里使用的是xstream-1.3.1.jar),代码如下:

/**

* 文本消息对象转换成xml

*/

public static String textMessageToXml(TextMessage textMessage) {

xstream.alias("xml", textMessage.getClass());

return xstream.toXML(textMessage);

}

/**

* 音乐消息对象转换成xml

*/

public static String musicMessageToXml(MusicMessage musicMessage) {

xstream.alias("xml", musicMessage.getClass());

return xstream.toXML(musicMessage);

}

/**

* 图文消息对象转换成xml

*/

public static String newsMessageToXml(NewsMessage newsMessage) {

xstream.alias("xml", newsMessage.getClass());

xstream.alias("item", new Article().getClass());

return xstream.toXML(newsMessage);

}

/**

* xstream拓展

*/

private static XStream xstream = new XStream(new XppDriver() {

public HierarchicalStreamWriter createWriter(Writer out) {

return new PrettyPrintWriter(out) {

// 对所有xml节点的转换都增加CDATA标记

boolean cdata = true;

@SuppressWarnings("unchecked")

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);

}

}

};

}

});

16、说明:由于xstream框架本身并不支持CDATA块的生成,因此对xtream做了扩展,使其支持在生成xml各元素值时添加CDATA块。

消息处理工具的封装

知道怎么解析请求消息,也知道如何将响应消息转化成xml了,接下来就是将消息相关的处理方法全部封装到工具类MessageUtil中,该类的完整代码如下:

package edu.siso.util;

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.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 edu.siso.resp.Article;

import edu.siso.resp.MusicMessage;

import edu.siso.resp.NewsMessage;

import edu.siso.resp.TextMessage;

public class MessageUtil {

/**

* 返回消息类型:文本

*/

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 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_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";

/**

* 解析微信发来的请求(XML)

*/

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;

}

/**

* 文本消息对象转换成xml

*/

public static String textMessageToXml(TextMessage textMessage) {

xstream.alias("xml", textMessage.getClass());

return xstream.toXML(textMessage);

}

/**

* 音乐消息对象转换成xml

*/

public static String musicMessageToXml(MusicMessage musicMessage) {

xstream.alias("xml", musicMessage.getClass());

return xstream.toXML(musicMessage);

}

/**

* 图文消息对象转换成xml

*/

public static String newsMessageToXml(NewsMessage newsMessage) {

xstream.alias("xml", newsMessage.getClass());

xstream.alias("item", new Article().getClass());

return xstream.toXML(newsMessage);

}

/**

* xstream拓展

*/

private static XStream xstream = new XStream(new XppDriver() {

public HierarchicalStreamWriter createWriter(Writer out) {

return new PrettyPrintWriter(out) {

// 对所有xml节点的转换都增加CDATA标记

boolean cdata = true;

@SuppressWarnings("unchecked")

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);

}

}

};

}

});

}

17、OK,到这里关于消息及消息处理工具的封装就讲到这里,其实就是对请求消息/响应消息建立了与之对应的Java类、对xml消息进行解析、将响应消息的Java对象转换成xml。下一篇讲会介绍如何利用上面封装好的工具识别用户发送的消息类型,并做出正确的响应。

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢