微信开发交流群:148540125html
系列文章参考地址 极速开发微信公众号java
欢迎留言、转发、打赏
项目源码参考地址 点我点我--欢迎Startgit
前几篇文章已讲完如何导入项目,如何启动配置项目,如何成为开发者(若是前三项不会的看这里 极速开发微信公众号。这篇文章就来说讲若是实现消息交互web
总所周知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
方法,以下图app
能够看出接收消息并返回一个InMsg,以后根据信息类型调用对应的抽象方法交给实现方式实现消息的处理。微信公众平台
那么问题来了:
一、如何接收微信交互的xml
二、如何处理微信的各类消息
三、如何响应微信的各类消息async
成功开发者(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);
如下是具体的实现:
一、将对象转化为xml outMsg.toXml()
二、若是是开发模式输出调试的xml
三、若是是加密模式,就将消息加密
四、经过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