All checks were successful
缓存序列化结构检查 / cache-schema-check (push) Has been skipped
1、多 key 默认拼成 1 条企微通知 2、UTF-8 超过 4096 字节 → 按 key 拆开,每条带完整抬头,依次发送 3、条间间隔 200ms,降低机器人限频风险 4、CI 控制台会标明「超长已按 key 拆为 N 条」并逐条打印
101 lines
3.8 KiB
Java
101 lines
3.8 KiB
Java
package com.codechecker.cache.notify;
|
||
|
||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||
|
||
import java.net.URI;
|
||
import java.net.http.HttpClient;
|
||
import java.net.http.HttpRequest;
|
||
import java.net.http.HttpResponse;
|
||
import java.nio.charset.StandardCharsets;
|
||
import java.time.Duration;
|
||
import java.util.LinkedHashMap;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 企业微信群机器人通知(markdown 消息)。
|
||
*/
|
||
public class WeComNotifier {
|
||
|
||
private final ObjectMapper mapper = new ObjectMapper();
|
||
private final HttpClient client = HttpClient.newBuilder()
|
||
.connectTimeout(Duration.ofSeconds(10))
|
||
.build();
|
||
|
||
/**
|
||
* @return 是否发送成功
|
||
*/
|
||
public boolean sendMarkdown(String webhookUrl, String markdown) {
|
||
if (webhookUrl == null || webhookUrl.trim().isEmpty()) {
|
||
System.err.println("[WeComNotifier] 未配置 webhook,跳过通知");
|
||
return false;
|
||
}
|
||
try {
|
||
Map<String, Object> md = new LinkedHashMap<>();
|
||
md.put("content", markdown);
|
||
Map<String, Object> payload = new LinkedHashMap<>();
|
||
payload.put("msgtype", "markdown");
|
||
payload.put("markdown", md);
|
||
|
||
String body = mapper.writeValueAsString(payload);
|
||
HttpRequest request = HttpRequest.newBuilder()
|
||
.uri(URI.create(webhookUrl))
|
||
.timeout(Duration.ofSeconds(15))
|
||
.header("Content-Type", "application/json; charset=utf-8")
|
||
.POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
|
||
.build();
|
||
|
||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||
if (response.statusCode() == 200) {
|
||
// 企微成功时 body 一般为 {"errcode":0,...}
|
||
if (response.body() != null && response.body().contains("\"errcode\":0")) {
|
||
return true;
|
||
}
|
||
if (response.body() != null && response.body().contains("errcode")
|
||
&& !response.body().contains("\"errcode\":0")) {
|
||
System.err.println("[WeComNotifier] 通知失败: " + response.body());
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
System.err.println("[WeComNotifier] 通知失败, HTTP " + response.statusCode() + ": " + response.body());
|
||
return false;
|
||
} catch (Exception e) {
|
||
System.err.println("[WeComNotifier] 通知异常: " + e.getMessage());
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 按序发送多条 Markdown(用于超长按 key 拆分后的通知)。
|
||
*
|
||
* @return 成功条数
|
||
*/
|
||
public int sendMarkdownMessages(String webhookUrl, List<String> markdownMessages) {
|
||
if (markdownMessages == null || markdownMessages.isEmpty()) {
|
||
return 0;
|
||
}
|
||
int ok = 0;
|
||
for (int i = 0; i < markdownMessages.size(); i++) {
|
||
String content = markdownMessages.get(i);
|
||
boolean success = sendMarkdown(webhookUrl, content);
|
||
if (success) {
|
||
ok++;
|
||
}
|
||
System.out.println("[WeComNotifier] 第 " + (i + 1) + "/" + markdownMessages.size()
|
||
+ " 条发送" + (success ? "成功" : "失败")
|
||
+ " (" + content.getBytes(StandardCharsets.UTF_8).length + " bytes)");
|
||
// 避免触发机器人频率限制(约 20 条/分钟)
|
||
if (i < markdownMessages.size() - 1) {
|
||
try {
|
||
Thread.sleep(200L);
|
||
} catch (InterruptedException e) {
|
||
Thread.currentThread().interrupt();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return ok;
|
||
}
|
||
}
|