消息推送第三方平台(个推)接入工具类

news/2025/1/15 18:59:05/文章来源:https://www.cnblogs.com/xd99/p/18405250

个推官方文档:https://docs.getui.com/getui/server/rest_v2/push/

1、编写配置文件   

  修改.yml文件

getui: AppID: OokKLlwRjU7tJMccVVra72AppKey: f8C6lK7OGu1115ckOfVxD8MasterSecret: aTxslPiUJy9kzzZaPONL26AppSecret: sAoJ9sQ66S13P0PG3c1y02

  编写映射文件

GeTuiConfig
 package com.common.disposition;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Data
@Component
@ConfigurationProperties(prefix = "getui")
public class GeTuiConfig {private String appId;private String appKey;private String masterSecret;private String appSecret;
}

2、编写工具类

GeTuiUtil
 package com.common.util;import com.common.disposition.GeTuiConfig;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.concurrent.TimeUnit;@Component
public class GeTuiUtil {private static String APP_ID;private static String APP_KEY;private static String MASTER_SECRET;// 在构造函数中初始化配置@Autowiredpublic GeTuiUtil(GeTuiConfig config) {APP_ID = config.getAppId();APP_KEY = config.getAppKey();MASTER_SECRET = config.getMasterSecret();}private static final String REDIS_TOKEN_KEY = "GETUI_ACCESS_TOKEN";private static RedisTemplate<String, String> redisTemplate;private static ObjectMapper objectMapper = new ObjectMapper();  // 用于解析 JSON 响应// 初始化 RedisTemplate,手动注入@Autowiredpublic void setRedisTemplate(@Qualifier("stringRedisTemplate") RedisTemplate<String, String> redisTemplate) {GeTuiUtil.redisTemplate = redisTemplate;}// 获取 access_token,优先从 Redis 中获取public static String getAccessToken() throws Exception {String accessToken = redisTemplate.opsForValue().get(REDIS_TOKEN_KEY);if (accessToken == null || accessToken.isEmpty()) {System.out.println("在Redis中找不到访问令牌,正在从GeTui获取...");accessToken = getAccessTokenFromGeTui();} else {System.out.println("从Redis检索到的访问令牌。");}return accessToken;}// 从个推获取 access_tokenprivate static String getAccessTokenFromGeTui() throws Exception {long timestamp = System.currentTimeMillis();String sign = sha256(APP_KEY + timestamp + MASTER_SECRET);String jsonPayload = String.format("{\"sign\": \"%s\", \"timestamp\": \"%s\", \"appkey\": \"%s\"}",sign, timestamp, APP_KEY);String response = postRequest("https://restapi.getui.com/v2/" + APP_ID + "/auth", jsonPayload);String accessToken = parseAccessTokenFromResponse(response);long expireTime = parseExpireTimeFromResponse(response); // 获取过期时间// 将 token 存入 Redis,并设置过期时间redisTemplate.opsForValue().set(REDIS_TOKEN_KEY, accessToken, expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);return accessToken;}// 发送cid单推消息 (toSingle)public static void sendPushMessageCid(String clientId, String title, String body) throws Exception {String token = getAccessToken();String jsonPayload = String.format("{\"request_id\": \"unique_request_id\", \"audience\": {\"cid\": [\"%s\"]}, \"push_message\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}, \"push_channel\": {\"ios\": {\"type\": \"notify\"}, \"android\": {\"ups\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}}}}",clientId, title, body, title, body);postRequest("https://restapi.getui.com/v2/" + APP_ID + "/push/single/cid", jsonPayload, token);}// 发送别名(alias)单推消息 (toSingle)public static void sendPushMessageAlias(String clientId, String title, String body) throws Exception {String token = getAccessToken();String jsonPayload = String.format("{\"request_id\": \"unique_request_id\", \"audience\": {\"alias\": [\"%s\"]}, \"push_message\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}, \"push_channel\": {\"ios\": {\"type\": \"notify\"}, \"android\": {\"ups\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}}}}",clientId, title, body, title, body);postRequest("https://restapi.getui.com/v2/" + APP_ID + "/push/single/cid", jsonPayload, token);}// 发送cid批量推消息 (toList)public static void sendBatchPushMessageCid(String[] clientIds, String title, String body) throws Exception {String token = getAccessToken();StringBuilder cidArray = new StringBuilder();for (String clientId : clientIds) {cidArray.append("\"").append(clientId).append("\",");}// Remove trailing commaString cidList = cidArray.substring(0, cidArray.length() - 1);String jsonPayload = String.format("{\"audience\": {\"cid\": [%s]}, \"push_message\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}, \"push_channel\": {\"ios\": {\"type\": \"notify\"}, \"android\": {\"ups\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}}}}",cidList, title, body, title, body);postRequest("https://restapi.getui.com/v2/" + APP_ID + "/push/list/cid", jsonPayload, token);}// 发送别名(alias)批量推消息 (toList)public static void sendBatchPushMessageAlias(String[] clientIds, String title, String body) throws Exception {String token = getAccessToken();StringBuilder cidArray = new StringBuilder();for (String clientId : clientIds) {cidArray.append("\"").append(clientId).append("\",");}// Remove trailing commaString cidList = cidArray.substring(0, cidArray.length() - 1);String jsonPayload = String.format("{\"audience\": {\"alias\": [%s]}, \"push_message\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}, \"push_channel\": {\"ios\": {\"type\": \"notify\"}, \"android\": {\"ups\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}}}}",cidList, title, body, title, body);postRequest("https://restapi.getui.com/v2/" + APP_ID + "/push/list/cid", jsonPayload, token);}// 发送群推消息 (toApp)public static void sendPushToApp(String title, String body) throws Exception {String token = getAccessToken();String jsonPayload = String.format("{\"request_id\": \"unique_request_id\", \"audience\": \"all\", \"push_message\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}, \"push_channel\": {\"ios\": {\"type\": \"notify\"}, \"android\": {\"ups\": {\"notification\": {\"title\": \"%s\", \"body\": \"%s\", \"click_type\": \"none\"}}}}}",title, body, title, body);postRequest("https://restapi.getui.com/v2/" + APP_ID + "/push/all", jsonPayload, token);}// 通用的 POST 请求,带 Tokenprivate static String postRequest(String requestUrl, String payload, String token) throws Exception {URL url = new URL(requestUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("POST");conn.setRequestProperty("Content-Type", "application/json");conn.setRequestProperty("token", token);conn.setDoOutput(true);try (OutputStream os = conn.getOutputStream()) {byte[] input = payload.getBytes(StandardCharsets.UTF_8);os.write(input, 0, input.length);}int responseCode = conn.getResponseCode();if (responseCode == 200) {System.out.println("推送消息发送成功。");} else {System.out.println("发送推送消息失败。响应代码: " + responseCode);}return new String(conn.getInputStream().readAllBytes(), StandardCharsets.UTF_8);}// 重载的 POST 请求,不带 Tokenprivate static String postRequest(String requestUrl, String payload) throws Exception {URL url = new URL(requestUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("POST");conn.setRequestProperty("Content-Type", "application/json");conn.setDoOutput(true);try (OutputStream os = conn.getOutputStream()) {byte[] input = payload.getBytes(StandardCharsets.UTF_8);os.write(input, 0, input.length);}int responseCode = conn.getResponseCode();if (responseCode == 200) {System.out.println("Request successful.");} else {System.out.println("发送请求失败。响应代码: " + responseCode);}return new String(conn.getInputStream().readAllBytes(), StandardCharsets.UTF_8);}// 解析获取到的 access_tokenprivate static String parseAccessTokenFromResponse(String response) throws Exception {JsonNode rootNode = objectMapper.readTree(response);return rootNode.path("data").path("token").asText();}// 解析过期时间private static long parseExpireTimeFromResponse(String response) throws Exception {JsonNode rootNode = objectMapper.readTree(response);return rootNode.path("data").path("expire_time").asLong();}// 生成 SHA-256 签名private static String sha256(String input) throws Exception {MessageDigest digest = MessageDigest.getInstance("SHA-256");byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));StringBuilder hexString = new StringBuilder();for (byte b : hash) {String hex = Integer.toHexString(0xff & b);if (hex.length() == 1){hexString.append('0');}hexString.append(hex);}return hexString.toString();}
}

3、调用示例

单推送消息
     // 单推送消息@PostMapping("sendBatchPushMessage")@Operation(summary = "单推送消息")public ApiResult<String> sendBatchPushMessage(@RequestParam("clientId") String clientId,@RequestParam("title") String title,@RequestParam("body") String body) {try {GeTuiUtil.sendPushMessageCid(clientId, title, body);return ApiResult.success("推送成功");} catch (Exception e) {// 打印详细的错误信息以便调试e.printStackTrace();return ApiResult.fail("推送失败,内部错误:" + e.getMessage());}}

 

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

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

相关文章

【VMware by Broadcom】Fusion 产品下载汇总

Fusion 产品下载汇总(百度网盘)-『2024年9月9日更新』Fusion 产品版本 百度网盘VMware-Fusion-1.0.0-51348.dmg 链接:https://pan.baidu.com/s/1C8Qkr6nwV5rKrhpsv2JJ_A?pwd=t0kjVMware-Fusion-1.1.0-62573.dmgVMware-Fusion-1.1.1-72241.dmgVMware-Fusion-1.1.2-87978.dmg…

C#/.NET/.NET Core技术前沿周刊 | 第 4 期(2024年9.1-9.8)

前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿,助力技术成长与视野拓宽。欢迎投稿,推荐或自荐优质文章/项目/学习资源等。…

51nod 1051 最大子矩阵和

51nod 1051 最大子矩阵和 可以用前缀和容斥优化到 \(O(n^4)\),但是不够进行如下图操作:将每一列的数值都压缩到一维的数组上,就转换为求最大字段和问题,时间复杂度 \(O(n^3)\)。 看看代码就知道了。 #include <bits/stdc++.h> using namespace std; #define ll long …

VS中如何将本地代码上传到码云仓库

VS中如何将本地代码上传到码云仓库 方式一:点击“添加到源代码管理”VS底部栏点击“添加到源代码管理”,并选择“Git”选项在弹出窗口中,选择“其他→现有远程”选项,在右侧区域找到“远程URL”输入框,输入Gitee仓库地址,然后点击“创建并推送”按钮。此时项目目录会多出…

Linux下网络丢包故障定位

转载: 云网络丢包故障定位全景指南 硬件网卡丢包 Ring Buffer溢出如图所示,物理介质上的数据帧到达后首先由NIC(网络适配器)读取,写入设备内部缓冲区 Ring Buffer中,再由中断处理程序触发 Softirq 从中消费,Ring Buffer 的大小因网卡设备而异。当网络数据包到达(生产)…

第一次个人编程作业

github地址这个作业属于哪个课程 计科22级12班这个作业要求在哪里 作业要求链接这个作业的目标 遍历论文查重并封装成可执行文件,学习PSP和commit规范,学习测试和评估代码一、设计思路 文件结构:程序流程:实现逻辑:查找资料发现比较简单的实现是通过计算余弦向量来实现重复…

echart map图标切换多选,单选,默认选中

需求是echart默认地图选中之前的去过的城市,一开始多选,后面点击为单选const option = {tooltip: {trigger: item,formatter: {b}},series: [{type: map,roam : true,//是否开启缩放和平移zoom : 1,//当前视角缩放比例selectedMode: multiple, // 只允许单选// 设置为一张完整…

CH58x/CH59x/CH57x RF_PHY(2.4g)切换Channel发送接收

前言:在做某些应用的时候可能需要我们发送或者接收时切换对应的channel。 此次完成测试的平台在WCH的CH592F上完成的。 在工作发送过程中切换37、38、39三个信道进行轮询发送。具体需要使用最关键的函数是:RF_SetChannel 实现代码如下:if(events & channl_37_tx_evt){RF…

ArmSoM-Sige5 的 RK3576 SoC 主线内核支持进展

我们很高兴地宣布,基于 RK3576 SoC 的 ArmSoM-Sige5 开发板的主线内核支持,collabora正在稳步推进中。RK3576 SoC 是 Rockchip 家族的一员,其设计和功能与广受欢迎的 RK3588 相似,许多硬件模块都得到了复用,这为我们在主线内核中添加支持提供了有利条件。 RK3576主线内核…

P3579

今天有点高效啊,切数论题都这样喵? #include<bits/stdc++.h> using namespace std; int main() {int n,a,b,c,d,s,m;cin>>n;while(n--){cin>>a>>b>>c>>d; m=min(b,d);for(int i=1;i<=m;i++){i=min(b/(b/i),d/(d/i));//优化,只考虑b/…

机器学习作业

Ch3-K均值聚类算法 【9月4日】 学号:102102156 姓名:高涛 1. make_circles方法生成数据 1.1 源代码 from sklearn.cluster import KMeans from sklearn.datasets import make_circles, make_moons, make_blobs import matplotlib.pyplo…

volta 管理多个node版本时,Volta error: Could not download node

设置代理 在终端中执行以下命令,替换为你自己的代理地址: bash $env:HTTP_PROXY="你的代理地址" $env:HTTPS_PROXY="你的代理地址" 然后重启终端: Windows 用户需要以管理员身份重新打开终端。 Mac 用户只需重启终端即可。 这样可以确保你在终端中通过代…