Home  >  Article  >  Backend Development  >  WeChat Public Account Development Tutorial Part 4 - Encapsulation of Messages and Message Processing Tools_PHP Tutorial

WeChat Public Account Development Tutorial Part 4 - Encapsulation of Messages and Message Processing Tools_PHP Tutorial

WBOY
WBOYOriginal
2016-07-20 11:12:14743browse

If a worker wants to do his job well, he must first sharpen his tools! This article mainly explains how to encapsulate the messages and message-related operations defined by the WeChat public platform into tool classes for later use. What needs to be made clear here is that the message is actually sent to your public account by the user. The message is first received by the WeChat platform, and then the WeChat platform will forward the message to the URL address you specified in the development mode interface configuration.

WeChat public platform message interface

To receive messages sent by the WeChat platform, we need to first be familiar with the message interface part of the WeChat public platform API. Click here to enter. After clicking, you will enter the message interface guide part, as shown in the figure below:

On the left side of the picture above, you can see that the WeChat public platform currently has three open interfaces: message interface, general interface and custom menu interface. The general interface and custom menu interface can only be called if you are qualified for internal testing, and the application for internal testing qualification has been closed. We can only hope that WeChat will be open to public users one day in the future, so users who do not have internal testing qualifications should not Don't waste time on these two interfaces anymore, just use the message interface.

Message push and message reply

The following will mainly introduce the message interface. For receiving and responding to messages, we only need to pay attention to "4 message push" and "5 message reply" in the figure above.

Let’s first understand what “message push” in the interface refers to. Click “4 Message Push” and you can see that “message push” in the interface refers to “when ordinary users send messages to public accounts, The WeChat server will POST the message to the filled-in URL." That is, what is defined here is what types of messages the user can send, what fields the message has, and how the message is forwarded to our public account backend by the WeChat server.

Message push defines 5 types of messages we will receive: text messages, picture messages, geographical location messages, link messages and event push. In fact, we can also receive voice messages, but we can’t get them. to obtain the specific voice files (you need to be qualified for internal testing to obtain the voice files).

The "message reply" in the interface defines the message type, message fields and message format that we can reply to the user. The interface guide of the WeChat public platform is described as follows:

As mentioned above, there are 5 types of messages that we can reply to users, but currently there are only 3 types of messages that can be replied to in development mode: text messages, music messages and graphic messages, while voice messages and video messages can currently only Used in edit mode.

Message encapsulation

The next thing to do is to encapsulate the messages defined in message push (request) and message reply (response), and create corresponding Java classes (Java is an object-oriented programming language, which can be used after encapsulation) More convenient), the request message below refers to the message defined in message push, and the response message refers to the message defined in message reply.

Base class for request messages

Extract the fields common to all messages defined in the message push and encapsulate them into a base class. These public fields include: ToUserName (developer’s WeChat account), FromUserName (sender account, OPEN_ID), CreateTime (message Creation time), MsgType (message type), MsgId (message ID), the code of the encapsulated base class org.liufeng.course.message.req.BaseMessage is as follows:

package org.liufeng.course.message.req;

/**
 * 消息基类(普通用户 -> 公众帐号)
 * 
 * @author liufeng
 * @date 2013-05-19
 */
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;
	}
}

Request message text message

package org.liufeng.course.message.req;

/**
 * 文本消息
 * 
 * @author liufeng
 * @date 2013-05-19
 */
public class TextMessage extends BaseMessage {
	// 消息内容
	private String Content;

	public String getContent() {
		return Content;
	}

	public void setContent(String content) {
		Content = content;
	}
}

Request message picture message

package org.liufeng.course.message.req;

/**
 * 图片消息
 * 
 * @author liufeng
 * @date 2013-05-19
 */
public class ImageMessage extends BaseMessage {
	// 图片链接
	private String PicUrl;

	public String getPicUrl() {
		return PicUrl;
	}

	public void setPicUrl(String picUrl) {
		PicUrl = picUrl;
	}
}

Request message for geographical location message

package org.liufeng.course.message.req;

/**
 * 地理位置消息
 * 
 * @author liufeng
 * @date 2013-05-19
 */
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;
	}
}

Request message link message

package org.liufeng.course.message.req; /*** Link message * * @author liufeng * @date 2013-05-19*/ public class LinkMessage extends BaseMessage { // Message title private String Title; // Message description private String Description; // Message link 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; } } ​

Request message voice message

package org.liufeng.course.message.req;

/**
 * 音频消息
 * 
 * @author liufeng
 * @date 2013-05-19
 */
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;
	}
}

Base class for response messages

Similarly, extract the fields common to all messages defined in the message reply and encapsulate them into a base class. These public fields include: ToUserName (recipient account, user’s OPEN_ID), FromUserName (developer’s WeChat ID) ), CreateTime (creation time of the message), MsgType (message type), FuncFlag (star mark of the message), the code of the encapsulated base class org.liufeng.course.message.resp.BaseMessage is as follows:

package org.liufeng.course.message.resp;

/**
 * 消息基类(公众帐号 -> 普通用户)
 * 
 * @author liufeng
 * @date 2013-05-19
 */
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;
	}
}

Text message of response message

package org.liufeng.course.message.resp;

