第三篇之消息的收发

前一篇文章里我们已经把微信公众平台接口中消息及相关操作都进行了封装,本章节将主要介绍如何接收微信服务器发送的消息并做出响应。

明确在哪接收消息

从微信公众平台接口消息指南中可以了解到,当用户向公众帐号发消息时,微信服务器会将消息通过POST方式提交给我们在接口配置信息中填写的URL,而我们就需要在URL所指向的请求处理类CoreServlet的doPost方法中接收消息、处理消息和响应消息。

 

接收、处理、响应消息

下面先来看我已经写好的CoreServlet的完整代码:

[java] view plain copy

  1. package org.liufeng.course.servlet;
  2. import java.io.IOException;
  3. import java.io.PrintWriter;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.http.HttpServlet;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. import org.liufeng.course.service.CoreService;
  9. import org.liufeng.course.util.SignUtil;
  10. /**
  11. * 核心请求处理类
  12. *
  13. * @author liufeng
  14. * @date 2013-05-18
  15. */
  16. public class CoreServlet extends HttpServlet {
  17. private static final long serialVersionUID = 4440739483644821986L;
  18. /**
  19. * 确认请求来自微信服务器
  20. */
  21. public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  22. // 微信加密签名
  23. String signature = request.getParameter("signature");
  24. // 时间戳
  25. String timestamp = request.getParameter("timestamp");
  26. // 随机数
  27. String nonce = request.getParameter("nonce");
  28. // 随机字符串
  29. String echostr = request.getParameter("echostr");
  30. PrintWriter out = response.getWriter();
  31. // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
  32. if (SignUtil.checkSignature(signature, timestamp, nonce)) {
  33. out.print(echostr);
  34. }
  35. out.close();
  36. out = null;
  37. }
  38. /**
  39. * 处理微信服务器发来的消息
  40. */
  41. public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  42. // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
  43. request.setCharacterEncoding("UTF-8");
  44. response.setCharacterEncoding("UTF-8");
  45. // 调用核心业务类接收消息、处理消息
  46. String respMessage = CoreService.processRequest(request);
  47. // 响应消息
  48. PrintWriter out = response.getWriter();
  49. out.print(respMessage);
  50. out.close();
  51. }
  52. }

代码说明:

1)第51行代码:微信服务器POST消息时用的是UTF-8编码,在接收时也要用同样的编码,否则中文会乱码;

2)第52行代码:在响应消息(回复消息给用户)时,也将编码方式设置为UTF-8,原理同上;

3)第54行代码:调用CoreService类的processRequest方法接收、处理消息,并得到处理结果;

4)第57~59行:调用response.getWriter().write()方法将消息的处理结果返回给用户

从doPost方法的实现可以看到,它是通过调用CoreService类的processRequest方法接收、处理消息的,这样做的目的是为了解耦,即业务相关的操作都不在Servlet里处理,而是完全交由业务核心类CoreService去做。下面来看CoreService类的代码实现:

