微信消息接收事件-将微信接收消息转发到指定服务器的servlet处理
场景:团队开放微信第三方公众号,此公众号中原先有一个活动,按照正常流程公众号配置指定接收消息事件的url,服务器端指定servlet进行xml解析处理。
现在原先基础上增加一个活动,此时为开放第三方公众号,里面有两个活动暂且称为A和B,A原先由Fa服务器指定的servlet处理微信推过来的事件(比如说关注事件),A和B有不同的服务器,独立的项目,不同的数据库。此时需求是根据场景的不同,将微信推送过来的消息分别放在不同的servlet里面进行解析处理。但实际上微信只往其中一个servlet中进行消息推送。
过程:使用转发就可以不用考虑了,转发只能在同一web中的servlet中进行跳转。如果场景是在同一个tomcat中,那么可以用request.getRequestDispatcher("/xxxx").forward(request,response);
如果消息事件只涉及到消息推送等,也就是只用到了微信推送xml里面的数据,那么上述场景完全可以在同一个servlet中进行处理,处理的方法就是根据不同的场景值。
具体的思路过程就不细说了,大体方向:在微信推送过来xml的时候就把xml给转到指定的服务器下面的servlet中; 在进入到特定场景的时候把得到的数据转到知道的服务器下面的servlet中;
结果:测试了各种方法百度了各种方法之后,我这里用了java后端发送post请求:
这里以微信第三方平台开发为例:
微信推送过来的消息为(部分代码):
1 /** 2 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 3 * response) 4 */ 5 protected void doPost(HttpServletRequest request, HttpServletResponse response) 6 throws ServletException, IOException { 7 DebugUtils.savaDebugInfo(null, "进入到servlet种的dePost",null); 8 String nonce = request.getParameter("nonce"); 9 String timestamp = request.getParameter("timestamp"); 10 String msgSignature = request.getParameter("msg_signature"); 11 12 request.setCharacterEncoding("UTF-8"); 13 response.setCharacterEncoding("UTF-8"); 14 PrintWriter out = response.getWriter(); 15 String message = "success"; 16 try { 17 StringBuilder sb = new StringBuilder(); 18 BufferedReader in = request.getReader(); 19 String line; 20 while ((line = in.readLine()) != null) { 21 sb.append(line); 22 } 23 String xml = sb.toString();
收到消息后要对xml进行解析,微信官方文档给的有解析的方法。解析之后根据解析出来的数据判断不同的场景走不同的出来方法。
现在我要在微信推送过来消息进入doPost方法的时候同时把消息发送到其他指定的服务器下面servlet中去。
首先到指定服务器下,找到WEB-INF下面的xml文件进行servlet访问配置:
1 <servlet> 2 <servlet-name>OpenWXMessageServlet</servlet-name> 3 <servlet-class> 4 xx.xx.xx.MessageServlet 5 </servlet-class> 6 </servlet> 7 <servlet-mapping> 8 <servlet-name>OpenWXMessageServlet</servlet-name> 9 <url-pattern>/OpenWXMessageServlet</url-pattern> 10 </servlet-mapping>
然后再接收到消息事件读取到未解密的xml的时候去发送post请求:
1 /** 2 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 3 * response) 4 */ 5 protected void doPost(HttpServletRequest request, HttpServletResponse response) 6 throws ServletException, IOException { 7 DebugUtils.savaDebugInfo(null, "进入到servlet种的dePost",null); 8 String nonce = request.getParameter("nonce"); 9 String timestamp = request.getParameter("timestamp"); 10 String msgSignature = request.getParameter("msg_signature"); 11 12 request.setCharacterEncoding("UTF-8"); 13 response.setCharacterEncoding("UTF-8"); 14 PrintWriter out = response.getWriter(); 15 String message = "success"; 16 try { 17 StringBuilder sb = new StringBuilder(); 18 BufferedReader in = request.getReader(); 19 String line; 20 while ((line = in.readLine()) != null) { 21 sb.append(line); 22 } 23 String xml = sb.toString(); 24 String path = "http://xxxxxx.com/OpenWXMessageServlet?nonce=" 25 +nonce+"×tamp="+timestamp+"&msg_signature="+msgSignature; 26 String echostr = HttpRequest.sendPost(path, xml);
然后指定服务器接收到的时间戳和随机数都是再一致状态下的了。这样就实现了开始场景的需求。
附带一下我这边的sendPost方法:
1 /** 2 * 向指定 URL 发送POST方法的请求 3 * 4 * @param url 5 * 发送请求的 URL 6 * @param param 7 * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 8 * @return 所代表远程资源的响应结果 9 */ 10 public static String sendPost(String url, String param) { 11 return sendPost(url, param, ""); 12 } 13 public static String sendPost(String url, String param, String charset) { 14 PrintWriter out = null; 15 BufferedReader in = null; 16 String result = ""; 17 InterfaceInfo interfaceInfo = new InterfaceInfo(url, param, ""); 18 19 try { 20 URL realUrl = new URL(url); 21 // 打开和URL之间的连接 22 URLConnection conn = realUrl.openConnection(); 23 // 设置通用的请求属性 24 conn.setConnectTimeout(60000); 25 conn.setReadTimeout(60000); 26 conn.setRequestProperty("accept", "application/Json;" + charset); 27 conn.setRequestProperty("connection", "Keep-Alive"); 28 conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); 29 conn.setRequestProperty("Content-Type", "application/Json;charset=UTF-8;"); 30 // 地址接口用到x-auth-header 31 if (param.contains("AddressReq")) { 32 conn.setRequestProperty("X-AUTH-HEADER", "ACAE705AF0531007BDCBC29D5121DBD6"); 33 } 34 // 铂涛锦江mpls通道必须加验证 35 if(url.contains("/v1/score/pay")){ 36 conn.setRequestProperty("apigwkey", "d72fa68d5734bb66b4b27d9b5dd50f65"); 37 } 38 // 发送POST请求必须设置如下两行 39 conn.setDoOutput(true); 40 conn.setDoInput(true); 41 // 获取URLConnection对象对应的输出流 42 out = new PrintWriter(conn.getOutputStream()); 43 // 发送请求参数 44 out.print(param); 45 // flush输出流的缓冲 46 out.flush(); 47 // 定义BufferedReader输入流来读取URL的响应 48 in = new BufferedReader(new InputStreamReader(conn.getInputStream())); 49 String line; 50 while ((line = in.readLine()) != null) { 51 result += line; 52 } 53 if (StringUtils.isBlank(result)) { 54 GetServiceUtil.getExceptionLogService().saveDebugInfo("扣分返回", "result等于空字符串"); 55 } 56 // 请求结束更新开始时保存的接口日志 57 String resultInterface = ""; 58 if (result.length() > 1000) { 59 resultInterface = result.substring(0, 1000); 60 } else { 61 resultInterface = result; 62 } 63 interfaceInfo.setRESULT(resultInterface); 64 } catch (Exception e) { 65 interfaceInfo.setRESULT(e.getMessage()); 66 67 ExceptionLog exceptionLog = new ExceptionLog(); 68 exceptionLog.setExceptiontype(ConstantData.EXCEPTION_TYPE_RUNTIME); 69 exceptionLog.setExceptiontitle("Http异常"); 70 exceptionLog.setExceptionmsg(url); 71 if (e.toString().length() > 500) { 72 exceptionLog.setStack(e.toString().substring(0, 500)); 73 } else { 74 exceptionLog.setStack(e.toString()); 75 } 76 ExceptionServiceImpl exceptionService = GetServiceUtil.getExceptionService(); 77 exceptionService.insertExceptionLogInfo(exceptionLog); 78 79 if (e.toString().contains("401")) { 80 result = e.toString(); 81 } else { 82 result = "服务器异常。。"; 83 } 84 } 85 // 使用finally块来关闭输出流、输入流 86 finally { 87 try { 88 GetServiceUtil.getExceptionLogService().saveInterfaceInfo(interfaceInfo); 89 if (out != null) { 90 out.close(); 91 } 92 if (in != null) { 93 in.close(); 94 } 95 } catch (IOException ex) { 96 ex.printStackTrace(); 97 } 98 } 99 return result; 100 }