1 说明
本篇博文承接上一篇博文:https://www.cnblogs.com/NeverCtrl-C/p/10241763.html
2 接收文本消息
微信公众号官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140453
说明:接收文本消息属于接收普通消息的范围,当公众号粉丝向公众号发送消息时,微信服务器会向开发者服务器发送一个POST请求,这个POST请求携带XML格式的数据包到开发者填写的URL上
2.1 文本消息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>
2.2 文本消息参数说明
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | text |
Content | 文本消息内容 |
MsgId | 消息id,64位整型 |
step01 创建一个com.xunyji.xunyjitest.comm.TransformUtils类用来存放一下数据类型转换相关的工具方法2.3 Java代码实现
step02 引入XML和对象相互转换相关的jar包
<!--xml2对象 start--> <!-- https://mvnrepository.com/artifact/dom4j/dom4j --> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <!--xml2对象 end--> <!--对象2XML start--> <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream --> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.3.1</version> </dependency> <!--对象2XML end-->
step03 创建com.xunyji.xunyjitest.comm.TransformUtils#xml2Map方法用于将XML转化成Map类型
/** * xml转换成map【微信平台请求开发者平台时的数据格式都是XML格式的】 * @param request * @return * @throws IOException * @throws DocumentException */ public static Map<String, String> xml2Map(HttpServletRequest request) throws IOException, DocumentException { // 01 定义Map对象用来存放数据 Map<String, String> map = new HashMap<>(); // 02 创建SAXReader用于读取xml文件 SAXReader reader = new SAXReader(); // 03 读取Request中的信息 InputStream ins = request.getInputStream(); Document doc = reader.read(ins); // 04 获取xml的根元素 Element root = doc.getRootElement(); // 05 获取根元素中的所有子元素 List<Element> list = root.elements(); // 06 遍历所有子元素并将数据存放到定义好的集合中 for (Element e : list) { map.put(e.getName(), e.getText()); } // 07 关闭输入流 ins.close(); // 08 返回存放xml内容的Map对象 return map; }
step04 创建一个com.xunyji.xunyjitest.web.weixin.WeixinController#receiveMessage方法用于接收微信平台发送的POST请求
step0401 该方法接收POST请求
step0402 通过 HttpServletRequest 对象获取微信平台传过来的XML数据包
step0403 将XML数据转化成Map数据并打印输出
@PostMapping public void receiveMessage(HttpServletRequest request, HttpServletResponse response) throws IOException, DocumentException { // 01 请求、响应编码格式设定 request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); // 02 获取输出对象 PrintWriter out = response.getWriter(); // 03 获取微信平台传过来的请求参数【PS:默认是XML格式的,这里转化成了Mapl类型】 Map<String, String> receiveMap = TransformUtils.xml2Map(request); log.info("接收微信消息时获取到的信息为:" + receiveMap); // 04 从Map对象中获取单个数据 String fromUserName = receiveMap.get("FromUserName"); String toUserName = receiveMap.get("ToUserName"); String msgType = receiveMap.get("MsgType"); String content = receiveMap.get("Content"); }
step0404 启动项目并通过粉丝账户向公众号发送文本消息,效果如图所示
3 回复文本消息
回复文本消息属于被动回复消息的范围,微信官网提供的被动回复消息文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140543
技巧01:粉丝向公众号发送消息时微信服务器会向开发者服务器发送一个POST请求,开发者可以从这个POST请求中获取到一些信息,也可以像发送者返回一些信息
3.1 回复文本消息XML格式
<xml> <ToUserName>< ![CDATA[toUser] ]></ToUserName> <FromUserName>< ![CDATA[fromUser] ]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType>< ![CDATA[text] ]></MsgType> <Content>< ![CDATA[你好] ]></Content> </xml>
3.2 回复文本消息参数说明
参数 | 是否必须 | 说明 |
---|---|---|
ToUserName | 是 | 接收方帐号(收到的OpenID) |
FromUserName | 是 | 开发者微信号 |
CreateTime | 是 | 消息创建时间 (整型) |
MsgType | 是 | image |
MediaId | 是 | 通过素材管理中的接口上传多媒体文件,得到的id。 |
3.3 Java代码实现
step01 创建一个com.xunyji.xunyjitest.model.weixin.send.SendBaseMessage类作为所有被动回复消息的基类
step02 创建一个com.xunyji.xunyjitest.model.weixin.send.ReplyTextMessage类作为回复文本消息的实体类
@Data @NoArgsConstructor @AllArgsConstructor public class ReplyTextMessage extends ReplyBaseMessage { /** 回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示) */ private String Content; }
step03 创建一个com.xunyji.xunyjitest.comm.enums.weixin.MessageTypeEnum枚举类来存放各种消息类型
@Getter public enum MessageTypeEnum { // 接收普通消息类型【0开头表示接收的消息类型】 start /** 被动回复文本消息 */ RECEIVE_MESSAGE_TEXT(001, "text"), RECEIVE_MESSAGE_IMAGE(002, "image"), RECEIVE_MESSAGE_VOICE(003, "voice"), RECEIVE_MESSAGE_LOCATION(004, "location"), RECEIVE_MESSAGE_LINK(005, "link"), RECEIVE_MESSAGE_SHORTVIDEO(06, "shortvideo"), RECEIVE_MESSAGE_VIDEO(007, "video"), // 接收普通消息类型【0开头表示接收的消息类型】 end ; /** 消息类型编号 */ private Integer code; /** 消息类型(和微信文档中保持一致) */ private String type; MessageTypeEnum(Integer code, String type) { this.code = code; this.type = type; } }
step04 创建一个com.xunyji.xunyjitest.comm.util.weixin.MessageUtils类作为各种消息封装类
step0401 创建com.xunyji.xunyjitest.comm.util.weixin.MessageUtils#replyTextMessageToXml方法实现将ReplyTextMessage 转化成 XML
/** * ReplyTextMessage 转化成 XML * @param replyTextMessage * @return */ private String replyTextMessageToXml(ReplyTextMessage replyTextMessage) { XStream xStream = new XStream(); xStream.alias("xml", replyTextMessage.getClass()); return xStream.toXML(replyTextMessage); }
step0402 创建com.xunyji.xunyjitest.comm.util.weixin.MessageUtils#initReplyTextMessage方法实现封装回复文本消息时所需的XML格式字符串
/** * 封装XML格式的"发送文本消息" * @param fromUserName 粉丝appId * @param toUserName 公众号appId * @param content XML格式的字符串 * @return */ public String initReplyTextMessage(String fromUserName, String toUserName, String content) { ReplyTextMessage text = new ReplyTextMessage(); text.setToUserName(fromUserName); text.setFromUserName(toUserName); text.setMsgType(MessageTypeEnum.RECEIVE_MESSAGE_TEXT.getType()); long time = System.currentTimeMillis(); text.setCreateTime(String.valueOf(time)); text.setContent("逆向公众号发送了:" + content); return replyTextMessageToXml(text); }
step05 重构com.xunyji.xunyjitest.web.weixin.WeixinController#receiveMessage方法实现接收文本消息时回复文本消息,其他消息不做任何处理
step0501 从封装了请求数据的map集合中获取公众号appid(toUserName)、粉丝appid(fromUserName)、接收消息类型(msgType)
step0502 判断接收消息类型并做相应处理,此处以接收到的消息类型为文本消息为例
如果是文本消息就获取文本内容,然后封装响应数据即可
step0503 必须对响应数据进行非空处理,因为如果响应数据为null就会出现一个错误,很影响用户体验
@PostMapping public void receiveMessage(HttpServletRequest request, HttpServletResponse response) throws IOException, DocumentException { // 01 请求、响应编码格式设定 request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); // 02 获取输出对象 PrintWriter out = response.getWriter(); // 03 获取微信平台传过来的请求参数【PS:默认是XML格式的,这里转化成了Mapl类型】 Map<String, String> receiveMap = TransformUtils.xml2Map(request); log.info("接收微信消息时获取到的信息为:" + receiveMap); // 04 从Map对象中获取单个数据 String fromUserName = receiveMap.get("FromUserName"); String toUserName = receiveMap.get("ToUserName"); String msgType = receiveMap.get("MsgType"); // 05 用于存放String类型的XML格式响应数据 String message = null; // 06 如果接收的消息类型是text类型的处理逻辑 if (MessageTypeEnum.RECEIVE_MESSAGE_TEXT.getType().equals(msgType)) { String content = receiveMap.get("Content"); message = new MessageUtils().initReplyTextMessage(fromUserName, toUserName, content); } // 07 响应对象非空处理,如果返回null会报异常(影响用户体验) if (message == null) { message = ""; } // 08 打印XML格式的响应消息 log.info("被动回复消息的XML格式为:" + message); // 09 响应XML格式数据给微信服务器 out.print(message); }
step06 启动项目并向公众号发送文本消息,效果如图所示
3.4 代码重构
应该根据不同的消息类型调用不同的服务层方法来实现业务逻辑,不应该将所有业务逻辑都放到controller层中
step01 引入fastjson依赖,因为需要将Map转化成Bean
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.54</version> </dependency>
step02 创建com.xunyji.xunyjitest.service.ReceiveMessageService接口用于定义处理各种接收到的消息
step03 创建com.xunyji.xunyjitest.service.ReceiveMessageServiceImpl实现了实现处理各种接收到的消息
step04 创建com.xunyji.xunyjitest.comm.TransformUtils#parseMap2Object方法用于将Map转化成Bean
/** * Map类型转化成指定类型 * @param paramMap 待转化的Map对象 * @param clazz 目标类型的类类型 * @param <T> 目标类型 * @return */ public static <T> T parseMap2Object(Map<String, String> paramMap, Class<T> clazz) { return JSONObject.parseObject(JSONObject.toJSONString(paramMap), clazz); }
step05 创建com.xunyji.xunyjitest.service.ReceiveMessageServiceImpl#textMessageHandler方法用于处理文本类型消息
@Override public String textMessageHandler(Map<String, String> receiveParam) { // 01 用于存放封装好的回复文本消息的XML数据 String message = null; // 02 将Map类型参数转化成ReceiveTextMessage类型 ReceiveTextMessage receiveTextMessage = TransformUtils.parseMap2Object(receiveParam, ReceiveTextMessage.class); log.info("接收到的text消息请求参数为:" + receiveTextMessage); // 03 获取文本内容和双方信息 // 0301 粉丝appId String fromUserName = receiveTextMessage.getFromUserName(); // 0302 公众号appId String toUserName = receiveTextMessage.getToUserName(); // 0303 接收到的文本内容 String content = receiveTextMessage.getContent(); content = content.trim(); // 04 根据文本内容响应不同的数据 TODO: 应该将接收到的消息信息存储到数据库或者缓存中 if ("1".equals(content)) { message = messageUtils.initReplyTextMessage(fromUserName, toUserName, messageUtils.firstMenu()); } else if ("2".equals(content)) { message = messageUtils.initReplyTextMessage(fromUserName, toUserName, messageUtils.secondMenu()); } else if ("?".equals(content) || "?".equals(content)) { message = messageUtils.initReplyTextMessage(fromUserName, toUserName, messageUtils.menuText()); } else { message = messageUtils.initReplyTextMessage(fromUserName, toUserName, content); } return message; }
step06 在com.xunyji.xunyjitest.web.weixin.WeixinController#receiveMessage方法中,如果是文本消息类型就调用com.xunyji.xunyjitest.service.ReceiveMessageService#textMessageHandler实现业务处理
step07 启动应用并以此发送 1、2、?、?,效果图如下:
4 接入百度翻译功能
待定更新时间:2019年1月10日23:23:02
扫码获取源代码