增加企业微信通知·

master
xce 2026-01-24 21:53:00 +08:00
parent 1c3dc095e4
commit 251bfe63a6
7 changed files with 142 additions and 19 deletions

View File

@ -16,7 +16,12 @@
</description> </description>
<dependencies> <dependencies>
<!-- 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.20</version> <!-- 该版本完全兼容JDK 8 -->
</dependency>
<!-- Spring框架基本的核心工具 --> <!-- Spring框架基本的核心工具 -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>

View File

@ -1,5 +1,22 @@
package com.agri.common.utils.http; package com.agri.common.utils.http;
import com.agri.common.constant.Constants;
import com.agri.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -11,17 +28,6 @@ import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.agri.common.constant.Constants;
import com.agri.common.utils.StringUtils;
import org.springframework.http.MediaType;
/** /**
* http * http
@ -32,6 +38,69 @@ public class HttpUtils
{ {
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class); private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
// 静态RestTemplate全局唯一线程安全
private static final RestTemplate restTemplate;
// 静态代码块初始化RestTemplate项目启动时执行一次
static {
// 配置超时时间,避免连接卡死
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 连接超时5秒
factory.setReadTimeout(5000); // 读取超时5秒
// 初始化静态RestTemplate
restTemplate = new RestTemplate(factory);
}
/**
* POST
* @param url
* @param requestBody /Map/JSON
* @param contentType Content-Typeapplication/json
* @param responseType String.class/.class
* @return
*/
public static <T, R> R post(String url, T requestBody, String contentType, Class<R> responseType) {
// 前置校验:避免空指针
if (url == null || url.isEmpty()) {
throw new IllegalArgumentException("请求URL不能为空");
}
if (contentType == null || contentType.isEmpty()) {
throw new IllegalArgumentException("Content-Type不能为空");
}
if (restTemplate == null) {
throw new IllegalStateException("RestTemplate初始化失败请检查配置");
}
try {
// 1. 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(contentType));
// 2. 封装请求实体
HttpEntity<T> requestEntity = new HttpEntity<>(requestBody, headers);
// 3. 发送POST请求
return restTemplate.postForObject(url, requestEntity, responseType);
} catch (RestClientException e) {
// 详细异常信息,方便定位问题
throw new RuntimeException(
String.format("HTTP POST请求失败url=%s, contentType=%s", url, contentType),
e
);
}
}
/**
* POSTString
* @param url
* @param requestBody
* @param contentType Content-Type
* @return
*/
public static <T> String post(String url, T requestBody, String contentType) {
return post(url, requestBody, contentType, String.class);
}
/** /**
* URL GET * URL GET
* *

View File

@ -0,0 +1,36 @@
package com.agri.common.utils.wechat;
import cn.hutool.core.map.MapUtil;
import com.agri.common.utils.http.HttpUtils;
import org.springframework.http.MediaType;
import java.util.Map;
/**
* @Auther: jone
* @Date: 2026/1/24 - 01 - 24 - 21:12
* @Description: com.agri.common.utils.wechat
* @version: 1.0
*/
public class WxUtil {
private static final String WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=3cfeb466-76b9-4cf9-b03b-2324a2c3900f";
/**
*
* @param param
* @return
*/
public static Map pushText(String param) {
// 1. 构建请求参数
Map<String, Object> requestBody = MapUtil.<String, Object>builder()
.put("msgtype", "text")
.put("text", MapUtil.<String, Object>builder()
.put("content", param)
.build())
.build();
return HttpUtils.post(WEBHOOK_URL,
requestBody, MediaType.APPLICATION_JSON_VALUE, Map.class);
}
}

View File

@ -0,0 +1,12 @@
package com.agri.framework.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration // 必须加
public class RestTemplateConfig {
@Bean // 必须加声明RestTemplate为Spring Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

View File

@ -1,5 +1,6 @@
package com.agri.framework.manager; package com.agri.framework.manager;
import com.agri.common.utils.wechat.WxUtil;
import com.agri.framework.config.MqttConfig; import com.agri.framework.config.MqttConfig;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
@ -174,6 +175,7 @@ public class MqttAutoOffManager {
try { try {
runAutoOff(deviceId, funcType); runAutoOff(deviceId, funcType);
} catch (Exception e) { } catch (Exception e) {
WxUtil.pushText("【自动关任务】提交任务失败! deviceId: "+deviceId+", funcType: "+funcType+", msg: "+e.getMessage());
log.error("【自动关任务】执行失败deviceId={}, funcType={}", deviceId, funcType, e); log.error("【自动关任务】执行失败deviceId={}, funcType={}", deviceId, funcType, e);
} finally { } finally {
// 任务执行完成后移除映射 // 任务执行完成后移除映射
@ -205,6 +207,7 @@ public class MqttAutoOffManager {
try { try {
latestObj = JSON.parseObject(latest); latestObj = JSON.parseObject(latest);
} catch (Exception e) { } catch (Exception e) {
WxUtil.pushText("自动关任务执行报错-解析异常deviceId:" + deviceId + ", funcType:" + funcType+"异常:"+e.getMessage());
log.warn("【自动关任务】最新状态JSON解析失败跳过deviceId={}, funcType={}", deviceId, funcType); log.warn("【自动关任务】最新状态JSON解析失败跳过deviceId={}, funcType={}", deviceId, funcType);
return; return;
} }

View File

@ -1,5 +1,6 @@
package com.agri.framework.manager; package com.agri.framework.manager;
import com.agri.common.utils.wechat.WxUtil;
import com.agri.framework.web.dispatcher.MqttMessageDispatcher; import com.agri.framework.web.dispatcher.MqttMessageDispatcher;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
@ -139,7 +140,7 @@ public class MqttClientManager implements SmartLifecycle {
log.error("【MQTT连接异常】连接断开clientId{},原因:{}", log.error("【MQTT连接异常】连接断开clientId{},原因:{}",
safeClientId(), (cause == null ? "unknown" : cause.getMessage()), cause); safeClientId(), (cause == null ? "unknown" : cause.getMessage()), cause);
WxUtil.pushText("【MQTT连接异常】连接断开clientId"+safeClientId()+",原因:"+(cause == null ? "unknown" : cause.getMessage()));
// 【方案A】不再触发自写重连Paho自动重连会接管重连过程 // 【方案A】不再触发自写重连Paho自动重连会接管重连过程
// 这里只记录日志即可 // 这里只记录日志即可
if (isRunning.get()) { if (isRunning.get()) {
@ -166,6 +167,9 @@ public class MqttClientManager implements SmartLifecycle {
log.debug("mqttBizPool active={}, queue={}", log.debug("mqttBizPool active={}, queue={}",
mqttBizPool.getActiveCount(), mqttBizPool.getActiveCount(),
mqttBizPool.getQueue().size()); mqttBizPool.getQueue().size());
if (mqttBizPool.getActiveCount()>10 || mqttBizPool.getQueue().size()>1000) {
WxUtil.pushText("线程池繁忙 正在处理中任务:"+mqttBizPool.getActiveCount()+", 剩余待进行任务:"+mqttBizPool.getQueue().size());
}
try { try {
// 优化显式指定UTF-8编码避免乱码JDK 8兼容 // 优化显式指定UTF-8编码避免乱码JDK 8兼容
mqttMessageDispatcher.handleMessage(topic, payload); mqttMessageDispatcher.handleMessage(topic, payload);

View File

@ -47,12 +47,6 @@
<version>3.5.3.1</version> <version>3.5.3.1</version>
</dependency> </dependency>
<!-- 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.20</version> <!-- 该版本完全兼容JDK 8 -->
</dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>