上一篇讲了通过封装json格式数据测试自定义菜单功能,这篇讲基础消息能力的接收普通消息和被动回复用户消息。
1.引入
开始我们将自己的服务器与微信服务器进行绑定时,将微信的GET请求获取并作了相关的验证,而对于用户在公众号上发消息等操作的时候微信服务器也会通过POST请求发送到我们填写的URL上,我们可以根据收到的信息进行相关的响应回复操作。
2.测试用户发消息操作,本地收到的POST请求 WeCharController
// 获取微信返回数据 @PostMapping public String getWeChar(@RequestBody String message) throws Exception { System.out.println("接收到微信返回的消息:"+message); return null; } 复制代码
控制台信息,可以看到,当在微信公众号发送文字消息时,本地服务收到如下消息。
ToUserName: gh_1e06f4c4ca61 开发者微信号
FromUserName: oITpR58LM-HJG0Fa4BY6MkOCG5lM 发送方帐号(一个OpenID)
CreateTime:1664693332 消息创建时间 (整型)
MsgType :text 消息类型,文本为text
Content: 文本消息内容
MsgId :消息id,64位整型
接收到微信返回的消息:<xml><ToUserName><![CDATA[gh_1e06f4c4ca61]]></ToUserName> <FromUserName><![CDATA[oITpR58LM-HJG0Fa4BY6MkOCG5lM]]></FromUserName> <CreateTime>1664693332</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[哈哈哈测试。。。]]></Content> <MsgId>23832676103729051</MsgId> </xml> 复制代码
图片消息特有的信息:
PicUrl: 图片链接(由系统生成)
MediaId:图片消息媒体id,可以调用获取临时素材接口拉取数据。
MsgId:消息id,64位整型
MsgDataId: 消息的数据ID(消息如果来自文章时才有)
接收到微信返回的消息:<xml><ToUserName><![CDATA[gh_1e06f4c4ca61]]></ToUserName> <FromUserName><![CDATA[oITpR58LM-HJG0Fa4BY6MkOCG5lM]]></FromUserName> <CreateTime>1664693659</CreateTime> <MsgType><![CDATA[image]]></MsgType> <PicUrl><![CDATA[http://mmbiz.qpic.cn/mmbiz_jpg/ZfcbAy54RBxoL0ZBCbvnvCERD7F7D1uNBY6fbO6UGnv2QRslGwicfhx4PXFOJJB3TnJkfmX8TI9pwfCqOdGjb0Q/0]]></PicUrl> <MsgId>23832682835649773</MsgId> <MediaId><![CDATA[uqSJdeAYZuyROkywTrIYTT0rJooLGBCEKwTGU-F8-Y1PF855UQPoQnpt3bQaytGP]]></MediaId> </xml> 复制代码
语音消息特有的信息: Format:语音格式:amr Recognition: 语音识别结果,UTF8编码
接收到微信返回的消息:<xml><ToUserName><![CDATA[gh_1e06f4c4ca61]]></ToUserName> <FromUserName><![CDATA[oITpR58LM-HJG0Fa4BY6MkOCG5lM]]></FromUserName> <CreateTime>1664693943</CreateTime> <MsgType><![CDATA[voice]]></MsgType> <MediaId><![CDATA[uqSJdeAYZuyROkywTrIYTeWX2VBmyIJL75ADGHxjFTZICINUYLZxshP4WRJdF5b6]]></MediaId> <Format><![CDATA[amr]]></Format> <MsgId>23832683876255433</MsgId> <Recognition><![CDATA[]]></Recognition> </xml> 复制代码
未开启接收语音识别结果权限Recognition是空的,因此开启接收语音识别结果权限
接收到微信返回的消息:<xml><ToUserName><![CDATA[gh_1e06f4c4ca61]]></ToUserName> <FromUserName><![CDATA[oITpR5-x01JQu8doRMMgaFDYU3eM]]></FromUserName> <CreateTime>1664694297</CreateTime> <MsgType><![CDATA[voice]]></MsgType> <MediaId><![CDATA[uqSJdeAYZuyROkywTrIYTXiT-nSSIDQ92XkbO9idN2RCdxdXap8xIs-X4MVU48FY]]></MediaId> <Format><![CDATA[amr]]></Format> <MsgId>7149807563452710912</MsgId> <Recognition><![CDATA[你好。]]></Recognition> </xml> 复制代码
其他消息,就不再介绍了,基本上不同的消息都会有自己特有的属性,其他属性则是各种消息所共有的。
3.被动响应用户的消息
当我们服务器收到用户的一些消息操作时,我们可以通过收到的消息类型、消息内容进行相应的回复操作。从上面的收到的消息信息可以看出,我们收到的消息是XML格式的信息,因此我们需要将其转为MAP格式数据从而方便我们的处理,同时再将要响应的结果转为XML进行返回。 引入相关依赖
<dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.1</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.10</version> </dependency> 复制代码
其中dom4j依赖的DocumentHelper.parseText方法 是将给定文本 XML解析为新创建的 Document。我们通过对Document遍历赋值转为MAP格式数据。 而xstream依赖的toXML方法是将对象转化为XML信息进行返回(其中对象属性上需要增加 @XStreamAlias("相关字段")注解)。
创建XmlUtils 转化处理工具类
import com.thoughtworks.xstream.XStream; import org.apache.commons.lang.StringUtils; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import java.util.HashMap; import java.util.List; import java.util.Map; /** * XML对象处理类 * * @auther: wanghongjie * @blame: wanghongjie * @date: 2020-08-30 17:31 * @Description: */ public class XmlUtils { /** * 将xml格式的字符串转换成Map对象 * * @param xmlStr xml格式的字符串 * @return Map对象 * @throws Exception 异常 */ public static Map<String, Object> xmlStrToMap(String xmlStr) throws Exception { if (StringUtils.isEmpty(xmlStr)) { return null; } Map<String, Object> map = new HashMap<>(16); //将xml格式的字符串转换成Document对象 Document doc = DocumentHelper.parseText(xmlStr); //获取根节点 Element root = doc.getRootElement(); //获取根节点下的所有元素 List children = root.elements(); //循环所有子元素 if (children != null && children.size() > 0) { for (Object o : children) { Element child = (Element) o; map.put(child.getName(), child.getTextTrim()); } } return map; } public static String beanToXml(Object object, Class cls) { XStream stream = new XStream(); stream.processAnnotations(cls); return stream.toXML(object); } } 复制代码
创建公共消息参数处理类BaseMessage (任何消息的公共属性类,对应具体消息只需要继承该类即可)
import com.ctsi.sddx.constants.WeCharConstant; import com.thoughtworks.xstream.annotations.XStreamAlias; import lombok.Data; import java.io.Serializable; import java.util.Map; /** * 公共消息参数处理类 * Created with IntelliJ IDEA. * User: wanghongjie * Date: 2020/10/17 - 09:56 * <p> * Description: */ @Data public class BaseMessage implements Serializable { /** * 消息ID 64位整型 */ @XStreamAlias("MsgId") private String msgId; /** * 开发者微信号 */ @XStreamAlias("ToUserName") private String toUserName; /** * 发送方帐号(一个OpenID) */ @XStreamAlias("FromUserName") private String fromUserName; /** * 消息创建时间 (整型) */ @XStreamAlias("CreateTime") private String createTime; /** * 消息类型,文本为text */ @XStreamAlias("MsgType") private String msgType; void init(Map<String, Object> map) { this.createTime = String.valueOf(map.get(WeCharConstant.CREATE_TIME)); this.fromUserName = String.valueOf(map.get(WeCharConstant.FROM_USER_NAME)); this.toUserName = String.valueOf(map.get(WeCharConstant.TO_USER_NAME)); this.msgType = String.valueOf(map.get(WeCharConstant.MSG_TYPE)); this.msgId = String.valueOf(map.get(WeCharConstant.MSG_ID)); } } 复制代码
文本消息实体类TextMessage
import cn.org.spring.common.util.XmlUtils; import com.thoughtworks.xstream.annotations.XStreamAlias; import lombok.Data; import java.util.Map; /** * Created with IntelliJ IDEA. * User: wanghongjie * Date: 2020/10/17 - 10:01 * <p> * Description: */ @Data @XStreamAlias("xml") public class TextMessage extends BaseMessage { @XStreamAlias("Content") private String content; public static TextMessage of(Map<String, Object> objectMap, String content) { TextMessage textMessage = new TextMessage(); textMessage.init(objectMap); textMessage.setContent(content); return textMessage; } public static TextMessage ofSendMsg(Map<String, Object> objectMap, String content) { TextMessage textMessage = new TextMessage(); textMessage.init(objectMap); textMessage.setContent(content); textMessage.setMsgType("text"); String from = textMessage.getFromUserName(); textMessage.setFromUserName(textMessage.getToUserName()); textMessage.setToUserName(from); return textMessage; } public String toXml() { return XmlUtils.beanToXml(this, TextMessage.class); } } 复制代码
测试 WeCharController
// 获取微信返回数据 @PostMapping public String getWeChar(@RequestBody String message) throws Exception { System.out.println("接收到微信返回的消息:"+message); Map<String, Object> stringObjectMap = XmlUtils.xmlStrToMap(message); TextMessage textMessage = TextMessage.ofSendMsg(stringObjectMap, "你好呀,欢迎关注我的测试公众号!"); String responseMessage = textMessage.toXml(); System.out.println("响应微信平台的消息:"+responseMessage); return responseMessage; } 复制代码
控制台输出:
接收到微信返回的消息:<xml><ToUserName><![CDATA[gh_1e06f4c4ca61]]></ToUserName> <FromUserName><![CDATA[oITpR5-x01JQu8doRMMgaFDYU3eM]]></FromUserName> <CreateTime>1664696395</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[滴滴滴]]></Content> <MsgId>23832721292703678</MsgId> </xml> 响应微信平台的消息:<xml> <MsgId>23832721292703678</MsgId> <ToUserName>oITpR5-x01JQu8doRMMgaFDYU3eM</ToUserName> <FromUserName>gh_1e06f4c4ca61</FromUserName> <CreateTime>1664696395</CreateTime> <MsgType>text</MsgType> <Content>你好呀,欢迎关注我的测试公众号!</Content> </xml> 复制代码
测试号响应效果:
思考
当你这么写的话貌似把响应信息的处理写死了,无论你发送的是文本信息,还是图片信息、语音信息他都会只回复这个信息。
下篇文章: 使用策略模式处理复杂消息