1
This commit is contained in:
@@ -214,6 +214,10 @@ jarvis:
|
||||
wxsend-base-url: http://127.0.0.1:36699
|
||||
# 须与 wxSend jarvis.wecom.push-secret 一致(Header X-WxSend-WeCom-Push-Secret)
|
||||
push-secret: jarvis_wecom_push_change_me
|
||||
# 闲鱼订单事件 → wxSend POST /wecom/goofish-active-push(须与 wxSend goofish-push-secret 一致)
|
||||
goofish-push-secret: jarvis_wecom_goofish_push_change_me
|
||||
# 接收企微通知的成员 UserID,多个逗号或 |;留空则不推送
|
||||
goofish-notify-touser: "LinPinFan"
|
||||
# 多轮会话:与 JDUtil interaction_state 类似,TTL 与空闲超时(分钟)
|
||||
session-ttl-minutes: 30
|
||||
session-idle-timeout-minutes: 30
|
||||
|
||||
@@ -210,6 +210,8 @@ jarvis:
|
||||
inbound-secret: jarvis_wecom_bridge_change_me
|
||||
wxsend-base-url: http://127.0.0.1:36699
|
||||
push-secret: jarvis_wecom_push_change_me
|
||||
goofish-push-secret: jarvis_wecom_goofish_push_change_me
|
||||
goofish-notify-touser: "LinPinFan"
|
||||
session-ttl-minutes: 30
|
||||
session-idle-timeout-minutes: 30
|
||||
session-sweep-ms: 60000
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.jarvis.domain.ErpGoofishOrder;
|
||||
import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLog;
|
||||
import com.ruoyi.jarvis.mapper.ErpGoofishOrderEventLogMapper;
|
||||
import com.ruoyi.jarvis.wecom.WxSendGoofishNotifyClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -30,6 +31,9 @@ public class GoofishOrderChangeLogger {
|
||||
@Resource
|
||||
private ErpGoofishOrderEventLogMapper erpGoofishOrderEventLogMapper;
|
||||
|
||||
@Resource
|
||||
private WxSendGoofishNotifyClient wxSendGoofishNotifyClient;
|
||||
|
||||
public void append(Long orderId, String appKey, String orderNo, String eventType, String source, String message) {
|
||||
if (orderId == null || StringUtils.isEmpty(message)) {
|
||||
return;
|
||||
@@ -47,8 +51,14 @@ public class GoofishOrderChangeLogger {
|
||||
erpGoofishOrderEventLogMapper.insert(row);
|
||||
} catch (Exception e) {
|
||||
log.warn("闲管家订单事件日志写入失败 orderId={} {}", orderId, e.toString());
|
||||
return;
|
||||
}
|
||||
log.info("[goofish-order-event] orderId={} orderNo={} type={} source={} {}", orderId, orderNo, eventType, source, msg);
|
||||
try {
|
||||
wxSendGoofishNotifyClient.notifyGoofishEvent(orderNo, eventType, source, msg);
|
||||
} catch (Exception ex) {
|
||||
log.debug("闲鱼订单事件 wxSend 通知跳过 err={}", ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
package com.ruoyi.jarvis.wecom;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 调用 wxSend 闲鱼自建应用文本推送(POST /wecom/goofish-active-push,agent 见 wxSend qywx.app.goofishAgentId)。
|
||||
*/
|
||||
@Component
|
||||
public class WxSendGoofishNotifyClient {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(WxSendGoofishNotifyClient.class);
|
||||
|
||||
public static final String HEADER_GOOFISH_PUSH_SECRET = "X-WxSend-Goofish-Push-Secret";
|
||||
|
||||
/** 与企微 message/send 文本 content 上限对齐,预留余量 */
|
||||
private static final int CONTENT_MAX = 2000;
|
||||
|
||||
@Value("${jarvis.wecom.wxsend-base-url:}")
|
||||
private String wxsendBaseUrl;
|
||||
|
||||
@Value("${jarvis.wecom.goofish-push-secret:}")
|
||||
private String goofishPushSecret;
|
||||
|
||||
/**
|
||||
* 接收通知的成员 UserID(企微管理后台可见),多个用英文逗号或 | 分隔;
|
||||
* 发往 wxSend 时会规范为 touser 的 user1|user2 形式。留空表示不推送。
|
||||
*/
|
||||
@Value("${jarvis.wecom.goofish-notify-touser:}")
|
||||
private String goofishNotifyTouser;
|
||||
|
||||
/**
|
||||
* 闲鱼订单事件通知 wxSend(由 wxSend 转企微应用消息)。
|
||||
*
|
||||
* @param orderNo 闲鱼订单号
|
||||
* @param eventType ORDER_SYNC / LOGISTICS_SYNC / SHIP
|
||||
* @param source NOTIFY、LIST、DETAIL_REFRESH 等
|
||||
* @param message 已截断的说明文案
|
||||
*/
|
||||
public void notifyGoofishEvent(String orderNo, String eventType, String source, String message) {
|
||||
if (!StringUtils.hasText(wxsendBaseUrl) || !StringUtils.hasText(goofishPushSecret)) {
|
||||
return;
|
||||
}
|
||||
String toUser = buildTouserParam(goofishNotifyTouser);
|
||||
if (!StringUtils.hasText(toUser)) {
|
||||
return;
|
||||
}
|
||||
String content = buildContent(orderNo, eventType, source, message);
|
||||
if (!StringUtils.hasText(content)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String base = normalizeBase(wxsendBaseUrl);
|
||||
String url = base + "/wecom/goofish-active-push";
|
||||
postJson(url, toUser, content);
|
||||
} catch (Exception e) {
|
||||
log.warn("wxSend goofish-active-push 失败 orderNo={} err={}", orderNo, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static String buildContent(String orderNo, String eventType, String source, String message) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("【闲鱼订单】").append(orderNo != null ? orderNo : "-").append("\n");
|
||||
if (StringUtils.hasText(eventType)) {
|
||||
sb.append(eventType);
|
||||
}
|
||||
if (StringUtils.hasText(source)) {
|
||||
sb.append(" | ").append(source);
|
||||
}
|
||||
sb.append("\n");
|
||||
if (StringUtils.hasText(message)) {
|
||||
sb.append(message);
|
||||
}
|
||||
String s = sb.toString();
|
||||
if (s.length() > CONTENT_MAX) {
|
||||
return s.substring(0, CONTENT_MAX - 1) + "…";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 逗号或 | 分隔的 UserID → 企微 API 要求的 user1|user2
|
||||
*/
|
||||
private static String buildTouserParam(String raw) {
|
||||
if (!StringUtils.hasText(raw)) {
|
||||
return null;
|
||||
}
|
||||
String[] parts = raw.split("[,|]");
|
||||
List<String> ids = new ArrayList<>();
|
||||
for (String p : parts) {
|
||||
String t = p == null ? "" : p.trim();
|
||||
if (t.length() > 0) {
|
||||
ids.add(t);
|
||||
}
|
||||
}
|
||||
if (ids.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return String.join("|", ids);
|
||||
}
|
||||
|
||||
private static String normalizeBase(String base) {
|
||||
String b = base.trim();
|
||||
if (b.endsWith("/")) {
|
||||
return b.substring(0, b.length() - 1);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
private void postJson(String url, String toUser, String content) throws Exception {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("toUser", toUser);
|
||||
body.put("content", content);
|
||||
byte[] bytes = body.toJSONString().getBytes(StandardCharsets.UTF_8);
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setConnectTimeout(15000);
|
||||
conn.setReadTimeout(60000);
|
||||
conn.setDoOutput(true);
|
||||
conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
|
||||
conn.setRequestProperty(HEADER_GOOFISH_PUSH_SECRET, goofishPushSecret);
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
os.write(bytes);
|
||||
}
|
||||
int code = conn.getResponseCode();
|
||||
InputStream is = code >= 200 && code < 300 ? conn.getInputStream() : conn.getErrorStream();
|
||||
String resp = readAll(is);
|
||||
if (code < 200 || code >= 300) {
|
||||
log.warn("wxSend goofish-active-push HTTP {} body={}", code, resp);
|
||||
} else {
|
||||
log.debug("wxSend goofish-active-push OK http={} resp={}", code, resp);
|
||||
}
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String readAll(InputStream is) throws java.io.IOException {
|
||||
if (is == null) {
|
||||
return "";
|
||||
}
|
||||
byte[] buf = new byte[4096];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int n;
|
||||
while ((n = is.read(buf)) >= 0) {
|
||||
sb.append(new String(buf, 0, n, StandardCharsets.UTF_8));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user