[java] view plain copy

  1. package org.liufeng.course.service;
  2. import java.util.Date;
  3. import java.util.Map;
  4. import javax.servlet.http.HttpServletRequest;
  5. import org.liufeng.course.message.resp.TextMessage;
  6. import org.liufeng.course.util.MessageUtil;
  7. /**
  8. * 核心服务类
  9. *
  10. * @author liufeng
  11. * @date 2013-05-20
  12. */
  13. public class CoreService {
  14. /**
  15. * 处理微信发来的请求
  16. *
  17. * @param request
  18. * @return
  19. */
  20. public static String processRequest(HttpServletRequest request) {
  21. String respMessage = null;
  22. try {
  23. // 默认返回的文本消息内容
  24. String respContent = "请求处理异常,请稍候尝试!";
  25. // xml请求解析
  26. Map<String, String> requestMap = MessageUtil.parseXml(request);
  27. // 发送方帐号(open_id)
  28. String fromUserName = requestMap.get("FromUserName");
  29. // 公众帐号
  30. String toUserName = requestMap.get("ToUserName");
  31. // 消息类型
  32. String msgType = requestMap.get("MsgType");
  33. // 回复文本消息
  34. TextMessage textMessage = new TextMessage();
  35. textMessage.setToUserName(fromUserName);
  36. textMessage.setFromUserName(toUserName);
  37. textMessage.setCreateTime(new Date().getTime());
  38. textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
  39. textMessage.setFuncFlag(0);
  40. // 文本消息
  41. if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
  42. respContent = "您发送的是文本消息!";
  43. }
  44. // 图片消息
  45. else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
  46. respContent = "您发送的是图片消息!";
  47. }
  48. // 地理位置消息
  49. else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
  50. respContent = "您发送的是地理位置消息!";
  51. }
  52. // 链接消息
  53. else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
  54. respContent = "您发送的是链接消息!";
  55. }
  56. // 音频消息
  57. else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
  58. respContent = "您发送的是音频消息!";
  59. }
  60. // 事件推送
  61. else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
  62. // 事件类型
  63. String eventType = requestMap.get("Event");
  64. // 订阅
  65. if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {
  66. respContent = "谢谢您的关注!";
  67. }
  68. // 取消订阅
  69. else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {
  70. // TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息
  71. }
  72. // 自定义菜单点击事件
  73. else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {
  74. // TODO 自定义菜单权没有开放,暂不处理该类消息
  75. }
  76. }
  77. textMessage.setContent(respContent);
  78. respMessage = MessageUtil.textMessageToXml(textMessage);
  79. } catch (Exception e) {
  80. e.printStackTrace();
  81. }
  82. return respMessage;
  83. }
  84. }

代码说明:

1)第29行:调用消息工具类MessageUtil解析微信发来的xml格式的消息,解析的结果放在HashMap里;

2)32~36行:从HashMap中取出消息中的字段;

3)39-44、84行:组装要返回的文本消息对象;

4)47~82行:演示了如何接收微信发送的各类型的消息,根据MsgType判断属于哪种类型的消息;

5)85行:调用消息工具类MessageUtil将要返回的文本消息对象TextMessage转化成xml格式的字符串;

关于事件推送(关注、取消关注、菜单点击)

对于消息类型的判断,像文本消息、图片消息、地理位置消息、链接消息和语音消息都比较好理解,有很多刚接触的朋友搞不懂事件推送消息有什么用,或者不清楚该如何判断用户关注的消息。那我们就专门来看下事件推送,下图是官方消息接口文档中关于事件推送的说明:

这里我们只要关心两个参数:MsgType和Event。当MsgType=event时,就表示这是一条事件推送消息;而Event表示事件类型,包括订阅、取消订阅和自定义菜单点击事件。也就是说,无论用户是关注了公众帐号、取消对公众帐号的关注,还是在使用公众帐号的菜单,微信服务器都会发送一条MsgType=event的消息给我们,而至于具体这条消息表示关注、取消关注,还是菜单的点击事件,就需要通过Event的值来判断了。(注意区分Event和event)

连载五篇教程总结

经过5篇的讲解,已经把开发模式启用,接口配置,消息相关工具类的封装,消息的接收与响应全部讲解完了,而且贴上了完整的源代码,相信有一定Java基础的朋友可以看的明白,能够通过系列文章基本掌握微信公众平台开发的相关技术知识。下面我把目前项目的完整结构贴出,方便大家对照:

时间: 2024-12-28 21:05:40

第三篇之消息的收发的相关文章

我们一起学习WCF 第三篇头消息验证用户身份

前言:今天我主要写的是关于头消息的一个用处验证用户信息 下面我画一个图,可以先看图 第一步:我们先开始做用户请求代码 首先:创建一个可执行的上下文对象块并定义内部传输的通道 using (OperationContextScope scope = new OperationContextScope(userClient.InnerChannel)) 然后:创建头消息 要发送的SOAP传输的内容 MessageHeader myHeaderUid = MessageHeader.CreateHea

SaltStack 入门到精通第三篇:Salt-Minion配置文件详解

