接入微信公众平台开发之用户关注(取消)事件触发后台自定义消息体通知给用户的实现过程
1.需求:用户关注公众号后回复给用户一个字符串,字符串不能重复使用即如果a用户关注公众号后商户后台回复给用户字符串str1后,b用户关注就是其他字符串,且a用户取消关注再次关注不回复消息体
2.实现过程:
①首先配置服务器url并开启,再次过程中需要微信后台与商户后台进行通信,所以,微信后台会发送请求,商户平台自定义接口回复相关内容即可完成通信。
②原理图:
③代码实现:
a.pcodecontroller:定义的一个接口类,用来处理微信服务器发送的请求
1 package com.java.zxf.controller; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.io.PrintWriter; 7 import java.io.UnsupportedEncodingException; 8 import java.util.HashMap; 9 import java.util.List; 10 import java.util.Map; 11 import javax.servlet.ServletInputStream; 12 import javax.servlet.ServletOutputStream; 13 import javax.servlet.http.HttpServletRequest; 14 import javax.servlet.http.HttpServletResponse; 15 import org.apache.log4j.Logger; 16 import org.dom4j.Document; 17 import org.dom4j.Element; 18 import org.dom4j.io.SAXReader; 19 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.stereotype.Controller; 21 import org.springframework.web.bind.annotation.RequestMapping; 22 import org.springframework.web.bind.annotation.ResponseBody; 23 import weixin.popular.bean.xmlmessage.XMLMessage; 24 import weixin.popular.bean.xmlmessage.XMLTextMessage; 25 import weixin.popular.support.ExpireKey; 26 import weixin.popular.support.expirekey.DefaultExpireKey; 27 import com.easytouch.util.MyCheck; 28 import com.java.zxf.dao.Pcodedao; 29 import com.java.zxf.domain.pcode; 30 31 @Controller 32 public class PcodeController { 33 34 @Autowired 35 private Pcodedao pcodedao; 36 private Logger log = Logger.getLogger(getClass()); 37 38 @RequestMapping("/getbyid") 39 @ResponseBody 40 public Map<String, Object> getbyid(HttpServletRequest request,int id){ 41 pcode code = pcodedao.getcodebyid(id); 42 Map<String, Object> map = new HashMap<String, Object>(); 43 map.put("code", code); 44 return map; 45 } 46 47 //重复通知过滤 48 private static ExpireKey expireKey = new DefaultExpireKey(); 49 50 51 //微信推送事件 url 52 @RequestMapping("/openwx/getticket") 53 public void getTicket(HttpServletRequest request, HttpServletResponse response) 54 throws Exception { 55 ServletInputStream inputStream = request.getInputStream(); 56 ServletOutputStream outputStream = response.getOutputStream(); String signature = request.getParameter("signature"); 57 String timestamp = request.getParameter("timestamp"); 58 String nonce = request.getParameter("nonce"); 59 String echostr = request.getParameter("echostr"); 60 61 //首次请求申请验证,返回echostr 62 if(echostr!=null){ 63 outputStreamWrite(outputStream,echostr); 64 return; 65 } 66 67 //验证请求签名 68 if(!MyCheck.checkSignature(signature, timestamp, nonce)){ 69 System.out.println("The request signature is invalid"); 70 return; 71 } 72 73 boolean isreturn= false; 74 //loger.info("1.收到微信服务器消息"); 75 Map<String, String> wxdata=parseXml(request); 76 if(wxdata.get("MsgType")!=null){ 77 if("event".equals(wxdata.get("MsgType"))){ 78 //loger.info("2.1解析消息内容为:事件推送"); 79 if( "subscribe".equals(wxdata.get("Event"))){ 80 //loger.info("2.2用户第一次关注 返回true哦"); 81 isreturn=true; 82 } 83 } 84 } 85 86 if(isreturn == true){ 87 String openid = wxdata.get("FromUserName"); 88 String tosend = "抱歉,提货码已用完"; 89 String key = wxdata.get("FromUserName")+ "__" 90 + wxdata.get("ToUserName")+ "__" 91 + wxdata.get("MsgId") + "__" 92 + wxdata.get("CreateTime"); 93 if(expireKey.exists(key)){ 94 //重复通知不作处理 95 //loger.info("3.1 重复通知了"); 96 return; 97 }else{ 98 //loger.info("3.1 第一次通知"); 99 //转换XML 100 //loger.info("3.0 进入回复 转换对象:"+key); 101 pcode temp = pcodedao.getbyopenid(openid); 102 if (temp==null){ 103 List<pcode> pcodelist = pcodedao.getAllcode(); 104 try{ 105 pcode code = pcodelist.get(0); 106 tosend = "您的提货码为:"+code.getPickupcode(); 107 int flag = pcodedao.update(code.getId(),openid); 108 if(flag==1){ 109 System.out.println("更新成功,取货码已使用"); 110 }else{ 111 log.error("更新用户openid失败,取货码未能使用"); 112 } 113 }catch(Exception e){ 114 System.out.println("取货码已经用完"); 115 log.info("取货码已经用完"); 116 } 117 //loger.info("3.2 回复你好"); 118 //创建回复 119 XMLMessage xmlTextMessage = new XMLTextMessage( 120 wxdata.get("FromUserName"), 121 wxdata.get("ToUserName"), 122 tosend); 123 expireKey.add(key); 124 //回复 125 xmlTextMessage.outputStreamWrite(outputStream); 126 return; 127 } 128 } 129 } 130 //loger.info("3.2 回复空"); 131 outputStreamWrite(outputStream,""); 132 } 133 134 /** 135 * 数据流输出 136 * @param outputStream 137 * @param text 138 * @return 139 */ 140 private boolean outputStreamWrite(OutputStream outputStream, String text){ 141 try { 142 outputStream.write(text.getBytes("utf-8")); 143 } catch (UnsupportedEncodingException e) { 144 // TODO Auto-generated catch block 145 e.printStackTrace(); 146 return false; 147 } catch (IOException e) { 148 // TODO Auto-generated catch block 149 e.printStackTrace(); 150 return false; 151 } 152 return true; 153 } 154 155 /** 156 * dom4j 解析 xml 转换为 map 157 * @param request 158 * @return 159 * @throws Exception 160 */ 161 public static Map<String, String> parseXml(HttpServletRequest request) throws Exception { 162 // 将解析结果存储在HashMap中 163 Map<String, String> map = new HashMap<String, String>(); 164 // 从request中取得输入流 165 InputStream inputStream = request.getInputStream(); 166 // 读取输入流 167 SAXReader reader = new SAXReader(); 168 Document document = reader.read(inputStream); 169 // 得到xml根元素 170 Element root = document.getRootElement(); 171 // 得到根元素的所有子节点 172 List<Element> elementList = root.elements(); 173 174 // 遍历所有子节点 175 for (Element e : elementList) 176 map.put(e.getName(), e.getText()); 177 178 // 释放资源 179 inputStream.close(); 180 inputStream = null; 181 return map; 182 } 183 184 /** 185 * 回复微信服务器"文本消息" 186 * @param response 187 * @param returnvaleue 188 */ 189 public void output(HttpServletResponse response, String returnvaleue) { 190 try { 191 PrintWriter pw = response.getWriter(); 192 pw.write(returnvaleue); 193 pw.flush(); 194 } catch (IOException e) { 195 e.printStackTrace(); 196 } 197 } 198 }
b.pcodedao:商户后台应用-数据层;定义的读写数据的类
1 package com.java.zxf.dao; 2 3 import java.util.List; 4 import org.apache.ibatis.annotations.Param; 5 import org.apache.ibatis.annotations.Select; 6 import org.apache.ibatis.annotations.Update; 7 import org.springframework.stereotype.Repository; 8 9 import com.java.zxf.domain.pcode; 10 @Repository 11 public interface Pcodedao { 12 @Select("select * from pcode where id=#{id}") 13 public pcode getcodebyid(int id); 14 15 @Select("select * from pcode where openid is null or openid=''") 16 public List<pcode> getAllcode(); 17 18 @Select("select * from pcode where openid=#{openid}") 19 public pcode getbyopenid(String openid); 20 21 @Update("update pcode set openid=#{openid} where id=#{id}") 22 public int update(@Param(value="id")int id,@Param(value="openid")String openid); 23 }
c.pom.xml中添加的依赖包
<dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>com.github.liyiorg</groupId> <artifactId>weixin-popular</artifactId> <version>2.8.24</version> </dependency>
三.总结:微信公众平台提供了包括关注动作,被动回复消息在内的一系列动作,具体见如下链接::https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140454