1
This commit is contained in:
@@ -6,6 +6,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.framework.web.domain.Server;
|
||||
import com.ruoyi.jarvis.service.ILogisticsService;
|
||||
import com.ruoyi.jarvis.service.IWxSendService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 服务器监控
|
||||
@@ -16,6 +22,12 @@ import com.ruoyi.framework.web.domain.Server;
|
||||
@RequestMapping("/monitor/server")
|
||||
public class ServerController
|
||||
{
|
||||
@Resource
|
||||
private ILogisticsService logisticsService;
|
||||
|
||||
@Resource
|
||||
private IWxSendService wxSendService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:server:list')")
|
||||
@GetMapping()
|
||||
public AjaxResult getInfo() throws Exception
|
||||
@@ -24,4 +36,52 @@ public class ServerController
|
||||
server.copyTo();
|
||||
return AjaxResult.success(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务健康度检测
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('monitor:server:list')")
|
||||
@GetMapping("/health")
|
||||
public AjaxResult getHealth() throws Exception
|
||||
{
|
||||
Map<String, Object> healthMap = new HashMap<>();
|
||||
|
||||
// 物流服务健康检测
|
||||
try {
|
||||
ILogisticsService.HealthCheckResult logisticsHealth = logisticsService.checkHealth();
|
||||
Map<String, Object> logisticsMap = new HashMap<>();
|
||||
logisticsMap.put("healthy", logisticsHealth.isHealthy());
|
||||
logisticsMap.put("status", logisticsHealth.getStatus());
|
||||
logisticsMap.put("message", logisticsHealth.getMessage());
|
||||
logisticsMap.put("serviceUrl", logisticsHealth.getServiceUrl());
|
||||
healthMap.put("logistics", logisticsMap);
|
||||
} catch (Exception e) {
|
||||
Map<String, Object> logisticsMap = new HashMap<>();
|
||||
logisticsMap.put("healthy", false);
|
||||
logisticsMap.put("status", "异常");
|
||||
logisticsMap.put("message", "健康检测异常: " + e.getMessage());
|
||||
logisticsMap.put("serviceUrl", "");
|
||||
healthMap.put("logistics", logisticsMap);
|
||||
}
|
||||
|
||||
// 微信推送服务健康检测
|
||||
try {
|
||||
IWxSendService.HealthCheckResult wxSendHealth = wxSendService.checkHealth();
|
||||
Map<String, Object> wxSendMap = new HashMap<>();
|
||||
wxSendMap.put("healthy", wxSendHealth.isHealthy());
|
||||
wxSendMap.put("status", wxSendHealth.getStatus());
|
||||
wxSendMap.put("message", wxSendHealth.getMessage());
|
||||
wxSendMap.put("serviceUrl", wxSendHealth.getServiceUrl());
|
||||
healthMap.put("wxSend", wxSendMap);
|
||||
} catch (Exception e) {
|
||||
Map<String, Object> wxSendMap = new HashMap<>();
|
||||
wxSendMap.put("healthy", false);
|
||||
wxSendMap.put("status", "异常");
|
||||
wxSendMap.put("message", "健康检测异常: " + e.getMessage());
|
||||
wxSendMap.put("serviceUrl", "");
|
||||
healthMap.put("wxSend", wxSendMap);
|
||||
}
|
||||
|
||||
return AjaxResult.success(healthMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user