SaltStack 入门到精通第三篇:Salt-Minion配置文件详解 作者:ArlenJ  发布日期:2014-06-09 17:52:16 ##### 主要配置设置 ##### 配置 默认值 说明 例子 default_include minion.d/*.conf master可以从其他文件读取配置,默认情况下master将自动的将master.d/*.conf中的配置读取出来并应用,其中master.d目录是相对存在于主配置文件所在的目录 default_include: minion

Android多线程编程之Handler篇(消息机制)

Android多线程编程之Handler篇(消息机制) Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑. MessageQueue 消息队列,以队列的形式(实为单链表结构)对外提供插入和删除的工作, Looper 以无限循环的形式不断获取MessageQueue中的消息,有则处理,无则等待. ThreadLocal ThreadLocal可以在不同的线程互不干扰的存储并提供数据,通过ThreadLocal可以很

第三篇——第二部分——第三文 配置SQL Server镜像——域环境

原文:第三篇--第二部分--第三文 配置SQL Server镜像--域环境 原文出处:http://blog.csdn.net/dba_huangzj/article/details/28904503 本文将演示如何在域环境下部署镜像,在域中部署相对来说简单很多,但是很多企业并不真正使用域来管理服务器(本人所在的公司就是其一),所以有必要演示非域环境,并且重点放在非域环境下.但是作为实践经验和最佳建议,强烈使用域环境管理.非域环境将在第四文中演示:http://blog.csdn.net/dba

第三篇——第二部分——第六文 监控SQL Server镜像

原文:第三篇--第二部分--第六文 监控SQL Server镜像 原文出处:http://blog.csdn.net/dba_huangzj/article/details/26846203 要优化,首先要监控,看看是否有性能问题,如果有,在哪里.才能开始真正的优化,所以本文以监控为入口,在上一篇已经略微提供了一些监控方面的信息 针对监控部分,本文将介绍以下内容: 监控组件 警告阈值 数据库镜像监视器 关于镜像的系统存储过程 性能计数器 1.1. 监控组件: 数据库镜像状态表: 数据库镜像状态存

三:JMS消息服务规范

一:JMS是什么?--->JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API--->用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信.--->Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持.---> JMS 使您能够通过消息收发服务(有时称为消息中介程序或路由器)从一个 JMS 客户机向另一个 JMS客户机发送消息.--->JMS(Java

设计模式就该这么学:以微信订阅号来讲观察者模式(第三篇)

前言:继续<设计模式就该这么学>系列文章,今天以当前比较火的微信订阅号给大家介绍应用得比较多的一种设计模式--观察者模式,之后再来介绍java拉模型方式的内置设计模式实现,最后附带一个项目实际观察者应用的例子! <设计模式就该这么学>系列文章: 设计模式就该这么学:为什么要学设计模式?(开篇漫谈) 设计模式就该这么学:要走心才能遵循设计模式五大原则(第二篇) 设计模式就该这么学:以微信订阅号来讲观察者模式(第三篇) 观察者模式实际应用:监听线程,意外退出线程后自动重启 一. 什么是

EnjoyingSoft之Mule ESB基础系列第三篇:Mule message structure - Mule message结构

目录 1. 探索Mule Message结构 2. Mule Message的Payload 3. Mule Message的Property 4. Mule Message的Attachment 5. Mule的Variable 6. 使用Java操作Mule Message Mule ESB是一个使用Java语言编写的开源企业服务总线,企业服务总线英文Enterprise Service Bus,简称ESB.其相关源代码也托管在GitHub上,可以在https://github.com/mu

Storm系列三: Storm消息可靠性保障

Storm系列三: Storm消息可靠性保障 在上一篇 Storm系列二: Storm拓扑设计 中我们已经设计了一个稍微复杂一点的拓扑. 而本篇就是在上一篇的基础上再做出一定的调整. 在这里先大概提一下上一篇的业务逻辑, 我们会不断收到来自前端的消息,消息包含消息的发送时间,消息内容,结束标识, 消息的发送者, SessionId等其他信息, 我们需要做的事情是当接收到消息之后,根据SessionId判断是否属于同一消息, 如果是的话将内容拼接, 如果结束标识为 true, 表示会话已结束,则存