JAVA实现公众号扫码登录和关注功能实战

news2024/12/30 2:29:05

前言

使用第三方插件
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-mp</artifactId>
    <version>4.6.0</version>
</dependency>

准备APPID和appSecet

扫码登录

公众号回调

  • 回调代码块实现

    /**
       * 验证微信服务器 此接口不调用
       */
      @ApiOperation(value = "验证微信服务器 此接口不调用")
      @GetMapping(value = "/callback")
      public String checkSign(HttpServletRequest request) {
          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);
          if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
              log.error("【无效的请求】");
              throw new ServiceException("无效的请求", -1);
          }
          return echostr;
      }
    
      /**
       * 响应微信,这一步是关注微信后,响应微信获取信息
       */
      @ApiOperation(value = "微信扫码响应微信服务器")
      @PostMapping("/callback")
      public String scanQRCodesCallBack(HttpServletRequest request, @RequestBody String requestBody) {
          String signature = request.getParameter("signature");
          String timestamp = request.getParameter("timestamp");
          String nonce = request.getParameter("nonce");
          String echostr = request.getParameter("echostr");
          String openid = request.getParameter("openid");
          String encType = request.getParameter("encType");
          String msgSignature = request.getParameter("msgSignature");
          log.info("\n接收到来自微信服务器的认证消息:[signature:{}, timestamp:{}, nonce:{}, echostr:{},encType:{},msgSignature:{}]", signature, timestamp, nonce, echostr, encType, msgSignature);
          if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
              log.error("【无效的请求】");
              throw new ServiceException("无效的请求", -1);
          }
          if (encType == null) {
              // 明文传输的消息
              WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
              log.debug("\n消息内容为:\n{} ", inMessage.toString());
              return weiXinService.scanQRCodesCallBack(inMessage);
          } else if ("aes".equalsIgnoreCase(encType)) {
              // aes加密的消息
              WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxMpService.getWxMpConfigStorage(),
                      timestamp, nonce, msgSignature);
              log.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
              return weiXinService.scanQRCodesCallBack(inMessage);
          }
          return "";
      }
    
    复制@Override
      public String scanQRCodesCallBack(WxMpXmlMessage message) {
          log.info("总的message:" + JSON.toJSONString(message));
          // content 公众号回复用户的文本内容
          String content = "欢迎关注公众号!NatCross是内网穿透工具,也是免费的端口映射软件。解决80被封/动态IP/无公网ip问题;适用于发布网站、访问局域网服务器和应用服务。";
          String messageType = message.getMsgType();                                //消息类型
          String messageEvent = message.getEvent();                                    //消息事件
          String fromUser = message.getFromUser();                                 //发送者帐号
          String toUser = message.getToUser();                                       //开发者微信号
          String text = message.getContent();                                        //文本消息  文本内容
          String eventKey = message.getEventKey();                                    //二维码参数
          JSONObject businessParams = JSON.parseObject(eventKey);                    //从二维码参数中获取uuid通过该uuid可通过websocket前端传数据
    
          log.info("消息类型:{},消息事件:{},发送者账号:{},接收者微信:{},文本消息:{},二维码参数:{}", messageType, messageEvent, fromUser, toUser, text, eventKey);
          WxMpUser wxMpUser = null;
          try {
              wxMpUser = wxMpService.getUserService().userInfo(fromUser);
          } catch (WxErrorException e) {
              e.printStackTrace();
          }
          log.info("通过用户openid获取用户信息:" + JSON.toJSONString(wxMpUser));
          if (StringUtils.equalsAnyIgnoreCase(WechatEventEnum.unsubscribe.getType(), messageEvent)) {
              //取消订阅
              log.info("取消订阅");
              return this.msgStr(message, "取消关注成功!");
          }
          String uuid = businessParams.containsKey("uuid") ? businessParams.getString("uuid") : null;
          if (StringUtils.isEmpty(uuid)) {
              //未知关注公众号,默认提示
              log.info("未知关注公众号,默认提示");
              return this.msgStr(message, content);
          }
          String redisData = Objects.toString(stringRedisTemplate.opsForValue().get(RedisKey.WECHAT_SCAN_UUID_FLAG + uuid), null);
          if (StringUtils.isNotEmpty(redisData) && wxMpUser != null) {
              if (StringUtils.equalsAnyIgnoreCase(WechatEventEnum.SCAN.getType(), messageEvent)) {
                  String eventType = businessParams.getString("eventType");
                  if (StringUtils.equalsAnyIgnoreCase(MsgEventTypeEnum.ADD_WARNING_RECEIVER.getEventType(), eventType)) {
                      content = DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS) + "添加告警接收人成功!";
                  } else if (StringUtils.equalsAnyIgnoreCase(MsgEventTypeEnum.USER_LOGIN.getEventType(), eventType)) {
                      content = DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS) + "扫描登录成功!";
                  }
                  JSONObject dataMap = JSON.parseObject(redisData);
                  dataMap.put("openid", wxMpUser.getOpenId());
                  dataMap.put("unionid", wxMpUser.getUnionId());
                  dataMap.put("nickName", wxMpUser.getNickname());
                  dataMap.put("headImgUrl", wxMpUser.getHeadImgUrl());
                  stringRedisTemplate.opsForValue().set(RedisKey.WECHAT_SCAN_UUID_RESULT_FLAG + uuid, dataMap.toString());
              }
          }
          // 根据来时的信息格式,重组返回。(注意中间不能有空格)
          final String msgStr = this.msgStr(message, content);
          return msgStr;
      }
    
      @Override
      public NatMemberWechat getScanResult(String uuid) {
          String redisData = Objects.toString(stringRedisTemplate.opsForValue().get(RedisKey.WECHAT_SCAN_UUID_RESULT_FLAG + uuid), null);
          if (StringUtils.isEmpty(redisData)) {
              log.debug("redisData is null");
              return null;
          }
          JSONObject jsonObject = JSONObject.parseObject(redisData);
          NatMemberWechat natMemberWechat = natMemberWechatService.selectNatMemberWechatByOpenId(jsonObject.getString("openid"));
          if(natMemberWechat==null){
              natMemberWechat=new NatMemberWechat();
              natMemberWechat.setOpenId(jsonObject.getString("openid"));
              natMemberWechat.setUserId(null);
          }
          return natMemberWechat;
      }
    
      private String msgStr(WxMpXmlMessage message, String content) {
          // 根据来时的信息格式,重组返回。(注意中间不能有空格)
          final String msgStr = "<xml>"
                  + "<ToUserName><![CDATA[" + message.getFromUser() + "]]></ToUserName>"
                  + "<FromUserName><![CDATA[" + message.getToUser() + "]]></FromUserName>"
                  + "<CreateTime>" + new Date().getTime() + "</CreateTime>"
                  + "<MsgType><![CDATA[text]]></MsgType>"
                  + "<Content><![CDATA[" + content + "]]></Content>"
                  + "</xml>";
          return msgStr;
      }
    
  • 回调日志​​​​​​​测试通过后,如果是vue前后端分离,可以把接口给前端调用。
    以上是JAVA实现公众号扫码登录和关注的开发流程。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

防火墙的混合模式配置

&#x1f3c6;本文收录于《全栈Bug调优(实战版)》专栏&#xff0c;主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&am…

刘洋,一个爱 drink 的好运程序员|MarsCoders 开发者说

「MarsCoders 开发者说」是 AI 时代下各类技术栈、各种经历的开发者的故事记录&#xff0c;我们捕捉并再现他们在技术洪流中的职场蜕变与角色定位重塑&#xff0c;希望给更多开发者带来启发。 同时&#xff0c;该系列也记录了众多豆包MarsCode 用户和 AI 爱好者们的实践案例&am…

ICE/TURN/STUN/Coturn服务器搭建

ICE 当我们想要实现在公网环境下的语音/视频通话功能时&#xff0c;就需要用到ICE交互式连接建立。ICE不是一种协议&#xff0c;整合了 STUN 和 TURN 两种协议&#xff08;用于 NAT 穿透&#xff09;的框架。 ICE的主要目标是解决NAT&#xff08;网络地址转换&#xff09;穿越…

5分钟英文论文降重工具:DeepL【翻译、改写、缩写】

关注B站可以观看更多实战教学视频&#xff1a;hallo128的个人空间 5分钟英文论文降重工具&#xff1a;DeepL【翻译、改写、缩写】 视频学习&#xff1a;5分钟英文论文降重工具&#xff1a;DeepL【翻译、改写、缩写】 DeepL网址 官方网址&#xff1a;https://www.deepl.com/zh/…

超越单线程:Web Worker 在前端性能中的角色

在当今快速发展的数字时代&#xff0c;用户对网页性能的期待已经达到了前所未有的高度&#xff0c;想象一下&#xff0c;当你打开一个网站&#xff0c;瞬间加载、流畅操作&#xff0c;没有任何卡顿和延迟&#xff0c;这种体验无疑会让你倍感惊喜。然而在前端开发中&#xff0c;…

机器学习——多模态学习

多模态学习&#xff1a;机器学习领域的新视野 引言 多模态学习&#xff08;Multimodal Learning&#xff09;是机器学习中的一个前沿领域&#xff0c;它涉及处理和整合来自多个数据模式&#xff08;如图像、文本、音频等&#xff09;的信息。随着深度学习的蓬勃发展&#xff0…

编译链接的过程发生了什么?

一&#xff1a;程序的翻译环境和执行环境 在 ANSI C 的任何一种实现中&#xff0c;存在两个不同的环境。 第 1 种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。 第 2 种是执行环境&#xff0c;它用于实际执行代码 也就是说&#xff1a;↓ 1&#xff1…

纠删码参数自适应匹配问题ECP-AMP实验方案(下)

7.参数选择 7.1.综合性能goal 根据权重和性能指标&#xff0c;本方案为每个文件确定最佳的纠删码参数&#xff0c;并将文件分组到不同的数据池中。本文使用了以下公式计算每个文件的评分&#xff0c;表示该文件在使用不同的纠删码参数时的综合性能。 s i j k ∑ j 1 6 c j…

2023 CCPC哈尔滨 报告

比赛链接&#xff1a;Dashboard - 10.6组队训练赛-2023CCPC哈尔滨站 - Codeforceshttps://codeforces.com/group/w6iGs8kreW/contest/552949 做题数&#xff1a;3 题 三题都是队友写的。所以来补一下 B L J。 B题&#xff1a; B. Memory Little G used to be a participant …

【MySQL】基本查询(上):创建、读取

1.Create(创建) 语法&#xff1a; INSERT [INTO] table_name [(column [, column] ...)] VALUES (value_list) [, (value_list)] ...value_list: value, [, value] ... 接下来我们用这个下表作为例子&#xff1a; -- 创建一张学生表 CREATE TABLE students ( id INT UNSIGN…

Http 协议和 RPC 协议有什么区别?

Http 协议和 RPC 协议有什么区别&#xff1f; 三个层面来述说&#xff1a; 从功能特性来说&#xff1a; HTTP是一个属于应用层的超文本传输协议&#xff0c;是万维网数据通信的基础&#xff0c;主要服务在网页端和服务端的数据传输上。 RPC是一个远程过程调用协议&#xff0…

【JS】哈希法解决两数之和

思路 使用哈希法&#xff1a;需要快速查询一个元素是否出现过&#xff0c;或者一个元素是否在集合里时 本题需要一个集合来存放我们遍历过的元素&#xff0c;然后在遍历数组的时候去询问这个集合&#xff0c;符合要求的某元素是否遍历过&#xff0c;也就是 是否出现在这个集合。…

【算法】链表:24.两两交换链表中的节点

目录 1、题目链接 2、题目介绍 3、解法 4、代码 1、题目链接 24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 2、题目介绍 3、解法 引入伪头节点&#xff1a; 为了处理头节点可能被交换的情况&#xff0c;我们引入一个伪头节点&#xff08;dummy no…

jenkins远程调用

curl -G -d tokenfetch_coverage_token&systemmes2&typefull&envsit&resetno http://remote_user:1172e3d5524629fabef5dd55c652646232192.168.36.196:8080/job/fetch_coverage/buildWithParameters 在jenkins的用户界面设置一个token就可以了 remote_user 为…

Android笔记(二十四)基于Compose组件的MVVM模式和MVI模式的实现

仔细研究了一下MVI(Model-View-Intent)模式&#xff0c;发现它和MVVM模式非常的相识。在采用Android JetPack Compose组件下&#xff0c;MVI模式的实现和MVVM模式的实现非常的类似&#xff0c;都需要借助ViewModel实现业务逻辑和视图数据和状态的传递。在这篇文章中&#xff0c…

ESP32-C3实现UART

配置串口参数 在编写代码之前&#xff0c;你需要确定要使用的 UART 端口号和配置参数&#xff08;波特率、数据位、停止位等&#xff09;。 // 定义 UART 端口 #define TX_PIN 1 // TX 管脚 #define RX_PIN 3 // RX 管脚// 定义串口配置参数 #define UART_BAUDRATE 115200 // …

springboot 项目使用 gitlab 的 API

springboot 项目使用 gitlab 的 API 前言获取用户 access tokenSpring boot项目集成GitLab依赖1 pom依赖2 配置文件3 启动类4 核心代码gitlab 的 API 说明前言 需求是通过gitlab的api获取其中的数据。 gitlab官方API文档:https://docs.gitlab.com/ee/api/users.html gitla…

SpringBoot实现电子文件签字+合同系统

​ 博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 在现代企业中&#xff0c;合同管理和电子文件签字已成为日常运营不可或缺的一部分。为了提升效率和安全性&#xff0c;我们可以使用SpringBoot框架来实现一个电子文件签字和合同管理系统。本文将详细介绍如何…

腾讯云SDK连麦应用

音视频终端 SDK&#xff08;腾讯云视立方&#xff09;将新版连麦管理方案的多个功能集成至 腾讯云视立方控制台 > 连麦管理&#xff0c;便于用户快捷使用&#xff0c;具体分为快速上手、连麦应用、用量统计和地址生成器四个功能页面。更多连麦功能说明&#xff0c;请参见 新…

【算法刷题指南】BFS解决FloodFill算法

&#x1f308;个人主页&#xff1a; 南桥几晴秋 &#x1f308;C专栏&#xff1a; 南桥谈C &#x1f308;C语言专栏&#xff1a; C语言学习系列 &#x1f308;Linux学习专栏&#xff1a; 南桥谈Linux &#x1f308;数据结构学习专栏&#xff1a; 数据结构杂谈 &#x1f308;数据…