增加企业微信通知·
parent
1c3dc095e4
commit
251bfe63a6
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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-Type(如application/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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态简化版POST请求(响应默认String)
|
||||||
|
* @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方法的请求
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue