个推官方文档:https://docs.getui.com/getui/server/rest_v2/push/
首先申请个推官方账号,然后注册App获取AppID、AppKey、AppSecret、MasterSecret
接入教程
1、编写配置文件
修改.yml文件
getui:
AppID: OokKLlwRjU7tJMccVVra72
AppKey: f8C6lK7OGu1115ckOfVxD8
MasterSecret: aTxslPiUJy9kzzZaPONL26
AppSecret: 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;
// 在构造函数中初始化配置
@Autowired
public 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,手动注入
@Autowired
public 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_token
private 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 comma
String 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 comma
String 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 请求,带 Token
private 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 请求,不带 Token
private 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_token
private 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());
}
}
标签:body,String,title,接入,token,static,import,推送,第三方 From: https://www.cnblogs.com/xd99/p/18405250