失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 微信公众号开发 - 事件处理和回复消息

微信公众号开发 - 事件处理和回复消息

时间:2018-08-22 15:52:49

相关推荐

微信公众号开发 - 事件处理和回复消息

微信公众号开发文章目录

1.微信公众号开发 - 环境搭建

2.微信公众号开发 - 配置表设计以及接入公众号接口开发

3.微信公众号开发 - token获取(保证同一时间段内只请求一次)

4.微信公众号开发 - 菜单按钮bean封装

5.微信公众号开发 - 创建菜单

6.微信公众号开发 - 事件处理和回复消息

7.微信公众号开发 - 发送Emoji表情

项目完整代码请访问github:/liaozq0426/wx.git

上篇文章实现了微信公众号菜单创建,现在实现事件的处理和回复用户消息。

微信服务器会将所有的用户事件和消息通过公众号后台配置的服务器地址推送给我们,就是下图红框的URL

编写代码

因为接收微信消息和返回消息都需要以xml格式数据进行传输,因此我们先封装一个工具类BeanXmlUtil,来实现xml和对象之间的转换,这里用的是dom4j框架来处理xml

package com.gavin.util;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.dom4j.Document;import org.dom4j.DocumentHelper;import org.dom4j.Element;import org.dom4j.io.SAXReader;import com.thoughtworks.xstream.XStream;import com.thoughtworks.xstream.io.naming.NoNameCoder;import com.thoughtworks.xstream.io.xml.DomDriver;/*** @title Map对象 和 xml字符串之间相互转换* @author gavin* @date 4月21日*/public class BeanXmlUtil {/*** @title 从HttpServletRequest中获取xml数据流,并转换为String对象* @author gavin* @date 4月22日* @param request* @return xml字符串*/public static String xmltoString(HttpServletRequest request) {try {BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8"));StringBuffer sb = new StringBuffer();String line = null;while((line = br.readLine()) != null) {sb.append(line+"\n");}br.close();return sb.toString();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}/*** @title 从HttpServletRequest中获取xml数据流,并转换为map对象* @author gavin* @date 4月21日* @param request* @return map对象*/public static Map<String, String> xmlToMap(HttpServletRequest request) {Map<String, String> map = new HashMap<String, String>();SAXReader reader = new SAXReader();try {InputStream ins = request.getInputStream();Document doc = reader.read(ins);Element root = doc.getRootElement();@SuppressWarnings("unchecked")List<Element> list = root.elements();for (Element e : list) {map.put(e.getName(), e.getText());}ins.close();} catch (Exception e) {e.printStackTrace();}return map;}/*** @title 将xml字符串转换为map对象* @author gavin* @date 4月21日* @param request* @return map对象*/public static Map<String, String> xmlToMap(String xml) {Map<String, String> map = new HashMap<String, String>();try {// 将字符串转为xmlDocument doc = DocumentHelper.parseText(xml);Element root = doc.getRootElement();@SuppressWarnings("unchecked")List<Element> list = root.elements();for (Element e : list) {map.put(e.getName(), e.getText());}} catch (Exception e) {e.printStackTrace();}return map;}/*** @title 将object对象转换为xml字符串* @desc 不进行 双下划线、CDATA标记处理* @author gavin* @date 4月21日* @param object* @return xml字符串*/public static String beanToXmlDefault(Object object) {XStream xStream = new XStream(new DomDriver());xStream.alias("xml", object.getClass());return xStream.toXML(object);}/*** @title 将object对象转换为xml字符串* @desc 对 双下划线 问题进行处理,并进行CDATA标记处理,根节点自动设置名字为xml* @author gavin* @date 4月21日* @param object* @return xml字符串*/public static String beanToXmlCommon(Object object) {XStream xStream = new CommonXStream(new CommonXppDriver(new NoNameCoder()) ,object.getClass());return xStream.toXML(object);}}

要注意的是,最后一个方法beanToXmlCommon()中使用的不是默认的XStream和DomDriver,而是自定义的CommonXStream和CommonXppDriver,这是因为我们要对返回给微信的dom元素内容增加CDATA标记

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[image]]></MsgType><Image><MediaId><![CDATA[media_id]]></MediaId></Image></xml>

CommonXppDriver类代码如下,该类继承了XppDriver,实现对dom元素增加CDATA标记

package com.gavin.util;import java.io.Writer;import com.thoughtworks.xstream.core.util.QuickWriter;import com.thoughtworks.xstream.io.HierarchicalStreamWriter;import com.thoughtworks.xstream.io.naming.NoNameCoder;import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;import com.thoughtworks.xstream.io.xml.XppDriver;/*** @title 自定义XappDriver , 对dom元素增加CDATA标记* @author gavin* @date 11月29日*/public class CommonXppDriver extends XppDriver {public CommonXppDriver() {super();}public CommonXppDriver(NoNameCoder noNameCoder) {super(noNameCoder);}@Overridepublic HierarchicalStreamWriter createWriter(Writer out) {return new PrettyPrintWriter(out) {// 对所有xml节点的转换都增加CDATA标记boolean cdata = true;@Override@SuppressWarnings("rawtypes")public void startNode(String name, Class clazz) {super.startNode(name, clazz);}@Overridepublic String encodeNode(String name) {return name;}@Overrideprotected void writeText(QuickWriter writer, String text) {if (cdata) {writer.write("<![CDATA[");writer.write(text);writer.write("]]>");} else {writer.write(text);}}};}}

CommonXStream类代码如下,该类继承了XStream,构造函数接收一个CommonXppDriver对象。

package com.gavin.util;import com.thoughtworks.xstream.XStream;/*** @title 自定义XStream* @author gavin* @date 11月29日*/public class CommonXStream extends XStream {public CommonXStream(CommonXppDriver driver) {super(driver);}public CommonXStream(CommonXppDriver driver , Class<?> rootClassType) {super(driver);// 将根元素重命名为xmlthis.alias("xml", rootClassType);}}

工具类封装完成后,开始编写消息处理的代码,我们定义一个TextMessage类来封装微信文本消息字段

package com.gavin.pojo;/*** @title 文本消息bean* @author gavin* @date 11月29日*/public class TextMessage {private String ToUserName;// 消息接收方private String FromUserName;// 消息发送方private long CreateTime;private String MsgType;// 消息类型private String Content;// 消息内容public long getCreateTime() {return CreateTime;}public void setCreateTime(long createTime) {CreateTime = createTime;}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 String getMsgType() {return MsgType;}public void setMsgType(String msgType) {MsgType = msgType;}public String getContent() {return Content;}public void setContent(String content) {Content = content;}}

再编写一个微信消息类型定义bean,避免出现硬代码

package com.gavin.pojo;/*** @title 微信消息类型定义bean* @author gavin* @date 11月29日*/public class WxMessageConst {public static String MSG_TYPE = "MsgType";// 消息类型 包含text:文本消息、event:事件类型等public static String MSG_TYPE_TEXT = "text"; // 本文消息public static String MSG_TYPE_EVENT = "event";// 事件消息public static String EVENT = "Event";// 值可以为subscribe、unsubscribe等public static String EVENT_TYPE_SUBSCRIBE = "subscribe"; //订阅public static String EVENT_TYPE_UN_SUBSCRIBE = "unsubscribe"; //取消订阅public static String FROM_USER_NAME = "FromUserName";public static String TO_USER_NAME = "ToUserName";public static String CONTENT = "Content";// 消息内容public static String DEFAULT_MSG = "success";// 如果不返回自定义消息,则返回success}

接下来定义WxMsgService接口来处理事件消息

package com.gavin.service;import javax.servlet.http.HttpServletRequest;public interface WxMsgService {String processWxRequest(HttpServletRequest request) throws Exception;}

实现类WxMsgServiceImpl代码如下

package com.gavin.service.impl;import java.util.Date;import java.util.Map;import javax.servlet.http.HttpServletRequest;import mons.lang3.StringUtils;import org.apache.log4j.Logger;import org.springframework.stereotype.Service;import com.gavin.pojo.TextMessage;import com.gavin.pojo.WxMessageConst;import com.gavin.service.WxMsgService;import com.gavin.util.BeanXmlUtil;/*** @title 微信消息处理* @author gavin* @date 11月29日*/@Servicepublic class WxMsgServiceImpl implements WxMsgService{private Logger logger = Logger.getLogger(this.getClass());@Overridepublic String processWxRequest(HttpServletRequest request) throws Exception {// xml请求解析成mapMap<String, String> requestMap = BeanXmlUtil.xmlToMap(request);logger.info(requestMap.toString());// 发送方帐号String fromUserName = requestMap.get(WxMessageConst.FROM_USER_NAME);// 接受方帐号String toUserName = requestMap.get(WxMessageConst.TO_USER_NAME);// 消息类型String msgType = requestMap.get(WxMessageConst.MSG_TYPE);if (WxMessageConst.MSG_TYPE_EVENT.equals(msgType)) {// 事件消息类型// 订阅if (WxMessageConst.EVENT_TYPE_SUBSCRIBE.equals(requestMap.get(WxMessageConst.EVENT))) {// 关注时自动回复消息TextMessage textMessage = new TextMessage();textMessage.setContent("感谢您关注,我会继续努力!");textMessage.setCreateTime(new Date().getTime());textMessage.setFromUserName(toUserName);textMessage.setToUserName(fromUserName);textMessage.setMsgType(WxMessageConst.MSG_TYPE_TEXT);String response = BeanXmlUtil.beanToXmlCommon(textMessage);if(response != null)return response;} else if (WxMessageConst.EVENT_TYPE_UN_SUBSCRIBE.equals(requestMap.get(WxMessageConst.EVENT))) {// 取消订阅logger.info("用户" + fromUserName + "取消关注了");}}else if(WxMessageConst.MSG_TYPE_TEXT.equals(msgType)) {// 文本消息类型// 定义自动回复文本消息TextMessage textMessage = new TextMessage();if (!StringUtils.isBlank(msgType)) {textMessage.setFromUserName(toUserName);textMessage.setToUserName(fromUserName);textMessage.setCreateTime(new Date().getTime());textMessage.setMsgType(WxMessageConst.MSG_TYPE_TEXT);// 用户发送过来的消息String content = requestMap.get(WxMessageConst.CONTENT);logger.info(content);// 回复消息String rspContent = "您好,有什么问题可以问我!";textMessage.setContent(rspContent);if(!StringUtils.isBlank(textMessage.getContent())) {String response = BeanXmlUtil.beanToXmlCommon(textMessage);logger.info(response);if(response != null)return response;}}}else {// 其他消息}// 默认回复return WxMessageConst.DEFAULT_MSG;}}

实现类中处理了关注/取消关注事件回复用户文本消息,当有用户关注时会返回感谢您关注,我会继续努力!给客户端,当接收到用户的文本消息时,会返回您好,有什么问题可以问我!给客户端。

另外要注意的是,如果不想返回任何内容给客户端,需要返回success字符串,否则微信公众号会提示故障异常。

最后在WxController中编写wxIn方法,注意一定要定义为post请求,因为微信服务器是以post方式推送消息给我们的。

@PostMapping("wxIn")public void wxMsgReply(HttpServletRequest request, HttpServletResponse response){try {request.setCharacterEncoding("UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}response.setCharacterEncoding("UTF-8");try {// String respMsg = "success";String respMsg = wxMsgService.processWxRequest(request);PrintWriter out = response.getWriter();out.print(respMsg);out.flush();out.close();} catch (Exception e) {e.printStackTrace();}}

到这里,消息处理的代码就编写完成了

测试

现在我们来测试一下,重新关注一下微信公众号,公众自动回复了感谢您关注,我会继续努力!,如下图所示

向公众号发送一条文本消息,公众号回复了您好,有什么问题可以问我!,如下图所示

如果觉得《微信公众号开发 - 事件处理和回复消息》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。