1
This commit is contained in:
+86
-12
@@ -12,7 +12,10 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -29,8 +32,8 @@ public class WeComApplicationTextPushService {
|
||||
private static final String GET_TOKEN = QYWX_ORIGIN + "/cgi-bin/gettoken";
|
||||
private static final String SEND = QYWX_ORIGIN + "/cgi-bin/message/send?access_token=";
|
||||
private static final String WX_ACCESS_TOKEN = "WECOM_APP_ACTIVE_PUSH_TOKEN:";
|
||||
/** 企微文本消息 content 上限约 2048,预留余量 */
|
||||
private static final int CONTENT_MAX = 2000;
|
||||
/** 企微文本 content 上限 2048 字节;按 UTF-8 拆条,禁止按字符数截断丢尾部 */
|
||||
private static final int CONTENT_MAX_BYTES = 1800;
|
||||
|
||||
@Resource
|
||||
private RedisCache redisCache;
|
||||
@@ -51,6 +54,13 @@ public class WeComApplicationTextPushService {
|
||||
@Value("${qywx.app.goofishSecret:}")
|
||||
private String goofishSecret;
|
||||
|
||||
/** 慢单利润日报等:独立自建应用 */
|
||||
@Value("${qywx.app.reportAgentId:}")
|
||||
private String reportAgentId;
|
||||
|
||||
@Value("${qywx.app.reportSecret:}")
|
||||
private String reportSecret;
|
||||
|
||||
public void sendTextToUser(String toUser, String content) throws Exception {
|
||||
sendTextToUser(toUser, content, null);
|
||||
}
|
||||
@@ -92,8 +102,17 @@ public class WeComApplicationTextPushService {
|
||||
sendTextWithAgent(toUser, content, fishAid, goofishSecret);
|
||||
return;
|
||||
}
|
||||
String reportAid = StrUtil.trimToEmpty(reportAgentId);
|
||||
if (StrUtil.isNotBlank(reportAid) && rid.equals(reportAid)) {
|
||||
if (StrUtil.isBlank(reportSecret)) {
|
||||
throw new IllegalStateException("未配置 qywx.app.reportSecret(与 reportAgentId 对应)");
|
||||
}
|
||||
sendTextWithAgent(toUser, content, reportAid, reportSecret);
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"active-push 未识别的 agentId=" + rid + ",与 qywx.app.agentId / goofishAgentId 均不一致;请补配置或传空使用默认应用");
|
||||
"active-push 未识别的 agentId=" + rid
|
||||
+ ",与 qywx.app.agentId / goofishAgentId / reportAgentId 均不一致;请补配置或传空使用默认应用");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,24 +132,35 @@ public class WeComApplicationTextPushService {
|
||||
if (StrUtil.isBlank(toUser)) {
|
||||
throw new IllegalArgumentException("toUser 不能为空");
|
||||
}
|
||||
String text = content != null ? content : "";
|
||||
if (text.length() > CONTENT_MAX) {
|
||||
text = text.substring(0, CONTENT_MAX) + "…";
|
||||
}
|
||||
|
||||
String token = getAccessToken(useCorpSecret);
|
||||
if (StrUtil.isBlank(token)) {
|
||||
throw new IllegalStateException("获取企微 access_token 失败");
|
||||
}
|
||||
|
||||
Map<String, Object> jsonMap = new HashMap<>();
|
||||
jsonMap.put("touser", toUser.trim());
|
||||
int agentIdInt;
|
||||
try {
|
||||
agentIdInt = Integer.parseInt(useAgentId.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalStateException("agentId 非法: " + useAgentId);
|
||||
}
|
||||
List<String> parts = splitUtf8Chunks(content != null ? content : "", CONTENT_MAX_BYTES);
|
||||
if (parts.isEmpty()) {
|
||||
throw new IllegalArgumentException("推送正文为空");
|
||||
}
|
||||
if (parts.size() > 1) {
|
||||
log.info("企微文本超长,拆成 {} 条下发 agentId={} toUser={}", parts.size(), useAgentId, toUser);
|
||||
}
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
postTextMessage(token, toUser.trim(), agentIdInt, parts.get(i), useAgentId, toUser);
|
||||
if (i + 1 < parts.size()) {
|
||||
sleep(120);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void postTextMessage(String token, String toUser, int agentIdInt, String text,
|
||||
String useAgentId, String logUser) throws Exception {
|
||||
Map<String, Object> jsonMap = new HashMap<>();
|
||||
jsonMap.put("touser", toUser);
|
||||
jsonMap.put("agentid", agentIdInt);
|
||||
jsonMap.put("safe", 0);
|
||||
jsonMap.put("msgtype", "text");
|
||||
@@ -144,7 +174,7 @@ public class WeComApplicationTextPushService {
|
||||
.timeout(30_000)
|
||||
.execute()
|
||||
.body();
|
||||
log.info("企微主动文本下发 agentId={} toUser={} respSnippet={}", useAgentId, toUser,
|
||||
log.info("企微主动文本下发 agentId={} toUser={} respSnippet={}", useAgentId, logUser,
|
||||
resp != null && resp.length() > 200 ? resp.substring(0, 200) + "..." : resp);
|
||||
|
||||
SendRespones sendResp = JSON.parseObject(resp, SendRespones.class);
|
||||
@@ -154,6 +184,50 @@ public class WeComApplicationTextPushService {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> splitUtf8Chunks(String text, int maxBytes) {
|
||||
List<String> out = new ArrayList<>();
|
||||
if (text == null) {
|
||||
return out;
|
||||
}
|
||||
String s = text.trim();
|
||||
if (s.isEmpty()) {
|
||||
return out;
|
||||
}
|
||||
int i = 0;
|
||||
while (i < s.length()) {
|
||||
int end = i;
|
||||
int bytes = 0;
|
||||
int lastBreak = i;
|
||||
while (end < s.length()) {
|
||||
int cp = s.codePointAt(end);
|
||||
int charLen = Character.charCount(cp);
|
||||
int b = new String(Character.toChars(cp)).getBytes(StandardCharsets.UTF_8).length;
|
||||
if (bytes + b > maxBytes) {
|
||||
break;
|
||||
}
|
||||
bytes += b;
|
||||
end += charLen;
|
||||
if (end > 0 && s.charAt(end - 1) == '\n') {
|
||||
lastBreak = end;
|
||||
}
|
||||
}
|
||||
if (end == i) {
|
||||
end = i + Character.charCount(s.codePointAt(i));
|
||||
} else if (lastBreak > i && end < s.length()) {
|
||||
end = lastBreak;
|
||||
}
|
||||
String piece = s.substring(i, end).trim();
|
||||
if (!piece.isEmpty()) {
|
||||
out.add(piece);
|
||||
}
|
||||
i = end;
|
||||
while (i < s.length() && s.charAt(i) == '\n') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private String getAccessToken(String corpSecretForApp) {
|
||||
if (StrUtil.isBlank(corpId) || StrUtil.isBlank(corpSecretForApp)) {
|
||||
return null;
|
||||
|
||||
@@ -88,5 +88,8 @@ qywx:
|
||||
# 生产建议仅通过环境变量注入,勿将真实 Secret 提交仓库
|
||||
goofishAgentId: "1000013"
|
||||
goofishSecret: "${QYWX_GOOFISH_SECRET:hINY8boNFjY3lypOKbcukE8wYnNS9wnXeonB4iTO1rA}"
|
||||
# 慢单利润日报/周报/月报:POST /wecom/active-push 传入 agentId=1000014
|
||||
reportAgentId: "1000014"
|
||||
reportSecret: "${QYWX_REPORT_SECRET:pCrqYLR4VODNyVyWbqP9IRUodzsOY7JrPWlKvoeIxNY}"
|
||||
token: "34NXCtEjkl"
|
||||
encodingAESKey: "bNlE8IhjU34CfXflcBhW3gXPwr8xaEDEhnpUvChvw5i"
|
||||
|
||||
Reference in New Issue
Block a user