/**
 * 文本消息
 * 
 * @author liufeng
 * @date 2013-05-19
 */
public class TextMessage extends BaseMessage {
	// 回复的消息内容
	private String Content;

	public String getContent() {
		return Content;
	}

	public void setContent(String content) {
		Content = content;
	}
}

Response message music message

package org.liufeng.course.message.resp;

/**
 * 音乐消息
 * 
 * @author liufeng
 * @date 2013-05-19
 */
public class MusicMessage extends BaseMessage {
	// 音乐
	private Music Music;

	public Music getMusic() {
		return Music;
	}

	public void setMusic(Music music) {
		Music = music;
	}
}

Response message with graphic message

package org.liufeng.course.message.resp;

import java.util.List;

/**
 * 文本消息
 * 
 * @author liufeng
 * @date 2013-05-19
 */
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 org.liufeng.course.message.resp;

/**
 * 图文model
 * 
 * @author liufeng
 * @date 2013-05-19
 */
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 null == Description ? "" : Description;
	}

	public void setDescription(String description) {
		Description = description;
	}

	public String getPicUrl() {
		return null == PicUrl ? "" : PicUrl;
	}

	public void setPicUrl(String picUrl) {
		PicUrl = picUrl;
	}

	public String getUrl() {
		return null == Url ? "" : Url;
	}

	public void setUrl(String url) {
		Url = url;
	}

}

全部消息封装完成后,Eclipse工程中关于消息部分的结构应该与下图保持一致,如果不一致的(类名、属性名称不一致的)请检查后调整一致,因为后面的章节还要介绍如何将微信开发中通用的类方法、与业务无关的工具类封装打成jar包,以后再做微信项目只需要引入该jar包即可,这种工作做一次就可以了。

WeChat Public Account Development Tutorial Part 4 - Encapsulation of Messages and Message Processing Tools_PHP Tutorial

 

如何解析请求消息?

接下来解决请求消息的解析问题。微信服务器会将用户的请求通过doPost方法发送给我们,让我们再来回顾下上一章节已经写好的doPost方法的定义:

 

/** 
     * 处理微信服务器发来的消息 
     */  
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
        // TODO 消息的接收、处理、响应  
    }  
 

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

 

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

 

/**
 * 文本消息对象转换成xml
 * 
 * @param textMessage 文本消息对象
 * @return xml
 */
public static String textMessageToXml(TextMessage textMessage) {
	xstream.alias("xml", textMessage.getClass());
	return xstream.toXML(textMessage);
}

/**
 * 音乐消息对象转换成xml
 * 
 * @param musicMessage 音乐消息对象
 * @return xml
 */
public static String musicMessageToXml(MusicMessage musicMessage) {
	xstream.alias("xml", musicMessage.getClass());
	return xstream.toXML(musicMessage);
}

/**
 * 图文消息对象转换成xml
 * 
 * @param newsMessage 图文消息对象
 * @return xml
 */
public static String newsMessageToXml(NewsMessage newsMessage) {
	xstream.alias("xml", newsMessage.getClass());
	xstream.alias("item", new Article().getClass());
	return xstream.toXML(newsMessage);
}

/**
 * 扩展xstream,使其支持CDATA块
 * 
 * @date 2013-05-19
 */
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);
				}
			}
		};
	}
});

说明:由于xstream框架本身并不支持CDATA块的生成,40~62行代码是对xtream做了扩展,使其支持在生成xml各元素值时添加CDATA块。

消息处理工具的封装

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

 

package org.liufeng.course.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 org.liufeng.course.message.resp.Article;
import org.liufeng.course.message.resp.MusicMessage;
import org.liufeng.course.message.resp.NewsMessage;
import org.liufeng.course.message.resp.TextMessage;

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;

/**
 * 消息工具类
 * 
 * @author liufeng
 * @date 2013-05-19
 */
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)
	 * 
	 * @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;
	}

	/**
	 * 文本消息对象转换成xml
	 * 
	 * @param textMessage 文本消息对象
	 * @return xml
	 */
	public static String textMessageToXml(TextMessage textMessage) {
		xstream.alias("xml", textMessage.getClass());
		return xstream.toXML(textMessage);
	}

	/**
	 * 音乐消息对象转换成xml
	 * 
	 * @param musicMessage 音乐消息对象
	 * @return xml
	 */
	public static String musicMessageToXml(MusicMessage musicMessage) {
		xstream.alias("xml", musicMessage.getClass());
		return xstream.toXML(musicMessage);
	}

	/**
	 * 图文消息对象转换成xml
	 * 
	 * @param newsMessage 图文消息对象
	 * @return xml
	 */
	public static String newsMessageToXml(NewsMessage newsMessage) {
		xstream.alias("xml", newsMessage.getClass());
		xstream.alias("item", new Article().getClass());
		return xstream.toXML(newsMessage);
	}

	/**
	 * 扩展xstream,使其支持CDATA块
	 * 
	 * @date 2013-05-19
	 */
	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);
					}
				}
			};
		}
	});
}

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


www.bkjia.comtruehttp://www.bkjia.com/PHPjc/444574.htmlTechArticle工欲善其事必先利其器!本篇内容主要讲解如何将微信公众平台定义的消息及消息相关的操作封装成工具类,方面后期的使用。这里需要明...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn