微信开发(5):公众号消息与事件推送处理(转)

1.0 开发背景
外包公司,所以各种各样的项目都有接触,有个需求,客户要做不同的二维码,通过二维码关注以后,给用户发送不同的消息,顺便统计用户来源,
本文用到了 微信带参数二维码接口和消息管理里的相关接口
注意 :在微信公众号后台,设置了服务器配置 URL 并启用后,会导致 微信后台设置的回复规则,以及底部菜单都全部失效!直接清空了!因为这时候 微信已经把公众号消息和事件 推送给开发者配置的url中,让开发者进行处理了。
本文先讲述微信官方后台设置带参二维码,后续更新使用第三方平台开发实现这个功能,从而保证了用户微信公众号官方设置底部菜单以及自定义回复没有失效!

2.0 开发准备
2.1老样子 官方文档 来一波 带参二维码 接收事件
2.2 需要在微信后台 配置服务器配置 ,微信会在你修改这个配置的时候 给你填写的URL发送数据,需要提前把项目上传服务器

这个东西 配置好之后 可以点击开启了 ,开启后啊,这个微信会把所有用户发送的信息,给转发给填写的url 上。开发者必须在五秒内回复微信服务器。否则 微信会进行三次重试,重试均失败后,会给用户提示 该公众号暂时无法提供服务。 而且在公众平台还有告警通知。

下面看代码

  1 package com.ysh.wxtest.controller;
  2 
  3 import org.apache.log4j.Logger;
  4 import org.dom4j.Document;
  5 import org.dom4j.Element;
  6 import org.dom4j.io.SAXReader;
  7 import org.springframework.beans.factory.annotation.Autowired;
  8 import org.springframework.stereotype.Controller;
  9 import org.springframework.web.bind.annotation.RequestMapping;
 10 import weixin.popular.bean.xmlmessage.XMLMessage;
 11 import weixin.popular.bean.xmlmessage.XMLTextMessage;
 12 import weixin.popular.support.ExpireKey;
 13 import weixin.popular.support.expirekey.DefaultExpireKey;
 14 import weixin.popular.util.SignatureUtil;
 15 
 16 import javax.servlet.ServletInputStream;
 17 import javax.servlet.ServletOutputStream;
 18 import javax.servlet.http.HttpServletRequest;
 19 import javax.servlet.http.HttpServletResponse;
 20 import java.io.*;
 21 import java.util.HashMap;
 22 import java.util.List;
 23 import java.util.Map;
 24 
 25 /**
 26  * 消息接收控制层
 27  * @author YaoShiHang
 28  * @Date 15:15 2017-10-16
 29  */
 30 @Controller
 31 public class WxqrcodeController {
 32 
 33     private final String TOKEN="xxxxxxxxxx";                      //Wx 开发者设置的 token
 34     private Logger loger = Logger.getLogger(getClass());
 35     //重复通知过滤
 36     private static ExpireKey expireKey = new DefaultExpireKey();
 37 
 38 
 39     //微信推送事件 url
 40     @RequestMapping("/openwx/getticket")
 41     public void getTicket(HttpServletRequest request, HttpServletResponse response)
 42             throws Exception {
 43         ServletInputStream inputStream = request.getInputStream();
 44         ServletOutputStream outputStream = response.getOutputStream(); String signature = request.getParameter("signature");
 45         String timestamp = request.getParameter("timestamp");
 46         String nonce = request.getParameter("nonce");
 47         String echostr = request.getParameter("echostr");
 48 
 49         //首次请求申请验证,返回echostr
 50         if(echostr!=null){
 51             outputStreamWrite(outputStream,echostr);
 52             return;
 53         }
 54 
 55         //验证请求签名
 56         if(!signature.equals(SignatureUtil.generateEventMessageSignature(TOKEN,timestamp,nonce))){
 57             System.out.println("The request signature is invalid");
 58             return;
 59         }
 60 
 61         boolean isreturn= false;
 62         loger.info("1.收到微信服务器消息");
 63         Map<String, String> wxdata=parseXml(request);
 64         if(wxdata.get("MsgType")!=null){
 65             if("event".equals(wxdata.get("MsgType"))){
 66                 loger.info("2.1解析消息内容为:事件推送");
 67                 if( "subscribe".equals(wxdata.get("Event"))){
 68                     loger.info("2.2用户第一次关注 返回true哦");
 69                     isreturn=true;
 70                 }
 71             }
 72         }
 73 
 74         if(isreturn == true){
 75             //转换XML
 76             String key = wxdata.get("FromUserName")+ "__"
 77                     + wxdata.get("ToUserName")+ "__"
 78                     + wxdata.get("MsgId") + "__"
 79                     + wxdata.get("CreateTime");
 80             loger.info("3.0 进入回复 转换对象:"+key);
 81 
 82             if(expireKey.exists(key)){
 83                 //重复通知不作处理
 84                 loger.info("3.1  重复通知了");
 85                 return;
 86             }else{
 87                 loger.info("3.1  第一次通知");
 88                 expireKey.add(key);
 89             }
 90 
 91             loger.info("3.2  回复你好");
 92             //创建回复
 93             XMLMessage xmlTextMessage = new XMLTextMessage(
 94                     wxdata.get("FromUserName"),
 95                     wxdata.get("ToUserName"),
 96                     "你好");
 97             //回复
 98             xmlTextMessage.outputStreamWrite(outputStream);
 99             return;
100         }
101         loger.info("3.2  回复空");
102         outputStreamWrite(outputStream,"");
103     }
104 
105     /**
106      * 数据流输出
107      * @param outputStream
108      * @param text
109      * @return
110      */
111     private boolean outputStreamWrite(OutputStream outputStream, String text){
112         try {
113             outputStream.write(text.getBytes("utf-8"));
114         } catch (UnsupportedEncodingException e) {
115             // TODO Auto-generated catch block
116             e.printStackTrace();
117             return false;
118         } catch (IOException e) {
119             // TODO Auto-generated catch block
120             e.printStackTrace();
121             return false;
122         }
123         return true;
124     }
125 
126     /**
127      * dom4j 解析 xml 转换为 map
128      * @param request
129      * @return
130      * @throws Exception
131      */
132     public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
133         // 将解析结果存储在HashMap中
134         Map<String, String> map = new HashMap<String, String>();
135         // 从request中取得输入流
136         InputStream inputStream = request.getInputStream();
137         // 读取输入流
138         SAXReader reader = new SAXReader();
139         Document document = reader.read(inputStream);
140         // 得到xml根元素
141         Element root = document.getRootElement();
142         // 得到根元素的所有子节点
143         List<Element> elementList = root.elements();
144 
145         // 遍历所有子节点
146         for (Element e : elementList)
147             map.put(e.getName(), e.getText());
148 
149         // 释放资源
150         inputStream.close();
151         inputStream = null;
152         return map;
153     }
154 
155     /**
156      * 回复微信服务器"文本消息"
157      * @param response
158      * @param returnvaleue
159      */
160     public void output(HttpServletResponse response, String returnvaleue) {
161         try {
162             PrintWriter pw = response.getWriter();
163             pw.write(returnvaleue);
164             loger.info("****************return valeue***************="+returnvaleue);
165             pw.flush();
166         } catch (IOException e) {
167             e.printStackTrace();
168         }
169     }
170 }

提供一个大神的帮助类

 1 package weixin.popular.bean.xmlmessage;
 2 
 3 import java.io.IOException;
 4 import java.io.OutputStream;
 5 import java.io.UnsupportedEncodingException;
 6 import java.util.UUID;
 7 
 8 import com.qq.weixin.mp.aes.AesException;
 9 import com.qq.weixin.mp.aes.WXBizMsgCrypt;
10 
11 import weixin.popular.bean.message.message.Message;
12 
13 public abstract class XMLMessage {
14 
15     protected String toUserName;
16     protected String fromUserName;
17     protected String msgType;
18 
19     protected XMLMessage(String toUserName, String fromUserName, String msgType) {
20         super();
21         this.toUserName = toUserName;
22         this.fromUserName = fromUserName;
23         this.msgType = msgType;
24     }
25 
26     /**
27      * 子类自定义XML
28      * @return XML
29      */
30     public abstract String subXML();
31 
32     /**
33      * 转换为  Message 对象
34      * @return Message
35      */
36     public abstract Message convert();
37 
38     public String toXML(){
39         StringBuilder sb = new StringBuilder();
40         sb.append("<xml>");
41         sb.append("<ToUserName><![CDATA["+toUserName+"]]></ToUserName>");
42         sb.append("<FromUserName><![CDATA["+fromUserName+"]]></FromUserName>");
43         sb.append("<CreateTime>"+System.currentTimeMillis()/1000+"</CreateTime>");
44         sb.append("<MsgType><![CDATA["+msgType+"]]></MsgType>");
45         sb.append(subXML());
46         sb.append("</xml>");
47         return sb.toString();
48     }
49 
50     public boolean outputStreamWrite(OutputStream outputStream){
51         try {
52             outputStream.write(toXML().getBytes("utf-8"));
53             outputStream.flush();
54         } catch (UnsupportedEncodingException e) {
55             e.printStackTrace();
56             return false;
57         } catch (IOException e) {
58             e.printStackTrace();
59             return false;
60         }
61         return true;
62     }
63 
64     public boolean outputStreamWrite(OutputStream outputStream,WXBizMsgCrypt bizMsgCrypt){
65         if(bizMsgCrypt != null){
66             try {
67                 String outputStr = bizMsgCrypt.encryptMsg(toXML(), System.currentTimeMillis()+"",UUID.randomUUID().toString());
68                 outputStream.write(outputStr.getBytes("utf-8"));
69                 outputStream.flush();
70             } catch (UnsupportedEncodingException e) {
71                 e.printStackTrace();
72                 return false;
73             } catch (IOException e) {
74                 e.printStackTrace();
75                 return false;
76             } catch (AesException e) {
77                 e.printStackTrace();
78                 return false;
79             }
80             return true;
81         }else{
82             return outputStreamWrite(outputStream);
83         }
84     }
85 
86     public String getToUserName() {
87         return toUserName;
88     }
89 
90     public String getFromUserName() {
91         return fromUserName;
92     }
93 
94     public String getMsgType() {
95         return msgType;
96     }
97 
98 
99 }

 

posted @ 2019-02-01 11:33  haw2106  阅读(3280)  评论(0编辑  收藏  举报