This commit is contained in:
Leo
2026-01-05 22:02:15 +08:00
parent e9747e6af2
commit 81203488c8
5 changed files with 375 additions and 21 deletions

View File

@@ -19,5 +19,60 @@ public interface ILogisticsService {
* @return 如果已处理返回true否则返回false
*/
boolean isOrderProcessed(Long orderId);
/**
* 检查物流服务健康状态
* @return 健康状态信息,包含是否健康、状态描述等
*/
HealthCheckResult checkHealth();
/**
* 健康检测结果
*/
class HealthCheckResult {
private boolean healthy;
private String status;
private String message;
private String serviceUrl;
public HealthCheckResult(boolean healthy, String status, String message, String serviceUrl) {
this.healthy = healthy;
this.status = status;
this.message = message;
this.serviceUrl = serviceUrl;
}
public boolean isHealthy() {
return healthy;
}
public void setHealthy(boolean healthy) {
this.healthy = healthy;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getServiceUrl() {
return serviceUrl;
}
public void setServiceUrl(String serviceUrl) {
this.serviceUrl = serviceUrl;
}
}
}

View File

@@ -0,0 +1,62 @@
package com.ruoyi.jarvis.service;
/**
* 微信推送服务接口
*/
public interface IWxSendService {
/**
* 检查微信推送服务健康状态
* @return 健康状态信息,包含是否健康、状态描述等
*/
HealthCheckResult checkHealth();
/**
* 健康检测结果
*/
class HealthCheckResult {
private boolean healthy;
private String status;
private String message;
private String serviceUrl;
public HealthCheckResult(boolean healthy, String status, String message, String serviceUrl) {
this.healthy = healthy;
this.status = status;
this.message = message;
this.serviceUrl = serviceUrl;
}
public boolean isHealthy() {
return healthy;
}
public void setHealthy(boolean healthy) {
this.healthy = healthy;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getServiceUrl() {
return serviceUrl;
}
public void setServiceUrl(String serviceUrl) {
this.serviceUrl = serviceUrl;
}
}
}

View File

@@ -71,19 +71,15 @@ public class LogisticsServiceImpl implements ILogisticsService {
return stringRedisTemplate.hasKey(redisKey);
}
/**
* 检查物流服务健康状态
* @return 是否健康
*/
private boolean checkLogisticsServiceHealth() {
@Override
public ILogisticsService.HealthCheckResult checkHealth() {
try {
logger.debug("开始检查物流服务健康状态 - URL: {}", healthCheckUrl);
String healthResult = HttpUtils.sendGet(healthCheckUrl);
if (healthResult == null || healthResult.trim().isEmpty()) {
logger.warn("物流服务健康检查返回空结果");
handleHealthCheckFailure("健康检查返回空结果");
return false;
return new ILogisticsService.HealthCheckResult(false, "异常", "健康检查返回空结果", healthCheckUrl);
}
// 尝试解析JSON响应
@@ -98,9 +94,7 @@ public class LogisticsServiceImpl implements ILogisticsService {
if ("ok".equalsIgnoreCase(status) || "healthy".equalsIgnoreCase(status) ||
Boolean.TRUE.equals(healthy) || (code != null && code == 200)) {
logger.debug("物流服务健康检查通过");
// 清除健康检查失败标记
stringRedisTemplate.delete(REDIS_HEALTH_CHECK_ALERT_KEY);
return true;
return new ILogisticsService.HealthCheckResult(true, "正常", "服务运行正常", healthCheckUrl);
}
}
} catch (Exception e) {
@@ -108,26 +102,40 @@ public class LogisticsServiceImpl implements ILogisticsService {
String lowerResult = healthResult.toLowerCase();
if (lowerResult.contains("ok") || lowerResult.contains("healthy") || lowerResult.contains("success")) {
logger.debug("物流服务健康检查通过非JSON格式");
stringRedisTemplate.delete(REDIS_HEALTH_CHECK_ALERT_KEY);
return true;
return new ILogisticsService.HealthCheckResult(true, "正常", "服务运行正常", healthCheckUrl);
}
}
logger.warn("物流服务健康检查失败 - 响应: {}", healthResult);
handleHealthCheckFailure("健康检查返回异常状态: " + healthResult);
return false;
return new ILogisticsService.HealthCheckResult(false, "异常", "健康检查返回异常状态: " + healthResult, healthCheckUrl);
} catch (Exception e) {
logger.error("物流服务健康检查异常 - URL: {}, 错误: {}", healthCheckUrl, e.getMessage(), e);
handleHealthCheckFailure("健康检查异常: " + e.getMessage());
return false;
return new ILogisticsService.HealthCheckResult(false, "异常", "健康检查异常: " + e.getMessage(), healthCheckUrl);
}
}
/**
* 检查物流服务健康状态(内部方法,用于业务逻辑)
* @return 是否健康
*/
@SuppressWarnings("unused")
private boolean checkLogisticsServiceHealth() {
ILogisticsService.HealthCheckResult result = checkHealth();
if (result.isHealthy()) {
// 清除健康检查失败标记
stringRedisTemplate.delete(REDIS_HEALTH_CHECK_ALERT_KEY);
} else {
handleHealthCheckFailure(result.getMessage());
}
return result.isHealthy();
}
/**
* 处理健康检查失败,推送提醒消息
* @param reason 失败原因
*/
@SuppressWarnings("null")
private void handleHealthCheckFailure(String reason) {
try {
// 检查是否在提醒间隔内已经推送过
@@ -167,8 +175,8 @@ public class LogisticsServiceImpl implements ILogisticsService {
if (pushResult != null && !pushResult.trim().isEmpty()) {
logger.info("健康检查失败提醒已推送 - 响应: {}", pushResult);
// 记录推送时间30分钟内不再重复推送
Long currentTime = System.currentTimeMillis();
stringRedisTemplate.opsForValue().set(alertKey, currentTime.toString(),
long currentTime = System.currentTimeMillis();
stringRedisTemplate.opsForValue().set(alertKey, Long.toString(currentTime),
HEALTH_CHECK_ALERT_INTERVAL_MINUTES, TimeUnit.MINUTES);
} else {
logger.warn("健康检查失败提醒推送失败 - 响应为空");
@@ -218,9 +226,9 @@ public class LogisticsServiceImpl implements ILogisticsService {
}
// 先进行健康检查
boolean healthCheckPassed = checkLogisticsServiceHealth();
if (!healthCheckPassed) {
logger.error("物流服务健康检查失败,跳过处理订单 - 订单ID: {}", orderId);
ILogisticsService.HealthCheckResult healthResult = checkHealth();
if (!healthResult.isHealthy()) {
logger.error("物流服务健康检查失败,跳过处理订单 - 订单ID: {}, 原因: {}", orderId, healthResult.getMessage());
return false;
}

View File

@@ -0,0 +1,169 @@
package com.ruoyi.jarvis.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.jarvis.service.IWxSendService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
/**
* 微信推送服务实现类
*/
@Service
public class WxSendServiceImpl implements IWxSendService {
private static final Logger logger = LoggerFactory.getLogger(WxSendServiceImpl.class);
private static final String PUSH_TOKEN = "super_token_b62190c26";
@Value("${jarvis.server.wxsend.base-url:https://wxts.van333.cn}")
private String wxSendBaseUrl;
@Value("${jarvis.server.wxsend.health-path:/wx/send/pdd}")
private String wxSendHealthPath;
private String healthCheckUrl;
@PostConstruct
public void init() {
healthCheckUrl = wxSendBaseUrl + wxSendHealthPath;
logger.info("微信推送服务健康检查地址已初始化: {}", healthCheckUrl);
}
@Override
public IWxSendService.HealthCheckResult checkHealth() {
try {
logger.debug("开始检查微信推送服务健康状态 - URL: {}", healthCheckUrl);
// 构建一个测试请求(使用最小的有效请求体)
JSONObject testRequest = new JSONObject();
testRequest.put("title", "健康检查");
testRequest.put("text", "健康检查测试消息");
testRequest.put("vanToken", PUSH_TOKEN);
testRequest.put("messageType", "PDD");
String jsonBody = testRequest.toJSONString();
// 发送POST请求进行健康检查
String healthResult = sendPostWithHeaders(healthCheckUrl, jsonBody, PUSH_TOKEN);
if (healthResult == null || healthResult.trim().isEmpty()) {
logger.warn("微信推送服务健康检查返回空结果");
return new IWxSendService.HealthCheckResult(false, "异常", "健康检查返回空结果", healthCheckUrl);
}
// 尝试解析JSON响应
try {
JSONObject response = JSON.parseObject(healthResult);
if (response != null) {
Integer code = response.getInteger("code");
Boolean success = response.getBoolean("success");
String msg = response.getString("msg");
// 检查是否成功code为200或0或者success为true
if ((code != null && (code == 200 || code == 0)) || Boolean.TRUE.equals(success)) {
logger.debug("微信推送服务健康检查通过");
return new IWxSendService.HealthCheckResult(true, "正常", "服务运行正常", healthCheckUrl);
} else {
// 检查是否是token验证失败说明服务可用只是token问题
if (msg != null && msg.contains("vanToken")) {
logger.debug("微信推送服务健康检查通过服务可用token验证失败是正常的");
return new IWxSendService.HealthCheckResult(true, "正常", "服务运行正常token验证失败是正常的", healthCheckUrl);
}
logger.warn("微信推送服务健康检查失败 - 响应: {}", healthResult);
return new IWxSendService.HealthCheckResult(false, "异常", "健康检查返回异常状态: " + msg, healthCheckUrl);
}
}
} catch (Exception e) {
// 如果不是JSON格式检查是否包含成功标识
String lowerResult = healthResult.toLowerCase();
if (lowerResult.contains("ok") || lowerResult.contains("success") || lowerResult.contains("正常")) {
logger.debug("微信推送服务健康检查通过非JSON格式");
return new IWxSendService.HealthCheckResult(true, "正常", "服务运行正常", healthCheckUrl);
}
}
logger.warn("微信推送服务健康检查失败 - 响应: {}", healthResult);
return new IWxSendService.HealthCheckResult(false, "异常", "健康检查返回异常状态: " + healthResult, healthCheckUrl);
} catch (Exception e) {
logger.error("微信推送服务健康检查异常 - URL: {}, 错误: {}", healthCheckUrl, e.getMessage(), e);
return new IWxSendService.HealthCheckResult(false, "异常", "健康检查异常: " + e.getMessage(), healthCheckUrl);
}
}
/**
* 发送POST请求支持自定义header用于健康检查
* @param url 请求URL
* @param jsonBody JSON请求体
* @param token 认证token
* @return 响应结果
*/
private String sendPostWithHeaders(String url, String jsonBody, String token) {
java.io.BufferedReader in = null;
java.io.PrintWriter out = null;
StringBuilder result = new StringBuilder();
try {
java.net.URL realUrl = new java.net.URL(url);
java.net.URLConnection conn = realUrl.openConnection();
// 设置请求头
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("vanToken", token);
conn.setRequestProperty("source", "XZJ_UBUNTU");
conn.setDoOutput(true);
conn.setDoInput(true);
// 设置超时时间(健康检查需要快速响应)
conn.setConnectTimeout(5000); // 5秒连接超时
conn.setReadTimeout(5000); // 5秒读取超时
// 发送请求体
out = new java.io.PrintWriter(conn.getOutputStream());
out.print(jsonBody);
out.flush();
// 读取响应
in = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream(), java.nio.charset.StandardCharsets.UTF_8));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
logger.debug("微信推送服务健康检查请求成功 - URL: {}, 响应: {}", url, result.toString());
} catch (java.net.ConnectException e) {
logger.error("微信推送服务健康检查连接失败 - URL: {}", url, e);
throw new RuntimeException("健康检查连接失败: " + e.getMessage(), e);
} catch (java.net.SocketTimeoutException e) {
logger.error("微信推送服务健康检查超时 - URL: {}", url, e);
throw new RuntimeException("健康检查请求超时: " + e.getMessage(), e);
} catch (java.io.IOException e) {
logger.error("微信推送服务健康检查IO异常 - URL: {}", url, e);
throw new RuntimeException("健康检查IO异常: " + e.getMessage(), e);
} catch (Exception e) {
logger.error("微信推送服务健康检查异常 - URL: {}", url, e);
throw new RuntimeException("健康检查异常: " + e.getMessage(), e);
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (java.io.IOException ex) {
logger.error("关闭流异常", ex);
}
}
return result.toString();
}
}