4.4.4 使用CoreServlet类完成消息的接收与响应

接下来,在CoreServlet类的doPost()方法中完成消息的接收与响应。CoreServlet类的完整代码如下。

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

从代码中可以看出,doPost()方法的实现可以分为编码设置、请求校验、请求处理和响应消息4个部分,说明如下。

1.编码设置

50~51行代码用于编码设置。微信服务器向公众账号服务器POST(发送)消息时采用的是UTF-8编码,因此在doPost()方法的最开始处需要将请求、响应的字符集编码方式统一设置为UTF-8,否则可能会遇到中文乱码问题。

2.请求校验

第60行代码用于请求校验。为了防止他人向公众账号服务器发送恶意请求,需要对每个消息请求进行合法性验证。微信服务器向公众账号服务器POST消息时,也会在URL后面追加4个参数signature、timestamp、nonce和echostr,仍然是通过校验签名判断消息的真实性,这里的校验方式与第3章中介绍的完全一致。

3.请求处理

第62行代码用于请求处理。我们并没有将请求处理代码直接写在doPost()方法中,而是将这部分代码封装在CoreService类中,这样做能够在一定程度上实现解耦。CoreServlet类不用关心具体的业务处理逻辑,而是完全交由核心服务类CoreService处理。CoreService类的处理结果respXml是一个XML格式的消息。

4.响应消息

第63行代码用于响应消息。通过调用PrintWriter类的print()方法将处理结果respXml返回给微信服务器。微信服务器在收到消息后,会通过公众账号将消息发送给用户。