微信官方文档地址:关注/取消关注事件 | 微信开放文档

以上,文档提到:用户在关注与取消关注公众号时,微信会把这个事件推送到开发者填写的URL,接下来我们就来看看这个URL怎么配置。

【配置步骤】:

1、微信公众号后台:设置与开发 》基本配置 》服务器配置,点击"修改配置"按钮;

URL:是我们用来接收微信消息和事件通知的接口地址(下面会提供代码说明);

Token:随便给个3~32位的数字+英文就好(如:o3MAytzQ0aZ0yB01BzzDG5f&j5gs),这个用作生成签名(该 Token 会和接口 URL 中包含的 Token 进行比对,从而验证安全性)。EncodingAESKey:用作消息体加解密密钥,这个点下随机生成就好,如果下面的“消息加解密方式”非安全模式,用不到。

【重要】

提醒下小伙伴们哦,启用服务器配置,会影响到你之前公众号设置的自定义菜单!!!

启用成功,微信会失效掉你之前配置的自定义菜单,要求你通过接口来生成公众号菜单。

好了,继续我们正文(生成菜单,代码我再另一篇文章附码)~

在配置以上服务器配置的时候,URL哪来?Token怎么用?

(上面消息加解密方式我先用:兼用模式,EncodingAESKey参数就用不上了哈)。

URL我配置的是:https://www.域名.com/wechat/reply/(URL最后的斜杠大伙看代码就知道了)

下面,直接上代码:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** 微信事件通知 - 控制层*/
@RestController
@RequestMapping(value = "/wechat/reply")
public class AutoReplyController {private Logger LOGGER = LoggerFactory.getLogger(AutoReplyController.class);@Value("${wechat.appId}")private String wechatAppId;@Value("${wechat.appSecret}")private String wechatAppSecret;// 这个Token就是微信后台 服务器配置 中的Token@Value("${wechat.token}")private String wechatToken;/*** 服务器校验* @param req 请求* @return 校验结果*/@GetMapping("/")public String verification(HttpServletRequest req) {return WechatEventUtil.verification(req, wechatToken);}/*** 消息事件* @param req 请求* @return 结果*/@PostMapping("/")public void messageEvent(HttpServletRequest req, HttpServletResponse resp) throws IOException {req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");String message = "success";PrintWriter out = resp.getWriter();try {String messageEvent = WechatMessageUtil.messageEvent(req);if(messageEvent != null) {message = messageEvent;}} catch (Exception e) {e.printStackTrace();} finally {LOGGER.info("消息事件:"+message);out.write(message);if (out != null) {out.close();}}}
}

从以上代码,我们可以看出,提供了一个Get请求和一个Post请求:

1、Get请求:用于你在微信公众号后台,修改配置 和 启用 “服务器配置” 的时候,验证服务安全性(简单讲就是微信会通过这个地址拿你刚刚设置的Token和你代码里的Token对比)

2、Post请求:后续,微信监控到用户的特定操作,然后通过这个接口通知到你,支持以下事件。

【WechatMessageUtil】:这里我做了个关注自动回复一条图文消息,如果大家没有这个需求直接忽略,Controller层直接返回一个success字符串就行。

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;/*** <pre>* 微信消息工具类:事件通知、自动回复、* </pre>** @author shenshao*/
public class WechatEventUtil {private static Logger log = LoggerFactory.getLogger(WechatEventUtil.class);/*** 公众号《事件通知》服务器校验** @param req 请求* @return 校验结果*/public static String verification(HttpServletRequest req, String wechatToken) {// 接收微信服务器发送请求时传递过来的参数String signature = req.getParameter("signature");String timestamp = req.getParameter("timestamp");String nonce = req.getParameter("nonce");// 将token、timestamp、nonce三个参数进行字典序排序,并拼接为一个字符串String sortStr = sort(wechatToken, timestamp, nonce);// 字符串进行shal加密String mySignature = shal(sortStr);// 校验微信服务器传递过来的签名 和  加密后的字符串是否一致, 若一致则签名通过if (!"".equals(signature) && !"".equals(mySignature) && signature.equals(mySignature)) {log.info("-----签名校验通过-----");return req.getParameter("echostr");} else {log.error("-----校验签名失败-----");return "";}}/*** 消息事件监控:关注、取消关注等事件* @param req* @return*/public static String messageEvent(HttpServletRequest req) {String result = null;Map<String, String> map = xmlToMap(req);String fromUserName = map.get("FromUserName");String toUserName = map.get("ToUserName");String msgType = map.get("MsgType");String content = map.get("Content");String eventType = map.get("Event");log.info("事件处理:event:{}、msgType:{}、toUserName:{}、fromUserName:{}", eventType, msgType, toUserName, fromUserName);if ("event".equals(msgType)) {if ("subscribe".equals(eventType)) {result = imgTextMsg(toUserName, fromUserName, "新用户注册", "仅限上海地区手机号用户", "图片地址", "点击后跳转的路径");log.info("新增关注事件:toUserName{}、fromUserName{}", toUserName, fromUserName);} else if ("unsubscribe".equals(eventType)) {log.info("取消关注事件:toUserName{}、fromUserName{}", toUserName, fromUserName);}}return result;}/*** 组装图文消息(懒得封装对象转XML方法,直接字符串拼装,大伙勿喷)* @param toUserName    开发者微信号* @param fromUserName  接收人openId* @param title         图文消息上的备注* @param description   图文消息上的备注* @param picUrl        图文消息上的图片* @param url           点击图文消息跳转的路径* @return*/public static String imgTextMsg(String toUserName, String fromUserName, String title, String description, String picUrl, String url){return "<xml>"+ "<ToUserName><![CDATA["+fromUserName+"]]></ToUserName>"+ "<FromUserName><![CDATA["+toUserName+"]]></FromUserName>"+ "<CreateTime>"+new Date().getTime()+"</CreateTime>"+ "<MsgType><![CDATA[news]]></MsgType>"+ "<ArticleCount>1</ArticleCount>"+ "<Articles>"+ "<item>"+ "<Title><![CDATA["+title+"]]></Title>"+ "<Description><![CDATA["+description+"]]></Description>"+ "<PicUrl><![CDATA["+picUrl+"]]></PicUrl>"+ "<Url><![CDATA["+url+"]]></Url>"+ "</item>"+ "</Articles>"+ "</xml>";}/*** 解析微信发来的请求(XML)** @param request 请求* @return map* @throws Exception 异常*/public static Map<String, String> xmlToMap(HttpServletRequest request) {// 将解析结果存储在HashMap中Map<String, String> map = new HashMap<>(16);// 从request中取得输入流try (InputStream inputStream = request.getInputStream()) {System.out.println("获取输入流");// 读取输入流SAXReader reader = new SAXReader();Document document = reader.read(inputStream);// 得到xml根元素Element root = document.getRootElement();// 得到根元素的所有子节点List<Element> elementList = root.elements();// 遍历所有子节点for (Element e : elementList) {System.out.println(e.getName() + " | " + e.getText());map.put(e.getName(), e.getText());}} catch (Exception e) {e.printStackTrace();}return map;}/*** 参数排序** @param token     服务器配置,自定义的Token* @param timestamp timestamp* @param nonce     nonce* @return 排序后拼接字符串*/public static String sort(String token, String timestamp, String nonce) {String[] strArray = {token, timestamp, nonce};Arrays.sort(strArray);StringBuilder sb = new StringBuilder();for (String str : strArray) {sb.append(str);}return sb.toString();}/*** 字符串进行shal加密** @param str 字符串* @return 密文*/public static String shal(String str) {try {MessageDigest digest = MessageDigest.getInstance("SHA-1");digest.update(str.getBytes());byte messageDigest[] = digest.digest();StringBuilder hexString = new StringBuilder();// 字节数组转换为 十六进制 数for (int i = 0; i < messageDigest.length; i++) {String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);if (shaHex.length() < 2) {hexString.append(0);}hexString.append(shaHex);}return hexString.toString();} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return "";}}

以上,程序完成,打包部署,然后就可以去微信后台点击启用了。最后啰嗦下:

1、程序里的Token用的是你服务器配置的Token,不是微信全局的唯一接口调用凭据Access token;

2、如果点击启用时有问题,先去浏览器看看自己写的Get接口有木有问题,能不能请求到;

3、上面重要提示讲到的自定义菜单,去看我另一篇文章,我把代码也放上去了。

【微信生成自定义菜单】:http://t.csdn.cn/n8Cqo

欢迎各位大佬指正,谢谢各位大佬~

Spring项目接入微信关注/取消关注事件监控(含代码demo,自动回复图文)相关推荐

  1. 微信公众号关注/取消关注事件推送开发记录

    一.奉上官方文档 关注/取消关注事件 | 微信开放文档微信开发者平台文档https://developers.weixin.qq.com/doc/offiaccount/Message_Managem ...

  2. 根据微信公众号关注/取消关注事件,获取用户信息

    第一步:微信公众平台->基本配置->服务器配置->配置接收地址 第二步:接收微信服务器推送过来的事件 微信文档地址: 关注/取消关注事件 用户在关注与取消关注公众号时,微信会把这个事 ...

  3. 微信公众号开发-----接送事件推送之关注/取消关注

    本文主要实现的功能包括 关注/取消关注事件 阅读本文之前请先认真阅读微信公众号技术文档之接受事件推送 需注意的是:验证消息的确来自微信服务器和接收事件时微信服务器都会发送请求到填写的服务器地址URL上 ...

  4. 微信 关注/取消关注事件

    <?php /*** wechat php test*/ //确定下你的token那个地方和微信公众平台的一致.然后URL那个路径是你真正设置验证的这个路径.然后验签那个地方是没有设置才去验签的 ...

  5. Java 微信关注/取消关注事件

    Java 微信关注/取消关注事件 一.需求.思路 二.文档.配置 配置步骤1 配置步骤2 三.代码 1.引入依赖包 2.controller 3.封装消息对象 4.service.解密 5.工具包 一 ...

  6. 使用.net 操作 微信公众平台 —— 接收用户操作 —— 关注/取消关注 公众号

    目录 1. 使用.net 操作 微信公众平台 -- 接入 2. 使用.net 操作 微信公众平台 -- 生成微信菜单 3. 使用.net 操作 微信公众平台 -- 接收并回复用户消息 3.1 使用.n ...

  7. 微信公众平台开发教程Java版(六) 事件处理(菜单点击/关注/取消关注)

    前言: 事件处理是非常重要的,这一章讲讲常见的事件处理 1.关注/取消关注 2.菜单点击 事件类型介绍: 在微信中有事件请求是消息请求中的一种.请求类型为:event 而event事件类型又分多种事件 ...

  8. 公众号开发精品教程(2)——将项目接入微信及简单交互

    系列文章传送门 公众号开发精品教程(1)--绪论及环境搭建 公众号开发精品教程(2)--将项目接入微信及简单交互 公众号开发精品教程(3)--创建菜单 公众号开发精品教程(4)--生成带参数的二维码及 ...

  9. 菜单点击/关注/取消关注

    事件处理是非常重要的,这一章讲讲常见的事件处理 1.关注/取消关注 2.菜单点击 事件类型介绍: 在微信中有事件请求是消息请求中的一种.请求类型为:event 而event事件类型又分多种事件类型,具 ...

最新文章

  1. 零基础入门学习Python(36) 类和对象:继承
  2. linux下安装python dlib依赖
  3. Rain and Umbrellas(dp)
  4. Altium Designer 09 (Protel)总线使用方法(解决导入PCB无网络标号问题)
  5. c语言程序位置式pid算法,增量式与位置式PID算法(C语言实现与电机控制项目)...
  6. 三类计算机语言及特点,计算机语言分为哪三类,计算机语言有哪些
  7. 翻译【mysqladmin --help】
  8. Git Merge代码失败 解决
  9. Ponemon Institute告诉你,大数据正在勾搭网络安全
  10. android界面编程内部类,Android精讲--界面编程1(界面编程与视图的组件)
  11. Go - cgo访问C数组 内存
  12. Windows程序设计与C语言的主要区别是什么?
  13. rpcbind结合nfs实现文件共享
  14. uicontrol_与UIControl结合
  15. C++ Vector初始化(一维,多维)
  16. 六子棋计算机博弈关键技术研究,六子棋计算机博弈系统的研究与实现-计算机应用技术专业论文.docx...
  17. Unity3D使用talkingData应用数据统计
  18. Junit Test a getter
  19. 怎么关闭win10虚拟机服务器,win10系统彻底关闭退出vmware虚拟机的步骤
  20. GTD和掌握Omni系列效率工具

热门文章

  1. 航空代理人,三字代码查询小助手,三字代码
  2. 邓应海:黄金虎视眈眈1800大关!最新黄金走势分析
  3. 2021-2027全球及中国游梁式抽油机行业研究及十四五规划分析报告
  4. 什么专业转CS,成功率最高?
  5. QR分解求矩阵全部特征值
  6. 计算机会计u8实验报告,会计电算化用友实验报告-20210406233157.pdf-原创力文档
  7. [转载]MATLAB技术论坛【源码交流】汇总
  8. Centos7 Fabric2.4 网络搭建(二)
  9. Adobe Photoshop CS6学习要点
  10. 论文介绍 -- ECO: Efficient Convolutional Network for Online Video Understanding