一、前言
今天开始讲解微信公众号开发如何接收普通消息,包括文本消息、图片消息、语音消息以及视频消息等。
不妥当之处多多指正。
二、消息的POST过程
2.1 POST过程图解
消息在微信服务器和开发者服务器之间的传输过程如下,不同之处在于,普通微信用户向公众账号发送的消息,微信服务器将消息进行XML形式的封装,封装成XML数据包,然后将消息的XML数据包POST到开发者填写的URL上:
2.2 XML数据包示例
以文本消息为例:
一条普通的文本消息共有以下几个属性,XML将这些属性封装成XML的形式进行POST传送。
<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>
2.3 消息传输的全过程
如2.1图示,开发者服务器在接收到来自微信服务器的XML数据包后,需要将XML数据包1.解析,然后进行2.业务处理,然后将业务处理的结果再次进行3.封装成XML数据,4.POST到微信服务器,再又5.微信服务器发送到客户端。
下面对各个数据解析和封装过程进行详解。
1.解析XML数据包
/**
* xml转换成Map
*/
public static Map<String, String>
xmlToMap(HttpServletRequest request)
throws IOException, DocumentException {
request.setCharacterEncoding(
"UTF-8");
Map<String, String> map =
new HashMap<String, String>();
SAXReader reader =
new SAXReader();
InputStream ins = request.getInputStream();
Document doc = reader.read(ins);
Element root = doc.getRootElement();
List<Element> list = root.elements();
for (Element e : list) {
map.put(e.getName(), e.getText());
}
ins.close();
return map;
}
2.业务处理
略
3.封装成XML数据
/**
* text转换成xml
*/
public static String
textMessageToXml(TextMessage textMessage) {
XStream xstream =
new XStream();
xstream.alias(
"xml", textMessage.getClass());
return xstream.toXML(textMessage);
}
三、实现接收普通消息
完整代码实现。
3.1 消息属性TextMessage
package cn.edu.sdut.model;
public class TextMessage {
private String ToUserName;
private String FromUserName;
private long CreateTime;
private String MsgType;
private String Content;
private String 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 String
getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
public String
getMsgId() {
return MsgId;
}
public void setMsgId(String msgId) {
MsgId = msgId;
}
}
3.2 数据处理MessageUtil
package cn.edu.sdut.service;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.thoughtworks.xstream.XStream;
import cn.edu.sdut.model.TextMessage;
public class MessageUtil {
/**
* xml转换成Map
*/
public static Map<String, String>
xmlToMap(HttpServletRequest request)
throws IOException, DocumentException {
request.setCharacterEncoding(
"UTF-8");
Map<String, String> map =
new HashMap<String, String>();
SAXReader reader =
new SAXReader();
InputStream ins = request.getInputStream();
Document doc = reader.read(ins);
Element root = doc.getRootElement();
List<Element> list = root.elements();
for (Element e : list) {
map.put(e.getName(), e.getText());
}
ins.close();
return map;
}
/**
* text转换成xml
*/
public static String
textMessageToXml(TextMessage textMessage) {
XStream xstream =
new XStream();
xstream.alias(
"xml", textMessage.getClass());
return xstream.toXML(textMessage);
}
}
3.3 业务处理MessageController
package cn
.edu.sdut.controller
import java
.io.IOException
import java
.io.PrintWriter
import java
.util.Date
import java
.util.Map
import javax
.servlet.ServletException
import javax
.servlet.http.HttpServlet
import javax
.servlet.http.HttpServletRequest
import javax
.servlet.http.HttpServletResponse
import org
.dom4j
.DocumentException
import cn
.edu.sdut.model.TextMessage
import cn
.edu.sdut.service.CheckUtil
import cn
.edu.sdut.service.MessageUtil
public class WeChatServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String signature = req
.getParameter(
"signature")
String timestamp = req
.getParameter(
"timestamp")
String nonce = req
.getParameter(
"nonce")
String echostr = req
.getParameter(
"echostr")
// 调用逻辑验证
PrintWriter
out = resp
.getWriter()
if (CheckUtil
.checkSignature(signature, timestamp, nonce)) {
out.println(echostr)
}
out.close()
out = null
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 设置一下相应的格式
req
.setCharacterEncoding(
"UTF-8")
resp
.setCharacterEncoding(
"UTF-8")
PrintWriter
out = resp
.getWriter()
Map<String, String> map
try {
map = MessageUtil
.xmlToMap(req)
String fromUserName = map
.get(
"FromUserName")
String toUserName = map
.get(
"ToUserName")
String msgType = map
.get(
"MsgType")
String content = map
.get(
"Content")
String format = map
.get(
"Format")
String message = null
if (
"text".equals(msgType)) {
TextMessage text = new TextMessage()
text
.setFromUserName(toUserName)
text
.setToUserName(fromUserName)
text
.setMsgType(
"text")
text
.setCreateTime(new Date()
.getTime())
text
.setContent(
"您发送的消息类型是:" + msgType +
";")
message = MessageUtil
.textMessageToXml(text)
}
if (
"image".equals(msgType)) {
TextMessage text = new TextMessage()
text
.setFromUserName(toUserName)
text
.setToUserName(fromUserName)
text
.setMsgType(
"text")
text
.setCreateTime(new Date()
.getTime())
text
.setContent(
"您发送的消息类型是:" + msgType +
";")
message = MessageUtil
.textMessageToXml(text)
}
if (
"voice".equals(msgType)) {
TextMessage text = new TextMessage()
text
.setFromUserName(toUserName)
text
.setToUserName(fromUserName)
text
.setMsgType(
"text")
text
.setCreateTime(new Date()
.getTime())
text
.setContent(
"您发送的消息类型是:" + msgType +
";")
message = MessageUtil
.textMessageToXml(text)
}
out.println(message)
} catch (DocumentException e) {
e
.printStackTrace()
} finally {
out.close()
}
}
}
四、项目代码仓库
详细、完整项目代码请移步:
https://github.com/GaoZiqiang/WeChatDevelopment