您的位置:首页 > 移动开发 > 微信开发

微信公众号开发之如何实现消息交互

2016-10-13 22:56 337 查看
微信开发交流群:148540125

系列文章参考地址 极速开发微信公众号

欢迎留言、转发、打赏

项目源码参考地址 点我点我--欢迎Start


前几篇文章已讲完如何导入项目,如何启动配置项目,如何成为开发者(如果前三项不会的看这里 极速开发微信公众号。这篇文章就来讲讲如果实现消息交互


总所周知
Jfinal
开发中配置非常简单只要在
web.xml
中添加如下代码就可以将所有的请求交由
Jfianl
处理

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<filter>
<filter-name>jfinal</filter-name>
<filter-class>com.jfinal.core.JFinalFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>configClass</param-name>
<param-value>com.javen.common.APPConfig</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jfinal</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

可以看到
com.javen.common.APPConfig
是项目的核心配置文件,他是继承自
JFinalConfig
实现了如下方法




以上配置详细介绍参考官方文档

成为开发者模式这篇文章中讲到过消息交互都是由
WeixinMsgController
接管的,


消息到底是如何交互的在此做详细的讲解

上面有讲到消息交互都是由
WeixinMsgController
接管的,她是继承自
MsgControllerAdapter
又继承自
MsgController
里面有个
index
方法其中上面的拦截器
MsgInterceptor
是进行加密验证的(成为开发者模式),验证没有问题就执行
index
方法,如下图




可以看出接收消息并返回一个InMsg,之后根据信息类型调用对应的抽象方法交给实现方式实现消息的处理。


那么问题来了:

1、如何接收微信交互的xml

2、如何处理微信的各种消息

3、如何响应微信的各种消息

接收微信交互的xml

成功开发者(get请求)之后,所有的消息接收处理都交由开发者url处理(post请求)所以就有一下方法获取xml

@Before({NotAction.class})
public String getInMsgXml() {
if(this.inMsgXml == null) {
this.inMsgXml = HttpKit.readData(this.getRequest());
if(ApiConfigKit.getApiConfig().isEncryptMessage()) {
this.inMsgXml = MsgEncryptKit.decrypt(this.inMsgXml, this.getPara("timestamp"), this.getPara("nonce"), this.getPara("msg_signature"));
}
}

if(StrKit.isBlank(this.inMsgXml)) {
throw new RuntimeException("请不要在浏览器中请求该连接,调试请查看WIKI:http://git.oschina.net/jfinal/jfinal-weixin/wikis/JFinal-weixin-demo%E5%92%8C%E8%B0%83%E8%AF%95");
} else {
return this.inMsgXml;
}
}

解析微信的各种消息

@Before({NotAction.class})
public InMsg getInMsg() {
if(this.inMsg == null) {
this.inMsg = InMsgParser.parse(this.getInMsgXml());
}

return this.inMsg;
}

可以看到
this.inMsg
为null时会解析
InMsgParser.parse(this.getInMsgXml());
获取到的xml

public static InMsg parse(String xml) {
XmlHelper xmlHelper = XmlHelper.of(xml);
return doParse(xmlHelper);
}

静态方法 通过xml 实例化一个
XmlHelper
(主要提供一些常用类型数据的获取方法) 再交给
doParse
方法处理
text消息
image消息
voice消息
vide消息
shortvideo消息
location消息
link消息
eveen消息


private static InMsg doParse(XmlHelper xmlHelper) {
String toUserName = xmlHelper.getString("//ToUserName");
String fromUserName = xmlHelper.getString("//FromUserName");
Integer createTime = Integer.valueOf(xmlHelper.getNumber("//CreateTime").intValue());
String msgType = xmlHelper.getString("//MsgType");
if("text".equals(msgType)) {
return parseInTextMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
} else if("image".equals(msgType)) {
return parseInImageMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
} else if("voice".equals(msgType)) {
return parseInVoiceMsgAndInSpeechRecognitionResults(xmlHelper, toUserName, fromUserName, createTime, msgType);
} else if("video".equals(msgType)) {
return parseInVideoMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
} else if("shortvideo".equals(msgType)) {
return parseInShortVideoMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
} else if("location".equals(msgType)) {
return parseInLocationMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
} else if("link".equals(msgType)) {
return parseInLinkMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
} else if("event".equals(msgType)) {
return parseInEvent(xmlHelper, toUserName, fromUserName, createTime, msgType);
} else {
LogKit.error("无法识别的消息类型 " + msgType + ",请查阅微信公众平台开发文档");
return parseInNotDefinedMsg(toUserName, fromUserName, createTime, msgType);
}
}

解析出来消息类型之后就调用对应的解析方法并返回
InMsg


消息类型很多避免重复造轮子,所以就诞生了消息的封装这个东西。

查看所有普通消息的xml格式找规律进行封装 官方文档 可以发现都包含有
ToUserName
FromUserName
CreateTime
MsgId
不同的是
MsgType
以及 各个类型对应的消息内容。

这里是接收消息以及响应消息的截图



以解析
text消息
为栗子讲解

接收到的xml 如下

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

解析text消息

private static InMsg parseInTextMsg(XmlHelper xmlHelper, String toUserName, String fromUserName, Integer createTime, String msgType) {
InTextMsg msg = new InTextMsg(toUserName, fromUserName, createTime, msgType);
msg.setContent(xmlHelper.getString("//Content"));
msg.setMsgId(xmlHelper.getString("//MsgId"));
return msg;
}

封装text消息

public class InTextMsg extends InMsg {
private String content;
private String msgId;

public InTextMsg(String toUserName, String fromUserName, Integer createTime, String msgType) {
super(toUserName, fromUserName, createTime, msgType);
}

public String getContent() {
return this.content;
}

public void setContent(String content) {
this.content = content;
}

public String getMsgId() {
return this.msgId;
}

public void setMsgId(String msgId) {
this.msgId = msgId;
}
}

接收消息的公用部分

public abstract class InMsg {
protected String toUserName;
protected String fromUserName;
protected Integer createTime;
protected String msgType;

public InMsg(String toUserName, String fromUserName, Integer createTime, String msgType) {
this.toUserName = toUserName;
this.fromUserName = fromUserName;
this.createTime = createTime;
this.msgType = msgType;
}

public String getToUserName() {
return this.toUserName;
}

public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}

public String getFromUserName() {
return this.fromUserName;
}

public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}

public Integer getCreateTime() {
return this.createTime;
}

public void setCreateTime(Integer createTime) {
this.createTime = createTime;
}

public String getMsgType() {
return this.msgType;
}

public void setMsgType(String msgType) {
this.msgType = msgType;
}
}

响应微信的各种消息

由上分析可以知道,消息处理完成后都是交由抽象方法的实现方法处理消息。
MsgControllerAdapter
主要是适配各种消息的抽象类。

下面
text消息
为例子说明

接收到
text消息
之后会调用
WeixinMsgController
中的
protected void processInTextMsg(InTextMsg inTextMsg)
方法,可以通过
InTextMsg
对象获取
text消息


protected void processInTextMsg(InTextMsg inTextMsg)
{
String msgContent = inTextMsg.getContent().trim();
// 帮助提示
if ("help".equalsIgnoreCase(msgContent) || "帮助".equals(msgContent)) {
OutTextMsg outMsg = new OutTextMsg(inTextMsg);
outMsg.setContent(helpStr);
render(outMsg);
}else {
renderOutTextMsg("你发的内容为:"+msgContent);
//转发给多客服PC客户端
//      OutCustomMsg outCustomMsg = new OutCustomMsg(inTextMsg);
//      render(outCustomMsg);
}

}

以上可以看到响应消息有两种实现方式

第一种render一个消息对象

OutTextMsg outMsg = new OutTextMsg(inTextMsg);
outMsg.setContent(helpStr);
render(outMsg);

第二种直接传一个String

renderOutTextMsg("你发的内容为:"+msgContent);

以下是具体的实现:

1、将对象转化为xml
outMsg.toXml()


2、如果是开发模式输出调试的xml

3、如果是加密模式,就将消息加密

4、通过
Jfinal 的renderText()
方法应用xml

public void render(OutMsg outMsg) {
String outMsgXml = outMsg.toXml();
if(ApiConfigKit.isDevMode()) {
System.out.println("发送消息:");
System.out.println(outMsgXml);
System.out.println("--------------------------------------------------------------------------------\n");
}

if(ApiConfigKit.getApiConfig().isEncryptMessage()) {
outMsgXml = MsgEncryptKit.encrypt(outMsgXml, this.getPara("timestamp"), this.getPara("nonce"));
}

this.renderText(outMsgXml, "text/xml");
}

renderOutTextMsg(String content)
方法就是调用的
render(outMsg)
方法

public void renderOutTextMsg(String content) {
OutTextMsg outMsg = new OutTextMsg(this.getInMsg());
outMsg.setContent(content);
this.render(outMsg);
}

欢迎留言、转发、打赏

项目源码参考地址 点我点我--欢迎Start
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: