微信公众号关注/取消订阅事件一文详解

一、背景介绍

这周期的项目需求中需要做一个引导用户关注微信公众号的功能,但是引导用户关注的前提是需要实时获取当前用户是否已经关注微信公众号,如果光看官方文档还是对于一些小伙伴来说比较无从下手,所以我来分享以下我做的过程中遇到的问题以及解决思路。

二、思路&方案

站在巨人的肩膀上:

做之前先阅读了微信公众号官方文档:关注/取消关注事件 | 微信开放文档

前提条件:

  1. 公网域名或IP
  2. 开通80或443端口
  3. 微信公众号的AppId和AppSecret必须认证

流程:

  1. 编写一个验签的接口,这个接口的目的是让微信服务器调用这个接口进行服务校验
  2. 公众号后台进行服务器配置
  3. 关注/取消关注事件接口。当用户对公众号进行关注或取消关注的时候会把这个事件推送到开发者在后台配置的url中,把消息返回给用户进行自定义的使用

三、过程

第一步、编写服务端与微信端建立连接的接口(GET请求)

思想:开发者提交信息后微信服务器会发功一个GET请求到你配置的这个接口,微信用你设置的token和你代码中的token进行对比,验证服务器的可用性

①、接收服务器请求

@Api("公众号")
@RestController
public class Controller {@Autowiredprivate GzhService gzhService;private static final Logger log = LogManager.getLogger(Controller.class);private static final String TOKEN = "szbk";public Controller() {}@GetMapping({"/serverCheck"})public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException,NoSuchAlgorithmException {//接收微信服务器发送请求时传递过来的参数//signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。//timestamp 时间戳//nonce 随机数//echostr 随机字符串String signature = request.getParameter("signature");String timestamp = request.getParameter("timestamp");String nonce = request.getParameter("nonce");String echostr = request.getParameter("echostr");log.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, timestamp, nonce, echostr);//校验signature,timestamp,nonce,echostr这四个参数是否字符串为空或为null,是返回true,反之if (StringUtils.isAnyBlank(new CharSequence[]{signature, timestamp, nonce, echostr})) {throw new IllegalArgumentException("请求参数非法,请核实!");} else {String signatureCheck = getSHA1("szbk", timestamp, nonce);log.info("\n加密后的signatureCheck = {}", signatureCheck);if (signatureCheck.equals(signature)) {log.info("\n接入成功");PrintWriter out = response.getWriter();out.print(echostr);out.flush();out.close();}}}
}

②、SHA1加密

将token、timestamp、nonce三个参数拼接成一个字符串进行sha1加密,之后会将加密后的字符串和singnature进行对比,一样则标识请求时来自微信,否则接入失败

//SHA1加密
public static String getSHA1(String token, String timestamp, String nonce) {try {String[] array = new String[]{token, timestamp, nonce};StringBuffer sb = new StringBuffer();Arrays.sort(array);for (int i = 0; i < 3; ++i) {sb.append(array[i]);}String str = sb.toString();//获取加密对象MessageDigest md = MessageDigest.getInstance("SHA-1");//获取字符串字节数组md.update(str.getBytes());//加密byte[] digest = md.digest();StringBuffer hexstr = new StringBuffer();String shaHex = "";//处理加密结果for (int i = 0; i < digest.length; ++i) {shaHex = Integer.toHexString(digest[i] & 255);if (shaHex.length() < 2) {hexstr.append(0);}hexstr.append(shaHex);}return hexstr.toString();} catch (Exception var11) {var11.printStackTrace();return token;}
}

第二步、编写关注/取消关注事件接口(POST请求)

思想:微信会实时监控公众号用户的指定操作,然后通过这个接口通知(调用这个接口返回信息)给你(服务器)

@PostMapping("/checkToken")
public void checkTokenPost(HttpServletRequest request, HttpServletResponse response) {try {request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");Map<String, String> requestMap = WxMessageUtil.parseXml(request);log.info("解析====>{}", request);String messageType = requestMap.get("MsgType");log.info("微信类型===>{}", messageType);String eventType = requestMap.get("Event");// 发送方帐号(open_id)String openid = requestMap.get("FromUserName");// 公众帐号String toUserName = requestMap.get("ToUserName");// 消息类型String msgType = requestMap.get("MsgType");if (messageType.equals(WxMessageType.EVENT.getCode())) {//判断消息类型是否是事件消息类型log.info("公众号====>事件消息");log.info("openid:" + openid);log.info("Event:" + eventType);if (eventType.equals(WxEeventType.SUBSCRIBE.getCode())) {log.info("公众号====>新用户关注");// 获取接口调用凭证String accessTokenStr = "https://api.weixin.qq.com/cgi-bin/token?" +"grant_type=client_credential" + "&appid=" + "wxXXXXXXXX" + "&secret=" + "f97XXXXXXXX";String tokenStr = HttpUtil.get(accessTokenStr);cn.hutool.json.JSONObject object = JSONUtil.parseObj(tokenStr);String accessToken = object.get("access_token").toString();// 构建获取用户的基本信息String buffer = "https://api.weixin.qq.com/cgi-bin/user/info?" +"access_token=" + accessToken +"&openid=" + openid + "&lang=zh_CN";String wxUserString = HttpUtil.get(buffer);log.info("获取用户信息===>{}", wxUserString);JSONObject jsonObject = JSONUtil.parseObj(wxUserString);} else if (eventType.equals(WxEeventType.UNSUBSCRIBE.getCode())) {log.info("公众号====>用户取消关注");} else {log.info("微信类型===>{}", messageType);log.info("公众号===>其他");}} else if (messageType.equals(WxMessageType.TEXT.getCode())) {log.info("用户输入文本信息");// 响应消息PrintWriter out = response.getWriter();TextMessage textMessage = new TextMessage();textMessage.setFromUserName(openid);textMessage.setToUserName(toUserName);textMessage.setMsgType(msgType);textMessage.setCreateTime(System.currentTimeMillis());textMessage.setContent("欢迎您");String message = WxMessageUtil.textMessageToXml(textMessage);log.info("message==>{}",message);out.println(message);// 关闭流out.close();}} catch (Exception e) {log.error(e.getMessage());}
}

注意:两个接口对外提供的接口名要保持一致!!!

第三步、微信公众平台接口调试工具测试

为了方便测试先使用了微信提供的【微信公众平台接口调试工具】,如果测试的没有问题了在进行公众号后台服务器的配置

 

 URL(服务器接口地址):确保接口能够调通,端口地址可以是80或443,我在做的过程中给接口服务原本配置的是6688接口,但是放到服务器上一直出现访问失败的原因,后来把服务器的80端口开通了就能访问通了

第四步、验证结果

  1. 把写的接口项目打成jar包放在服务器上
  2. 在公众号进行关注或取消关注操作
  3. 查看log文件

在log文件我们发现刚才对公众号的操作都被实时打印到了文件中,这样我们就可以根据这个事件完成对应的业务了

通过第四步的测试说明我们写的接口没有问题,此时我们就可以在公众号后台进行服务器配置了,当然如果你确保你写的接口没有问题也可以直接在公众号后台配置,省略生面测试步骤,下面是配置流程

第五步、填写公众号后台服务器配置

 URL(服务器接口地址):确保接口能够调通,端口地址可以是80或443,我在做的过程中给接口服务原本配置的是6688接口,但是放到服务器上一直出现访问失败的原因,后来把服务器的80端口开通了就能访问通了

Token(令牌):用户可以自定义设置,但是需要和上一步在接口中设置的token保持一致,否则验证也无法通过。(注意:这里的Token不是微信的Access_Token

EncodingAESKey(消息加密密钥):可以自定义生成

消息加密方式:为了测试方便我先选择了明文模式,但是如果你们实际项目中用为了保证安全性可以设置加密级别更好的模式

我们点击提交,如果显示成功则说明验证通过,微信就是实时监听微信公众号用户关注/取消关注的操作,并且将结果转发到我们刚才配置的服务器地址上

四、总结

在接触没有做过的事物之前站在巨人肩膀上(官方文档)可以帮助我们更快速了解,网上资料千千万,我们还要具备选择的能力,否则就是大海捞针。希望这篇文章能帮助到你!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/103687.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTP与RPC的取舍

HTTP与RPC的取舍 HTTP和RPC都是常用的网络通信协议&#xff0c;它们各有优劣。选择何种协议&#xff0c;主要取决于应用的需求和场景。 HTTP和RPC都有各自的优点和缺点&#xff0c;首先我们对两种协议进行一个总结。 HTTP协议图 HTTP的优点&#xff1a; 广泛的支持&#xff1…

leetcode:338. 比特位计数(python3解法)

难度&#xff1a;简单 给你一个整数 n &#xff0c;对于 0 < i < n 中的每个 i &#xff0c;计算其二进制表示中 1 的个数 &#xff0c;返回一个长度为 n 1 的数组 ans 作为答案。 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;[0,1,1] 解释&#xff1a; 0…

在自定义数据集上使用 Detectron2 和 PyTorch 进行人脸检测

本文讲讲述如何使用Python在自定义人脸检测数据集上微调预训练的目标检测模型。学习如何为Detectron2和PyTorch准备自定义人脸检测数据集&#xff0c;微调预训练模型以在图像中找到人脸边界。 人脸检测是在图像中找到&#xff08;边界的&#xff09;人脸的任务。这在以下情况下…

【Java】树结构SQL数据的如何去实现搜索

这里写自定义目录标题 需要实现的效果前端需要的json格式&#xff1a;一定是一个完整的树结构错误错误的返回格式错误的返回格式实现的效果 正确正确的返回格式正确的展示画面 后端逻辑分析代码总览 数据库表结构 需要实现的效果 前端需要的json格式&#xff1a;一定是一个完整…

STM32F4X USART串口使用

STM32F4X USART串口使用 串口概念起始位波特率数据位停止位校验位串口间接线 STM32F4串口使用步骤GPIO引脚复用函数串口初始化函数串口例程 串口概念 串口是MCU与外部通信的重要通信接口&#xff0c;也是MCU在开发过程中的调试利器。串口通信有几个重要的参数&#xff0c;分别…

java8:HashMap的实现原理

一概述 这个哈希表是基于 Map 接口的实现的&#xff0c;它允许 null 值和null 键&#xff0c;它不是线程同步的&#xff0c;同时也不保证有序。 Map 的这种实现方式为 get&#xff08;取&#xff09;和 put&#xff08;存&#xff09;带来了比较好的性能。但是如果涉及到大量的…

如何使用自动化测试工具Selenium?

哈喽&#xff0c;大家好&#xff0c;我是小浪。那么有一段时间没有更新了&#xff0c;还是在忙实习和秋招的事情&#xff0c;那么今天也是实习正式结束啦&#xff0c;开始继续更新我们的学习博客&#xff0c;后期主要是开发和测试的学习博客内容巨多&#xff0c;感兴趣的小伙伴…

Qt 编译使用Bit7z库接口调用7z.dll、7-Zip.dll解压压缩常用Zip、ISO9660、Wim、Esd、7z等格式文件(一)

bit7z一个c静态库&#xff0c;为7-zip共享库提供了一个干净简单的接口 使用CMAKE重新编译github上的bit7z库&#xff0c;用来解压/预览iso9660&#xff0c;WIm&#xff0c;Zip,Rar等常用的压缩文件格式。z-zip库支持大多数压缩文件格式 导读 编译bit7z(C版本)使用mscv 2017编译…

【LeetCode-困难题】42. 接雨水

题目 题解一&#xff1a;暴力双重for循环&#xff08;以行计算水量&#xff09; 1.先找出最高的柱子有多高&#xff08;max 3&#xff09; 2.然后第一个for为行数&#xff08;1&#xff0c;2&#xff0c;3&#xff09; 3.第二个for计算每一行的雨水量&#xff08;关键在于去除…

Dubbo重启服务提供者或先启动服务消费者后启动服务提供者,消费者有时候会出现找不到服务的问题及解决

文章目录 [toc] 1.环境2.版本3.pom依赖3.1父工程的pom3.2子模块的pom 4.问题5.根本原因5.1根本原因说明5.2总入口5.3servletWeb容器初始化5.4 nacos服务注册监听点5.5 dubbo启动服务注册监听点 6.解决办法6.1降低springBoot版本为2.2.x6.2 修改源码6.2.1修改源码方式一6.2.2修改…

机器学习笔记之优化算法(十六)梯度下降法在强凸函数上的收敛性证明

机器学习笔记之优化算法——梯度下降法在强凸函数上的收敛性证明 引言回顾&#xff1a;凸函数与强凸函数梯度下降法&#xff1a;凸函数上的收敛性分析 关于白老爹定理的一些新的认识梯度下降法在强凸函数上的收敛性收敛性定理介绍结论分析证明过程 引言 本节将介绍&#xff1a…

探索PDF校对:为何这是现代数字文档的关键步骤

在今日的数字化浪潮中&#xff0c;文档的创建与分享从未如此频繁。尤其是PDF&#xff0c;作为一个普遍接受的标准文件格式&#xff0c;其在企业、学术和日常生活中的应用已经无处不在。但随之而来的挑战是如何确保文档的准确性和专业性。让我们深入探索PDF校对的重要性以及它为…

Linux 定时任务 crontab 用法学习整理

一、linux版本 lsb_release -a 二、crontab 用法学习 2.1&#xff0c;crontab 简介 linux中crontab命令用于设置周期性被执行的指令&#xff0c;该命令从标准输入设备读取指令&#xff0c;并将其存放于“crontab”文件中&#xff0c;以供之后读取和执行。cron 系统调度进程。…

SQL注入之万能用户名

文章目录 分析代码原理实现 分析代码 在安装的cms数据库目录C:\phpStudy\WWW\cms\admin下找到login.action.php文件&#xff0c;查看第20行&#xff0c;发现如下php代码&#xff1a; $user_row $db->getOneRow("select userid from cms_users where username "…

消息队列——RabbitMQ(一)

MQ的相关概念 什么事mq MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是 message 而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游传递消息。在互联网架构中&#xff…

【unity数据持久化】XML数据管理器知识点

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

如何更高效的写出更健全的代码,一篇文章教会你如何拥有一个良好的代码风格

前言&#xff1a;在平常的写代码的过程中&#xff0c;或多或少的遇到很多奇怪的 bug &#xff0c;尤其是一些大的程序&#xff0c;明明上一部分都是好好的&#xff0c;写下一块的时候突然多几百个 bug 的情况&#xff0c;然后这一块写完了后编译的时候直接傻眼了&#xff0c;看…

缓存穿透、缓存击穿和缓存雪崩

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱发博客的嗯哼&#xff0c;爱好Java的小菜鸟 &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;社区论坛&#xff1a;希望大家能加入社区共同进步…

拼多多app商品详情接口 获取pdd商品主图价格销量库存信息

拼多多是中国一家知名的电商平台&#xff0c;以"社交团购新零售"的商业模式闻名&#xff0c;通过手机app和微信小程序等渠道提供商品销售和购物体验。平台上的商品种类丰富多样&#xff0c;涵盖了服装、家居、美妆、食品、数码电子等各个领域。 拼多多的商业模式主要…

Windows运行Spark所需的Hadoop安装

解压文件 复制bin目录 找到winutils-master文件hadoop对应的bin目录版本 全部复制替换掉hadoop的bin目录文件 复制hadoop.dll文件 将bin目录下的hadoop.dll文件复制到System32目录下 配置环境变量 修改hadoop-env.cmd配置文件 注意jdk装在非C盘则完全没问题&#xff0c;如果装在…