spring boot 发送微信小程序订阅消息

首先我们需要订阅一个消息:

订阅教程本文章并未提起,感兴趣的同学自行百度。

我们可以看到订阅消息中【消息内容】有很多参数,我们在发送消息时就需要将这些参数进行填充,当然填充的时候要注意格式,如果格式不对还是会报错。 

教程开始:

1、创建一个实体类,用来填充对应的数据

import lombok.Data;import java.util.Date;@Data
public class LeaveResultMsg {/*** 请假结果通知 -- 模板ID*/public static String RESULTID = "Qd0*************T8k";/*** 请假人OpenId*/private String openId;/*** 请假人名称*/private String name;/*** 请假开始时间*/private Date startTime;/*** 请假结束时间*/private Date endTime;/*** 审核人*/private String examine;/*** 请假结果(同意,不同意)*/private String status;/*** 请假类型*/private String type;}

2、实现类

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import org.dromara.common.api.service.ApiWeChatUtilsService;
import org.dromara.common.api.utils.DateUtil;
import org.dromara.school.domain.LeaveResultMsg;
import org.dromara.school.service.ISubscribeMsgService;
import org.dromara.system.service.ISysConfigService;
import org.springframework.stereotype.Service;import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;@Service
@RequiredArgsConstructor
public class SubscribeMsgService implements ISubscribeMsgService {private final static String SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";//	private final WeChatTokenUtil weChatTokenUtil;private final ISysConfigService configService;private final ApiWeChatUtilsService apiWeChatUtilsService;/*** 请假结果通知* @param msg* @throws Exception*/public void leaveResultW(LeaveResultMsg msg){try {System.out.println(msg.toString());Map<String, Object> params = baseParams(msg.getOpenId());params.put("template_id", LeaveResultMsg.RESULTID);Map<String, Object> data = new HashMap<String, Object>();// 传入转换后的 UTF-8 编码字节数组data.put("thing2", Collections.singletonMap("value", new String(msg.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)));data.put("time3", Collections.singletonMap("value", DateUtil.getStringDateFormat(msg.getStartTime())));data.put("time4",Collections.singletonMap("value", DateUtil.getStringDateFormat(msg.getEndTime())));data.put("thing7", Collections.singletonMap("value",new String(msg.getExamine().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)));data.put("phrase1",Collections.singletonMap("value", new String(msg.getStatus().getBytes(StandardCharsets.UTF_8),StandardCharsets.UTF_8)));params.put("data", data);System.err.println(params);String post;try {post = HttpUtil.post(SEND_URL + apiWeChatUtilsService.getAccessTokenByRedis(0), JSONUtil.toJsonStr(params));}catch (Exception e) {post = HttpUtil.post(SEND_URL + apiWeChatUtilsService.getAccessTokenByRedis(1), JSONUtil.toJsonStr(params));}
//			String post = HttpUtil.post(SEND_URL + weChatTokenUtil.getAccessToken(), JSONUtil.toJsonStr(params));System.err.println(post);}catch (Exception e){e.printStackTrace();}}
}

关联到的其他方法:

3、组装参数

@Service
@RequiredArgsConstructor
public class SubscribeMsgService implements ISubscribeMsgService {/*** 组装基础参数** @param openId* @return*/private Map<String, Object> baseParams(String openId) {Map<String, Object> map = new HashMap<String, Object>();String touser = openId;String page = "/pages/home/index";// 微信-小程序订阅跳转版本,developer:开发版,trial:体验版,formal:正式版String miniprogramState = configService.selectConfigByKey("***.version"); //小程序版本map.put("touser", touser);map.put("page", page);map.put("miniprogram_state", miniprogramState);return map;}
}

4、时间转换

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;public class DateUtil {   /*** 获取当前时间,转换成String(yyyy-MM-dd HH:mm:ss)* @return yyyyMMddHHmmss*/public static String getStringDateFormat(Date date){//Thu May 11 11:08:15 GMT+08:00 2023//设置日期格式SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//获取String类型的时间String str = df.format(date);return str;}
}

5、获取token

package org.dromara.system.dubbo;import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.api.service.ApiWeChatUtilsService;
import org.dromara.common.api.utils.StringUtil;
import org.dromara.common.api.utils.https.HttpClientUtil;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;import java.time.Duration;
import java.util.HashMap;
import java.util.Map;/*** 字典 业务层处理** @author Lion Li*/
@RequiredArgsConstructor
@Service
@Slf4j
public class ApiWeChatUtilsServiceImpl implements ApiWeChatUtilsService {@AutowiredISysConfigService sysConfigService;/*** 0正常获取,1可能token失效了,重新获取(线上线下冲突)* @return*/@Overridepublic String getAccessTokenByRedis(int state)  {String key = "wx.access_token";String accessToken;if (state==0){accessToken = RedisUtils.getCacheObject(key);if (StringUtil.isEmpty(accessToken)) {accessToken = getAccessTokenByAddress();if (!StringUtil.isEmpty(accessToken))RedisUtils.setCacheObject(key, accessToken, Duration.ofMinutes(120));}}else {accessToken = getAccessTokenByAddress();if (!StringUtil.isEmpty(accessToken))RedisUtils.setCacheObject(key, accessToken, Duration.ofMinutes(120));}return accessToken;}private String getAccessTokenByAddress() {String appid = sysConfigService.selectConfigByKey("***.appid");String secret =sysConfigService.selectConfigByKey("***.secret");String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;String result = HttpUtil.get(url);HashMap<String, String> resultMap = (HashMap<String, String>) JSONUtil.parse(result).toBean(HashMap.class);String accessToken = resultMap.get("access_token");if (StringUtil.isEmpty(accessToken))throw new BaseException(resultMap.get("errmsg"));return accessToken;}/*** 获取手机号* @param code* @return*/@Overridepublic String getPhoneByCode(String code) {String accessToken = getAccessTokenByRedis(0);String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;HttpHeaders headers = new HttpHeaders();RestTemplate restTemplate = new RestTemplate();HttpEntity<Map<String, String>> httpEntity;if (code.contains("code")) {httpEntity = new HttpEntity(code,headers);}else {Map<String, String> params = new HashMap<>();params.put("code", code);httpEntity = new HttpEntity(params,headers);}ResponseEntity<Object> response = restTemplate.postForEntity(url, httpEntity, Object.class, new Object[0]);HashMap<String, Object> resultMap = (HashMap<String, Object>) JSONUtil.parse(response.getBody()).toBean(HashMap.class);int errcode = ((Integer) resultMap.get("errcode")).intValue();if (errcode != 0) {if (errcode == 40001){//可能会出现多个服务器重复获取,导致accessToken失效的情况accessToken = getAccessTokenByRedis(1);url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;response = restTemplate.postForEntity(url, httpEntity, Object.class, new Object[0]);resultMap = (HashMap<String, Object>) JSONUtil.parse(response.getBody()).toBean(HashMap.class);errcode = ((Integer) resultMap.get("errcode")).intValue();if (errcode != 0){throw new ServiceException("获取手机号出错,报错类型------>{}",errcode);}}else {throw new ServiceException("获取手机号出错,报错类型------>{}",errcode);}}HashMap<String, Object> phoneInfo = (HashMap<String, Object>) JSONUtil.parse(resultMap.get("phone_info")).toBean(HashMap.class);String phone = (String) phoneInfo.get("purePhoneNumber");return phone;}/*** 获取手机号2* @param code* @return*/public String getPhoneByCode2(String code) {String accessToken = getAccessTokenByRedis(0);String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
//        String jsonStr = "{\"code\":\"" + code + "\"}";String httpOrgCreateTestRtn = HttpClientUtil.doPost(url, code, "utf-8");System.out.println("获取到的手机号----------->"+httpOrgCreateTestRtn);return httpOrgCreateTestRtn;}/*** 获取openid* @param code* @return*/@Overridepublic String getOpenidByCode(String code) {String appid = sysConfigService.selectConfigByKey("weChat.mini.appid");String secret =sysConfigService.selectConfigByKey("weChat.mini.secret");//https://api.weixin.qq.com/sns/jscode2sessionString url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret +"&js_code=" + code + "&grant_type=authorization_code";String result = HttpUtil.get(url);HashMap<String, String> resultMap = (HashMap<String, String>) JSONUtil.parse(result).toBean(HashMap.class);String openId = resultMap.get("openid");
//        System.out.println("获取到的openId----------->"+openId);if (StringUtils.isNotEmpty(openId)) {return openId;} else {throw new ServiceException("用户信息获取错误,请稍候重试",Integer.valueOf(resultMap.get("errcode")) );}}}

以上用到的config类是配置类,配置的内容是由你申请小程序时候得到的数据。

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

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

相关文章

LDR6020在Type-C手机同时充电与USB2.0数据传输方案

随着科技的飞速发展&#xff0c;Type-C接口已成为智能手机等移动设备的主流充电和数据传输接口。为了满足用户对于高效充电与稳定数据传输的双重需求&#xff0c;乐得瑞科技推出的LDR6020芯片凭借其卓越的性能和丰富的功能&#xff0c;为Type-C手机提供了同时充电与USB2.0数据传…

关于归并排序:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_urlhttps%3A%2F return 语句开始之后&#xff0c;会执行之前剩余遗留下的语句和状态#include<bits/stdc.h> using namespace std…

使用RestHighLevelClient进行Elasticsearch Function Score查询

简介 Function Score查询在Elasticsearch中是一个强大的工具&#xff0c;它允许我们根据一个或多个函数来调整查询结果的相关性得分。这使得我们可以基于某些条件对搜索结果进行更精细的控制。本文将介绍如何在Java应用程序中使用Elasticsearch的RestHighLevelClient执行Funct…

快速把文件名统计到excel表的方法

文件名统计到EXCEL表&#xff0c;这似乎很多人都没听说过&#xff0c;因为它与EXCEL表格不沾边&#xff0c;那么这个需求如何实现&#xff0c;用到什么方法&#xff0c;今天给大家介绍一个比较实用的方法&#xff0c;它可以把文件名或文件夹的名快速提取并统计到EXCEL表格上去。…

【Day05】0基础微信小程序入门-学习笔记

文章目录 基础加强学习目标使用npm包1.准备项目2. 小程序对于npm的支持和限制3. Vant Weapp小程序UI组件库4. 使用Vant组件5. 定制全局主题样式6. API Promise化 全局数据共享1. 简介2. MobX2.1 安装MobX相关包并构建npm2.2 创建MobX的Store实例2.3 将Store成员绑定到页面中2.4…

ppt中添加页码(幻灯片编号)及问题解决方案

在幻灯片母版中&#xff0c;选择插入 幻灯片编号 右下角显示幻灯片编号 问题一&#xff1a;母版中没有显示编号 原因可能是母版版式中没有设置显示&#xff0c;勾选即可。 问题二&#xff1a;子母版中没有显示幻灯片 将母版中的编号复制到子母版中。 问题三&#xff1a;应用…

股指期货套期保值中的展期管理有哪些?

在复杂的金融市场环境中&#xff0c;展期作为一种重要的风险管理工具&#xff0c;被广泛应用于期货交易中&#xff0c;特别是当投资者需要对长期资产进行套期保值时。展期的核心思想在于&#xff0c;通过连续替换高流动性的近月期货合约来替代流动性较差的远月合约&#xff0c;…

神经发育过程中结构性大脑不对成的大规模分析

摘要 目前&#xff0c;只有少数研究评估了儿童期和青春期两个大脑半球之前的结构差异&#xff0c;而且现有的研究结果缺乏一致性&#xff0c;或者局限于特定的脑区、特定的大脑特征或相对较窄的年龄范围。在这里&#xff0c;本研究考察了大脑不对称性与年龄和性别之间的关系&a…

Java SE--IO流

一.File类型 如果我们想在程序中操作或者描述一个文件夹或文件&#xff0c;可以使用File类型 File类型在java.io包下 File可以新建&#xff0c;删除&#xff0c;移动&#xff0c;修改&#xff0c;重命名文件夹&#xff0c;也可以对文件或者文件夹的属性进行访问&#xff1b;…

进阶!haproxy高级功能与配置

文章目录 前言基于cookie的会话保持IP透传四层IP透传未开启状态开启透传状态 七层IP透传 自定义错误界面重定向HAProxy 四层负载之数据库HAProxy https 前言 本文主要介绍HAProxy高级配置及使用案例 文章相关连接如下&#xff1a; 如果想深入了解haproxy算法的相关知识&…

EXCEL数据清洗步骤

1.合并的单元格&#xff1a; 用Ctrlg查找空值&#xff0c;拆分单元格&#xff0c;ctrl enter填充 2.空值空行&#xff1a; 辅助列counta&#xff0c;筛选出空值行 3.重复值&#xff1a; 条件格式——突出显示单元格规则——重复值 数据——数据工具——删除重复值 4.脏数据…

[算法2] 第二集 二叉树中的深度搜索

深度优先遍历&#xff08;DFS&#xff0c;全称为 Depth First Traversal&#xff09;&#xff0c;是我们树或者图这样的数据结构中常⽤的 ⼀种遍历算法。这个算法会尽可能深的搜索树或者图的分支&#xff0c;直到⼀条路径上的所有节点都被遍历 完毕&#xff0c;然后再回溯到上…

Steinberg SpectraLayers Pro for Mac:专业音频频谱编辑的巅峰之作

Steinberg SpectraLayers Pro for Mac是一款专为音频专业人士设计的专业音频频谱编辑器&#xff0c;它以其强大的频谱编辑功能和直观的操作界面&#xff0c;在音频处理领域树立了新的标杆。该软件不仅为音频编辑工作带来了前所未有的精确度和灵活性&#xff0c;还极大地提升了音…

WPF 数据模板DataTemplate、控件模板ControlTemplate、Style、ItemsPreseter

一言蔽之&#xff0c;Template就是“外衣”—— ControlTemplate是控件的外衣&#xff0c; DataTemplate是数据的外衣。 DataTemplate 它定义了一个数据对象的可视化结构 DataTemplate常用的地方有3处&#xff0c;分别是&#xff1a; ContentControl的ContentTemplate属性&…

CODEXGRAPH:突破代码与AI的壁垒,开启智能编程新时代

CODEXGRAPH&#xff1a;突破代码与AI的壁垒&#xff0c;开启智能编程新时代 CODEXGRAPH论文阅读1. 概述2. 相关研究代码库级别的任务检索增强代码生成&#xff08;RACG&#xff09; 3. CODEXGRAPH系统设计代码图数据库的构建与图数据库的交互 4. 实验设计与结果CrossCodeEvalSW…

数据结构---单链表实现

单链表是什么 我的理解是“特殊的数组”&#xff0c;通过访问地址来连接起来 1怎么创建链表 ----通过结构体&#xff08;成员有存入数据的data和指向下一个节点的地址的指针&#xff08;结构体指针&#xff09;next 初始架构---DataType 对应存入数据类型&#xff0c;此处的N…

数字引领风尚·智能改变生活“青岛电博会”路演活动(济南站)

2024CICE中国国际消费电子博览会路演活动&#xff08;济南站&#xff09;成功举行 数字引领风尚&#xff0c;智能改变生活。 8月7日&#xff0c;50余家行业协会、企业嘉宾、展商代表等云集2024中国国际消费电子博览会路演活动&#xff08;济南站&#xff09;现场&#xff0c;共…

瑞萨电子并购Altium 引领行业创新与发展

公开资料显示&#xff0c;2023 年 6 月&#xff0c;瑞萨电子曾宣布在 Altium 的 Altium 365 云平台上实现了所有 PCB 设计的标准化开发。瑞萨电子一直与 Altium 合作&#xff0c;将其所有产品的 ECAD 库发布到 Altium Public Vault。借助 Altium365 上的制造商零件搜索等功能&a…

Wireshark分析工具

简单用例 首先打开软件,左上角点文件,选中要分析的文件列表。 导入用tcpdump抓的包后进行分析,这里要输入过滤条件,对网络包进行一定的过滤处理。(这里172网段是阿里云的地址,用自己写的python2脚本对阿里云进行压测。) 这里输入过滤条件 tcp.port == 80 ,语法含义是…

Java虚拟机:类的加载机制

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 034 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…