增加多Mqtt实例

This commit is contained in:
zhangyue 2026-07-29 16:28:09 +08:00
parent 246483f4ec
commit 340abe8a18
21 changed files with 954 additions and 328 deletions

View File

@ -221,4 +221,10 @@ public interface IotConstants {
*/ */
String lhviot_standard = "lhviot_standard"; String lhviot_standard = "lhviot_standard";
/**
* mqtt连接协议
*/
String CONFIG_TYPE_MQTT = "mqtt";
} }

View File

@ -88,6 +88,12 @@ public class SurvConfig extends Model<SurvConfig> {
@TableField("CONFIG_TYPE") @TableField("CONFIG_TYPE")
private String configType; private String configType;
/**
* 系统内置
*/
@TableField("CONFIG_SUB_TYPE")
private String configSubType;
/** /**
* 备注 * 备注
*/ */

View File

@ -9,6 +9,7 @@ public enum IotInerfaceTopicType {
LH_IOT_TOPIC_UP("/lh-iot-up","蓝海虚拟设备头上行"), LH_IOT_TOPIC_UP("/lh-iot-up","蓝海虚拟设备头上行"),
LH_IOT_TOPIC_DOWN("/lh-iot-down","蓝海虚拟设备头下行"), LH_IOT_TOPIC_DOWN("/lh-iot-down","蓝海虚拟设备头下行"),
API_TOPIC("/api-","厂家api头"), API_TOPIC("/api-","厂家api头"),
RENKE_TOPIC("rtd/","厂家仁科头"),
OTHER("other","其他") OTHER("other","其他")
; ;

View File

@ -0,0 +1,229 @@
package com.lanhai.mqtt.config;
import com.lanhai.mqtt.handler.MqttCallbackHandler;
import com.lanhai.mqtt.service.MessageProcessor;
import com.lanhai.service.ISurvIotVirtualDeviceService;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Slf4j
@Component
public class MqttClientManager {
private final MqttProperties mqttProperties;
private final ISurvIotVirtualDeviceService deviceService;
private final MessageProcessor messageProcessor;
/**
* 存储所有MQTT客户端实例key为客户端名称
*/
private final Map<String, MqttClient> clientMap = new ConcurrentHashMap<>();
/**
* 存储每个客户端对应的回调处理器
*/
private final Map<String, MqttCallbackHandler> callbackMap = new ConcurrentHashMap<>();
public MqttClientManager(MqttProperties mqttProperties,
ISurvIotVirtualDeviceService deviceService,
MessageProcessor messageProcessor) {
this.mqttProperties = mqttProperties;
this.deviceService = deviceService;
this.messageProcessor = messageProcessor;
}
/**
* 初始化所有MQTT连接
*/
public void init() {
if (!Boolean.TRUE.equals(mqttProperties.getEnabled())) {
log.info("MQTT 未启用,跳过初始化");
return;
}
List<MqttProperties.MqttClientConfig> clients = mqttProperties.getClients();
if (clients == null || clients.isEmpty()) {
log.warn("MQTT 客户端配置列表为空");
return;
}
for (MqttProperties.MqttClientConfig config : clients) {
if (Boolean.FALSE.equals(config.getEnabled())) {
log.info("MQTT 客户端 [{}] 已禁用,跳过", config.getName());
continue;
}
try {
initClient(config);
} catch (Exception e) {
log.error("MQTT 客户端 [{}] 初始化失败", config.getName(), e);
}
}
}
/**
* 初始化单个MQTT客户端
*/
private void initClient(MqttProperties.MqttClientConfig config) throws MqttException {
String clientName = config.getName();
log.info("========== 初始化 MQTT 客户端 [{}] ==========", clientName);
// 创建客户端
MqttClient mqttClient = new MqttClient(
config.getBroker().getUrl(),
config.getClient().getId(),
new MemoryPersistence()
);
// 创建对应的回调处理器
MqttCallbackHandler callbackHandler = new MqttCallbackHandler();
callbackHandler.setClientName(clientName);
callbackHandler.setMqttClient(mqttClient);
callbackHandler.setMessageProcessor(messageProcessor);
mqttClient.setCallback(callbackHandler);
// 配置连接选项
MqttConnectOptions options = createConnectOptions(config);
// 连接
mqttClient.connect(options);
log.info("MQTT 客户端 [{}] 连接成功!", clientName);
// 存储到Map
clientMap.put(clientName, mqttClient);
callbackMap.put(clientName, callbackHandler);
// 订阅主题
subscribeTopics(clientName, mqttClient, config);
}
/**
* 创建连接选项
*/
private MqttConnectOptions createConnectOptions(MqttProperties.MqttClientConfig config) {
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(config.getClient().getCleanSession());
options.setConnectionTimeout(config.getConnection().getTimeout());
options.setKeepAliveInterval(config.getConnection().getKeepAlive());
if (config.getConnection().getAutomaticReconnect() != null) {
options.setAutomaticReconnect(config.getConnection().getAutomaticReconnect());
}
if (config.getAuth().getUsername() != null) {
options.setUserName(config.getAuth().getUsername());
options.setPassword(config.getAuth().getPassword().toCharArray());
}
return options;
}
/**
* 订阅主题
*/
private void subscribeTopics(String clientName, MqttClient mqttClient,
MqttProperties.MqttClientConfig config) {
try {
// 查询所有需要订阅的mqtt主题
List<String> urlList = deviceService.getAllMqttTopic(clientName);
urlList = urlList.stream()
.distinct()
.collect(Collectors.toList());
for (String url : urlList) {
mqttClient.subscribe(url, config.getQos());
}
log.info("MQTT 客户端 [{}] 订阅主题成功topic{}",
clientName, String.join(",", urlList));
} catch (MqttException e) {
log.error("MQTT 客户端 [{}] 订阅主题失败", clientName, e);
}
}
/**
* 获取指定名称的MQTT客户端
*/
public MqttClient getClient(String name) {
return clientMap.get(name);
}
/**
* 获取默认MQTT客户端
*/
public MqttClient getDefaultClient() {
String defaultClient = mqttProperties.getDefaultClient();
if (defaultClient != null && clientMap.containsKey(defaultClient)) {
return clientMap.get(defaultClient);
}
// 如果没有指定默认客户端返回第一个
if (!clientMap.isEmpty()) {
return clientMap.values().iterator().next();
}
return null;
}
/**
* 获取所有客户端名称
*/
public List<String> getAllClientNames() {
return Collections.unmodifiableList(new ArrayList<>(clientMap.keySet()));
}
/**
* 检查指定客户端是否连接
*/
public boolean isConnected(String name) {
MqttClient client = clientMap.get(name);
return client != null && client.isConnected();
}
/**
* 检查默认客户端是否连接
*/
public boolean isDefaultConnected() {
MqttClient client = getDefaultClient();
return client != null && client.isConnected();
}
/**
* 获取指定客户端的配置
*/
public MqttProperties.MqttClientConfig getClientConfig(String name) {
return mqttProperties.getClients().stream()
.filter(c -> name.equals(c.getName()))
.findFirst()
.orElse(null);
}
/**
* 断开所有连接
*/
@PreDestroy
public void destroy() {
for (Map.Entry<String, MqttClient> entry : clientMap.entrySet()) {
MqttClient client = entry.getValue();
if (client != null && client.isConnected()) {
try {
client.disconnect();
log.info("MQTT 客户端 [{}] 已断开连接", entry.getKey());
} catch (MqttException e) {
log.error("断开 MQTT 客户端 [{}] 连接失败", entry.getKey(), e);
}
}
}
clientMap.clear();
callbackMap.clear();
}
}

View File

@ -1,23 +1,12 @@
package com.lanhai.mqtt.config; package com.lanhai.mqtt.config;
import com.lanhai.mqtt.handler.MqttCallbackHandler;
import com.lanhai.service.ISurvIotVirtualDeviceService; import com.lanhai.service.ISurvIotVirtualDeviceService;
import com.lanhai.service.Impl.SurvIotVirtualDeviceServiceImpl;
import com.lanhai.util.SpringContextUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import javax.annotation.PreDestroy; import javax.annotation.PostConstruct;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j @Slf4j
@Configuration @Configuration
@ -25,123 +14,11 @@ import java.util.stream.Collectors;
@ConditionalOnProperty(prefix = "mqtt", name = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = "mqtt", name = "enabled", havingValue = "true")
public class MqttConfig { public class MqttConfig {
private final MqttProperties mqttProperties; private final MqttClientManager mqttClientManager;
private final MqttCallbackHandler mqttCallbackHandler; // 这里注入
private MqttClient mqttClient;
private final ISurvIotVirtualDeviceService deviceService;
@PostConstruct
@Bean public void init() {
public MqttClient mqttClient() { log.info("========== MQTT 配置初始化 ==========");
try { mqttClientManager.init();
log.info("========== 初始化 MQTT 客户端 ==========");
// 1. 创建客户端
mqttClient = new MqttClient(
mqttProperties.getBroker().getUrl(),
mqttProperties.getClient().getId(),
new MemoryPersistence()
);
// 2. MqttClient 注入到 CallbackHandler
mqttCallbackHandler.setMqttClient(mqttClient);
// 3. 设置回调
mqttClient.setCallback(mqttCallbackHandler);
// 4. 配置连接选项
MqttConnectOptions options = createConnectOptions();
// 5. 连接
mqttClient.connect(options);
log.info("MQTT 连接成功!");
// 6. 订阅主题
subscribeTopics();
return mqttClient;
} catch (MqttException e) {
log.error("MQTT 连接失败", e);
throw new RuntimeException("MQTT 连接失败", e);
}
}
private void subscribeTopics() {
try {
// // 订阅接收主题
// if (mqttProperties.getTopics().getReceive() != null) {
// mqttClient.subscribe(
// mqttProperties.getTopics().getReceive(),
// mqttProperties.getQos()
// );
// log.info("订阅主题: {}", mqttProperties.getTopics().getReceive());
// }
//
// // 订阅状态主题
// if (mqttProperties.getTopics().getStatus() != null) {
// mqttClient.subscribe(
// mqttProperties.getTopics().getStatus(),
// mqttProperties.getQos()
// );
// log.info("订阅主题: {}", mqttProperties.getTopics().getStatus());
// }
//
// // 订阅设备通配符主题
// if (mqttProperties.getTopics().getDevice() != null) {
// mqttClient.subscribe(
// mqttProperties.getTopics().getDevice(),
// mqttProperties.getQos()
// );
// log.info("订阅通配符主题: {}", mqttProperties.getTopics().getDevice());
// }
//查询所有需要订阅的mqtt主题
List<String> urlList = deviceService.getAllMqttTopic();
//去重
urlList = urlList.stream()
.distinct()
.collect(Collectors.toList());
for (String url : urlList) {//共享主题语法
mqttClient.subscribe(
url,
mqttProperties.getQos()
);
}
log.error("== MyMqttCallback ==> 订阅主题成功topic{}", String.join(",", urlList));
} catch (MqttException e) {
log.error("订阅主题失败", e);
}
}
private MqttConnectOptions createConnectOptions() {
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(mqttProperties.getClient().getCleanSession());
options.setConnectionTimeout(mqttProperties.getConnection().getTimeout());
options.setKeepAliveInterval(mqttProperties.getConnection().getKeepAlive());
if (mqttProperties.getConnection().getAutomaticReconnect() != null) {
options.setAutomaticReconnect(mqttProperties.getConnection().getAutomaticReconnect());
}
if (mqttProperties.getAuth().getUsername() != null) {
options.setUserName(mqttProperties.getAuth().getUsername());
options.setPassword(mqttProperties.getAuth().getPassword().toCharArray());
}
return options;
}
@PreDestroy
public void destroy() {
if (mqttClient != null && mqttClient.isConnected()) {
try {
mqttClient.disconnect();
log.info("MQTT 客户端已断开连接");
} catch (MqttException e) {
log.error("断开 MQTT 连接失败", e);
}
}
} }
} }

View File

@ -4,18 +4,62 @@ import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Data @Data
@Component @Component
@ConfigurationProperties(prefix = "mqtt") @ConfigurationProperties(prefix = "mqtt")
public class MqttProperties { public class MqttProperties {
private Boolean enabled; private Boolean enabled;
/**
* 默认客户端向后兼容单连接配置
*/
private String defaultClient;
/**
* 多客户端配置列表
*/
private List<MqttClientConfig> clients = new ArrayList<>();
@Data
public static class MqttClientConfig {
/**
* 客户端名称用于区分不同连接
*/
private String name;
/**
* 是否启用
*/
private Boolean enabled = true;
/**
* Broker配置
*/
private Broker broker = new Broker(); private Broker broker = new Broker();
/**
* Client配置
*/
private Client client = new Client(); private Client client = new Client();
/**
* Connection配置
*/
private Connection connection = new Connection(); private Connection connection = new Connection();
/**
* Auth配置
*/
private Auth auth = new Auth(); private Auth auth = new Auth();
/**
* Topics配置
*/
private Topics topics = new Topics(); private Topics topics = new Topics();
private Integer qos; /**
private Boolean retained; * QoS
*/
private Integer qos = 1;
/**
* Retained
*/
private Boolean retained = false;
}
@Data @Data
public static class Broker { public static class Broker {

View File

@ -6,27 +6,33 @@ import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
@Slf4j @Slf4j
@Component
public class MqttCallbackHandler implements MqttCallback { public class MqttCallbackHandler implements MqttCallback {
private final MessageProcessor messageProcessor; private MessageProcessor messageProcessor;
private MqttClient mqttClient; // 改为 Setter 注入 private MqttClient mqttClient;
private String clientName;
public MqttCallbackHandler() {
}
public MqttCallbackHandler(MessageProcessor messageProcessor) { public MqttCallbackHandler(MessageProcessor messageProcessor) {
this.messageProcessor = messageProcessor; this.messageProcessor = messageProcessor;
} }
/** public void setMessageProcessor(MessageProcessor messageProcessor) {
* 通过 Setter 注入 MqttClient避免循环依赖 this.messageProcessor = messageProcessor;
*/ }
public void setMqttClient(MqttClient mqttClient) { public void setMqttClient(MqttClient mqttClient) {
this.mqttClient = mqttClient; this.mqttClient = mqttClient;
log.info("MqttClient 已注入到 CallbackHandler"); }
public void setClientName(String clientName) {
this.clientName = clientName;
} }
@PostConstruct @PostConstruct
@ -36,26 +42,30 @@ public class MqttCallbackHandler implements MqttCallback {
@Override @Override
public void connectionLost(Throwable cause) { public void connectionLost(Throwable cause) {
log.error("MQTT 连接丢失,原因: {}", cause.getMessage(), cause); log.error("MQTT 客户端 [{}] 连接丢失,原因: {}",
clientName, cause.getMessage(), cause);
if (mqttClient != null && !mqttClient.isConnected()) { if (mqttClient != null && !mqttClient.isConnected()) {
log.info("等待客户端自动重连..."); log.info("MQTT 客户端 [{}] 等待自动重连...", clientName);
} }
} }
@Override @Override
public void messageArrived(String topic, MqttMessage message) throws Exception { public void messageArrived(String topic, MqttMessage message) throws Exception {
String payload = new String(message.getPayload()); String payload = new String(message.getPayload());
log.info("收到消息 - 主题: {}, QoS: {}", topic, message.getQos()); log.info("MQTT 客户端 [{}] 收到消息 - 主题: {}, QoS: {}",
clientName, topic, message.getQos());
// 异步处理消息 if (messageProcessor != null) {
messageProcessor.processAsync(topic, payload); messageProcessor.processAsync(clientName,topic, payload);
}
} }
@Override @Override
public void deliveryComplete(IMqttDeliveryToken token) { public void deliveryComplete(IMqttDeliveryToken token) {
try { try {
log.debug("消息发送完成 - Message ID: {}", token.getMessageId()); log.debug("MQTT 客户端 [{}] 消息发送完成 - Message ID: {}",
clientName, token.getMessageId());
} catch (Exception e) { } catch (Exception e) {
log.error("处理消息发送完成回调失败", e); log.error("处理消息发送完成回调失败", e);
} }

View File

@ -1,6 +1,8 @@
package com.lanhai.mqtt.listener; package com.lanhai.mqtt.listener;
import com.lanhai.mqtt.config.MqttClientManager;
import com.lanhai.mqtt.config.MqttProperties; import com.lanhai.mqtt.config.MqttProperties;
import com.lanhai.service.ISurvIotVirtualDeviceService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttClient;
@ -15,6 +17,9 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@Slf4j @Slf4j
@ -24,11 +29,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
@ConditionalOnProperty(prefix = "mqtt", name = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = "mqtt", name = "enabled", havingValue = "true")
public class MqttReconnectListener { public class MqttReconnectListener {
private final MqttClient mqttClient; private final MqttClientManager mqttClientManager;
private final MqttProperties mqttProperties; private final MqttProperties mqttProperties;
private final ISurvIotVirtualDeviceService deviceService;
// 每个客户端独立的重连状态
private final Map<String, AtomicBoolean> reconnectingMap = new ConcurrentHashMap<>();
private final Map<String, Integer> reconnectCountMap = new ConcurrentHashMap<>();
private AtomicBoolean isReconnecting = new AtomicBoolean(false);
private int reconnectCount = 0;
private static final int MAX_RECONNECT_COUNT = 5; private static final int MAX_RECONNECT_COUNT = 5;
private static final long RECONNECT_INTERVAL = 30000; // 30秒 private static final long RECONNECT_INTERVAL = 30000; // 30秒
@ -39,140 +47,160 @@ public class MqttReconnectListener {
@EventListener(ContextRefreshedEvent.class) @EventListener(ContextRefreshedEvent.class)
public void onApplicationReady() { public void onApplicationReady() {
log.info("应用启动完成MQTT 连接状态: {}", mqttClient.isConnected()); List<String> clientNames = mqttClientManager.getAllClientNames();
for (String name : clientNames) {
log.info("MQTT 客户端 [{}] 连接状态: {}", name, mqttClientManager.isConnected(name));
}
} }
/** /**
* 定时检查连接状态并重连 * 定时检查所有客户端连接状态并重连
*/ */
@Scheduled(fixedDelay = 10000) // 每10秒检查一次 @Scheduled(fixedDelay = 10000) // 每10秒检查一次
public void checkAndReconnect() { public void checkAndReconnect() {
List<String> clientNames = mqttClientManager.getAllClientNames();
for (String clientName : clientNames) {
MqttClient client = mqttClientManager.getClient(clientName);
if (client == null) continue;
// 如果已经连接重置重连计数 // 如果已经连接重置重连计数
if (mqttClient.isConnected()) { if (client.isConnected()) {
if (reconnectCount > 0) { Integer count = reconnectCountMap.get(clientName);
log.info("MQTT 连接已恢复,重置重连计数器"); if (count != null && count > 0) {
reconnectCount = 0; log.info("MQTT 客户端 [{}] 连接已恢复,重置重连计数器", clientName);
isReconnecting.set(false); reconnectCountMap.put(clientName, 0);
reconnectingMap.put(clientName, new AtomicBoolean(false));
} }
return; continue;
} }
// 如果正在重连跳过 // 如果正在重连跳过
AtomicBoolean isReconnecting = reconnectingMap.computeIfAbsent(clientName, k -> new AtomicBoolean(false));
if (isReconnecting.get()) { if (isReconnecting.get()) {
return; continue;
} }
// 检查重连次数 // 检查重连次数
int reconnectCount = reconnectCountMap.getOrDefault(clientName, 0);
if (reconnectCount >= MAX_RECONNECT_COUNT) { if (reconnectCount >= MAX_RECONNECT_COUNT) {
log.error("MQTT 重连失败次数已达上限 ({}),停止重连", MAX_RECONNECT_COUNT); log.error("MQTT 客户端 [{}] 重连失败次数已达上限 ({}),停止重连", clientName, MAX_RECONNECT_COUNT);
return; continue;
} }
// 执行重连 // 执行重连
attemptReconnect(); attemptReconnect(clientName);
}
} }
@Async @Async
public void attemptReconnect() { public void attemptReconnect(String clientName) {
AtomicBoolean isReconnecting = reconnectingMap.computeIfAbsent(clientName, k -> new AtomicBoolean(false));
if (!isReconnecting.compareAndSet(false, true)) { if (!isReconnecting.compareAndSet(false, true)) {
return; return;
} }
try { try {
reconnectCount++; int reconnectCount = reconnectCountMap.getOrDefault(clientName, 0) + 1;
log.info("尝试重连 MQTT (第 {}/{} 次)...", reconnectCount, MAX_RECONNECT_COUNT); reconnectCountMap.put(clientName, reconnectCount);
log.info("尝试重连 MQTT 客户端 [{}] (第 {}/{} 次)...", clientName, reconnectCount, MAX_RECONNECT_COUNT);
// 等待一段时间再重连 // 等待一段时间再重连
Thread.sleep(RECONNECT_INTERVAL); Thread.sleep(RECONNECT_INTERVAL);
// 重新连接 MqttClient client = mqttClientManager.getClient(clientName);
if (!mqttClient.isConnected()) { if (client != null && !client.isConnected()) {
MqttConnectOptions options = createConnectOptions(); MqttProperties.MqttClientConfig config = mqttClientManager.getClientConfig(clientName);
mqttClient.connect(options); if (config == null) {
log.info("MQTT 重连成功!"); log.error("MQTT 客户端 [{}] 配置不存在", clientName);
return;
}
MqttConnectOptions options = createConnectOptions(config);
client.connect(options);
log.info("MQTT 客户端 [{}] 重连成功!", clientName);
// 重连成功后重新订阅主题 // 重连成功后重新订阅主题
resubscribeTopics(); resubscribeTopics(clientName, client, config);
// 重置重连计数 // 重置重连计数
reconnectCount = 0; reconnectCountMap.put(clientName, 0);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
log.warn("重连被中断"); log.warn("MQTT 客户端 [{}] 重连被中断", clientName);
} catch (MqttException e) { } catch (MqttException e) {
log.error("MQTT 重连失败", e); log.error("MQTT 客户端 [{}] 重连失败", clientName, e);
// 如果重连次数达到上限发送告警 int reconnectCount = reconnectCountMap.getOrDefault(clientName, 0);
if (reconnectCount >= MAX_RECONNECT_COUNT) { if (reconnectCount >= MAX_RECONNECT_COUNT) {
sendReconnectAlert(); sendReconnectAlert(clientName);
} }
} finally { } finally {
isReconnecting.set(false); isReconnecting.set(false);
} }
} }
private MqttConnectOptions createConnectOptions() { private MqttConnectOptions createConnectOptions(MqttProperties.MqttClientConfig config) {
MqttConnectOptions options = new MqttConnectOptions(); MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(mqttProperties.getClient().getCleanSession()); options.setCleanSession(config.getClient().getCleanSession());
options.setConnectionTimeout(mqttProperties.getConnection().getTimeout()); options.setConnectionTimeout(config.getConnection().getTimeout());
options.setKeepAliveInterval(mqttProperties.getConnection().getKeepAlive()); options.setKeepAliveInterval(config.getConnection().getKeepAlive());
if (mqttProperties.getAuth().getUsername() != null) { if (config.getConnection().getAutomaticReconnect() != null) {
options.setUserName(mqttProperties.getAuth().getUsername()); options.setAutomaticReconnect(config.getConnection().getAutomaticReconnect());
options.setPassword(mqttProperties.getAuth().getPassword().toCharArray()); }
if (config.getAuth().getUsername() != null) {
options.setUserName(config.getAuth().getUsername());
options.setPassword(config.getAuth().getPassword().toCharArray());
} }
return options; return options;
} }
private void resubscribeTopics() { private void resubscribeTopics(String clientName, MqttClient client, MqttProperties.MqttClientConfig config) {
try { try {
log.info("重新订阅主题..."); log.info("MQTT 客户端 [{}] 重新订阅主题...", clientName);
if (mqttProperties.getTopics().getReceive() != null) { // 查询所有需要订阅的主题
mqttClient.subscribe(mqttProperties.getTopics().getReceive(), List<String> urlList = deviceService.getAllMqttTopic(clientName);
mqttProperties.getQos()); urlList = urlList.stream().distinct().collect(java.util.stream.Collectors.toList());
log.info("重新订阅: {}", mqttProperties.getTopics().getReceive());
}
if (mqttProperties.getTopics().getStatus() != null) { for (String url : urlList) {
mqttClient.subscribe(mqttProperties.getTopics().getStatus(), client.subscribe(url, config.getQos());
mqttProperties.getQos());
log.info("重新订阅: {}", mqttProperties.getTopics().getStatus());
}
if (mqttProperties.getTopics().getDevice() != null) {
mqttClient.subscribe(mqttProperties.getTopics().getDevice(),
mqttProperties.getQos());
log.info("重新订阅: {}", mqttProperties.getTopics().getDevice());
} }
// 发送上线消息 // 发送上线消息
if (mqttProperties.getTopics().getStatus() != null) { if (config.getTopics() != null && config.getTopics().getStatus() != null) {
mqttClient.publish( client.publish(
mqttProperties.getTopics().getStatus(), config.getTopics().getStatus(),
"online".getBytes(), "online".getBytes(),
mqttProperties.getQos(), config.getQos(),
true true
); );
log.info("已发送上线状态"); log.info("MQTT 客户端 [{}] 已发送上线状态", clientName);
} }
log.info("MQTT 客户端 [{}] 重新订阅主题成功topic{}", clientName, String.join(",", urlList));
} catch (MqttException e) { } catch (MqttException e) {
log.error("重新订阅主题失败", e); log.error("MQTT 客户端 [{}] 重新订阅主题失败", clientName, e);
} }
} }
private void sendReconnectAlert() { private void sendReconnectAlert(String clientName) {
MqttProperties.MqttClientConfig config = mqttClientManager.getClientConfig(clientName);
log.error("========== MQTT 重连告警 =========="); log.error("========== MQTT 重连告警 ==========");
log.error("MQTT 服务器: {}", mqttProperties.getBroker().getUrl()); log.error("MQTT 客户端: {}", clientName);
if (config != null) {
log.error("MQTT 服务器: {}", config.getBroker().getUrl());
}
log.error("重连失败次数: {}", MAX_RECONNECT_COUNT); log.error("重连失败次数: {}", MAX_RECONNECT_COUNT);
log.error("请检查 MQTT 服务器状态和网络连接"); log.error("请检查 MQTT 服务器状态和网络连接");
log.error("=================================="); log.error("==================================");
// 这里可以添加告警通知如发送邮件短信等 // 这里可以添加告警通知如发送邮件短信等
// emailService.sendAlert("MQTT连接失败"); // emailService.sendAlert("MQTT连接失败: " + clientName);
} }
} }

View File

@ -25,19 +25,19 @@ public class MessageProcessor {
/** /**
* 同步处理消息 * 同步处理消息
*/ */
public void process(String topic, String payload) { public void process(String clientName,String topic, String payload) {
log.debug("处理消息 - 主题: {}, 负载: {}", topic, payload); log.debug("处理消息 - 客户端: {}, 主题: {}, 负载: {}", clientName, topic, payload);
try { try {
// 根据主题选择处理器 // 根据主题选择处理器
MessageHandler handler = findHandler(topic); MessageHandler handler = findHandler(topic);
if (handler != null) { if (handler != null) {
handler.handle(topic, payload); handler.handle(clientName,topic, payload);
} else { } else {
handleDefault(topic, payload); handleDefault(clientName,topic, payload);
} }
} catch (Exception e) { } catch (Exception e) {
log.error("处理消息失败", e); log.error("处理消息失败:{},主题:{},内容:{}",clientName,topic,payload);
} }
} }
@ -45,8 +45,8 @@ public class MessageProcessor {
* 异步处理消息 * 异步处理消息
*/ */
@Async @Async
public void processAsync(String topic, String payload) { public void processAsync(String clientName,String topic, String payload) {
process(topic, payload); process(clientName,topic, payload);
} }
/** /**
@ -91,8 +91,8 @@ public class MessageProcessor {
/** /**
* 处理默认消息 * 处理默认消息
*/ */
private void handleDefault(String topic, String payload) { private void handleDefault(String clientName,String topic, String payload) {
log.info("默认处理 - 主题: {}, 消息: {}", topic, payload); log.info("默认处理 - 客户端: {}, 主题: {}, 消息: {}", clientName, topic, payload);
// 可以根据需要存储到数据库或转发到其他系统 // 可以根据需要存储到数据库或转发到其他系统
// 例如: saveToDatabase(topic, payload); // 例如: saveToDatabase(topic, payload);
} }
@ -119,6 +119,10 @@ public class MessageProcessor {
return this::handleDeviceRep; return this::handleDeviceRep;
} }
if (topic.startsWith(IotInerfaceTopicType.RENKE_TOPIC.getCode())) {
return this::handleRenkeDeviceRep;
}
// // 设备状态主题 // // 设备状态主题
// if (topic.contains("/device/") && topic.endsWith("/status")) { // if (topic.contains("/device/") && topic.endsWith("/status")) {
// return this::handleDeviceStatus; // return this::handleDeviceStatus;
@ -164,14 +168,22 @@ public class MessageProcessor {
@FunctionalInterface @FunctionalInterface
public interface MessageHandler { public interface MessageHandler {
void handle(String topic, String payload); void handle(String clientName,String topic, String payload);
} }
/** /**
* 处理设备监测回执消息 * 处理设备监测回执消息
*/ */
private void handleDeviceRep(String topic, String payload) { private void handleDeviceRep(String clientName,String topic, String payload) {
commonService.processMqttData(topic,payload); commonService.processMqttData(clientName,topic,payload);
}
/**
* 处理仁科设备监测回执消息
*/
private void handleRenkeDeviceRep(String clientName,String topic, String payload) {
commonService.processRenkeMqttData(clientName,topic,payload);
} }
} }

View File

@ -2,6 +2,7 @@ package com.lanhai.mqtt.service;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.lanhai.mqtt.config.MqttClientManager;
import com.lanhai.mqtt.config.MqttProperties; import com.lanhai.mqtt.config.MqttProperties;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -20,23 +21,55 @@ import java.util.concurrent.CompletableFuture;
@RequiredArgsConstructor @RequiredArgsConstructor
public class MqttService { public class MqttService {
private final MqttClient mqttClient; private final MqttClientManager mqttClientManager;
private final MqttProperties mqttProperties; private final MqttProperties mqttProperties;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
/** /**
* 发送消息 * 发送消息使用默认客户端
*/ */
public boolean sendMessage(String topic, String payload) { public boolean sendMessage(String topic, String payload) {
return sendMessage(topic, payload, mqttProperties.getQos(), mqttProperties.getRetained()); return sendMessage(null, topic, payload);
} }
/** /**
* 发送消息自定义QoS * 指定客户端发送消息
*/
public boolean sendMessage(String clientName, String topic, String payload) {
MqttClient client = getClient(clientName);
if (client == null) {
log.warn("MQTT 客户端 [{}] 不存在", clientName != null ? clientName : "默认");
return false;
}
MqttProperties.MqttClientConfig config = getClientConfig(clientName);
int qos = config != null && config.getQos() != null ? config.getQos() : 1;
boolean retained = config != null && config.getRetained() != null ? config.getRetained() : false;
return doSendMessage(client, topic, payload, qos, retained);
}
/**
* 发送消息自定义QoS使用默认客户端
*/ */
public boolean sendMessage(String topic, String payload, int qos, boolean retained) { public boolean sendMessage(String topic, String payload, int qos, boolean retained) {
return sendMessage(null, topic, payload, qos, retained);
}
/**
* 指定客户端发送消息自定义QoS
*/
public boolean sendMessage(String clientName, String topic, String payload, int qos, boolean retained) {
MqttClient client = getClient(clientName);
if (client == null) {
return false;
}
return doSendMessage(client, topic, payload, qos, retained);
}
private boolean doSendMessage(MqttClient client, String topic, String payload, int qos, boolean retained) {
try { try {
if (!mqttClient.isConnected()) { if (!client.isConnected()) {
log.warn("MQTT 未连接,消息发送失败: {}", payload); log.warn("MQTT 未连接,消息发送失败: {}", payload);
return false; return false;
} }
@ -46,7 +79,7 @@ public class MqttService {
message.setRetained(retained); message.setRetained(retained);
message.setId((int) (System.currentTimeMillis() % 100000)); message.setId((int) (System.currentTimeMillis() % 100000));
mqttClient.publish(topic, message); client.publish(topic, message);
log.debug("消息发送成功 - 主题: {}, QoS: {}, 消息: {}", topic, qos, log.debug("消息发送成功 - 主题: {}, QoS: {}, 消息: {}", topic, qos,
payload.length() > 100 ? payload.substring(0, 100) + "..." : payload); payload.length() > 100 ? payload.substring(0, 100) + "..." : payload);
return true; return true;
@ -58,12 +91,19 @@ public class MqttService {
} }
/** /**
* 发送 JSON 消息 * 发送 JSON 消息使用默认客户端
*/ */
public boolean sendJsonMessage(String topic, Object data) { public boolean sendJsonMessage(String topic, Object data) {
return sendJsonMessage(null, topic, data);
}
/**
* 指定客户端发送 JSON 消息
*/
public boolean sendJsonMessage(String clientName, String topic, Object data) {
try { try {
String json = objectMapper.writeValueAsString(data); String json = objectMapper.writeValueAsString(data);
return sendMessage(topic, json); return sendMessage(clientName, topic, json);
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
log.error("JSON 序列化失败", e); log.error("JSON 序列化失败", e);
return false; return false;
@ -71,16 +111,30 @@ public class MqttService {
} }
/** /**
* 异步发送消息 * 异步发送消息使用默认客户端
*/ */
public CompletableFuture<Boolean> sendMessageAsync(String topic, String payload) { public CompletableFuture<Boolean> sendMessageAsync(String topic, String payload) {
return CompletableFuture.supplyAsync(() -> sendMessage(topic, payload)); return sendMessageAsync(null, topic, payload);
} }
/** /**
* 发送设备控制指令 * 指定客户端异步发送消息
*/
public CompletableFuture<Boolean> sendMessageAsync(String clientName, String topic, String payload) {
return CompletableFuture.supplyAsync(() -> sendMessage(clientName, topic, payload));
}
/**
* 发送设备控制指令使用默认客户端
*/ */
public boolean sendDeviceCommand(String deviceId, String command, Object params) { public boolean sendDeviceCommand(String deviceId, String command, Object params) {
return sendDeviceCommand(null, deviceId, command, params);
}
/**
* 指定客户端发送设备控制指令
*/
public boolean sendDeviceCommand(String clientName, String deviceId, String command, Object params) {
String topic = String.format("lanhai/device/%s/command", deviceId); String topic = String.format("lanhai/device/%s/command", deviceId);
try { try {
@ -90,7 +144,7 @@ public class MqttService {
message.put("timestamp", System.currentTimeMillis()); message.put("timestamp", System.currentTimeMillis());
message.put("requestId", UUID.randomUUID().toString()); message.put("requestId", UUID.randomUUID().toString());
return sendJsonMessage(topic, message); return sendJsonMessage(clientName, topic, message);
} catch (Exception e) { } catch (Exception e) {
log.error("发送设备指令失败", e); log.error("发送设备指令失败", e);
return false; return false;
@ -98,12 +152,23 @@ public class MqttService {
} }
/** /**
* 订阅主题 * 订阅主题使用默认客户端
*/ */
public boolean subscribe(String topic, int qos) { public boolean subscribe(String topic, int qos) {
return subscribe(null, topic, qos);
}
/**
* 指定客户端订阅主题
*/
public boolean subscribe(String clientName, String topic, int qos) {
MqttClient client = getClient(clientName);
if (client == null) {
return false;
}
try { try {
mqttClient.subscribe(topic, qos); client.subscribe(topic, qos);
log.info("订阅主题: {}", topic); log.info("MQTT 客户端 [{}] 订阅主题: {}", clientName != null ? clientName : "默认", topic);
return true; return true;
} catch (MqttException e) { } catch (MqttException e) {
log.error("订阅失败", e); log.error("订阅失败", e);
@ -112,12 +177,23 @@ public class MqttService {
} }
/** /**
* 取消订阅 * 取消订阅使用默认客户端
*/ */
public boolean unsubscribe(String topic) { public boolean unsubscribe(String topic) {
return unsubscribe(null, topic);
}
/**
* 指定客户端取消订阅
*/
public boolean unsubscribe(String clientName, String topic) {
MqttClient client = getClient(clientName);
if (client == null) {
return false;
}
try { try {
mqttClient.unsubscribe(topic); client.unsubscribe(topic);
log.info("取消订阅: {}", topic); log.info("MQTT 客户端 [{}] 取消订阅: {}", clientName != null ? clientName : "默认", topic);
return true; return true;
} catch (MqttException e) { } catch (MqttException e) {
log.error("取消订阅失败", e); log.error("取消订阅失败", e);
@ -126,51 +202,117 @@ public class MqttService {
} }
/** /**
* 检查连接状态 * 检查默认客户端连接状态
*/ */
public boolean isConnected() { public boolean isConnected() {
return mqttClient.isConnected(); return mqttClientManager.isDefaultConnected();
} }
/** /**
* 获取客户端ID * 检查指定客户端连接状态
*/
public boolean isConnected(String clientName) {
return mqttClientManager.isConnected(clientName);
}
/**
* 获取默认客户端ID
*/ */
public String getClientId() { public String getClientId() {
return mqttProperties.getClient().getId(); MqttProperties.MqttClientConfig config = getClientConfig(null);
return config != null && config.getClient() != null ? config.getClient().getId() : null;
} }
/** /**
* 手动重连 * 获取指定客户端ID
*/
public String getClientId(String clientName) {
MqttProperties.MqttClientConfig config = getClientConfig(clientName);
return config != null && config.getClient() != null ? config.getClient().getId() : null;
}
/**
* 手动重连默认客户端
*/ */
public boolean reconnect() { public boolean reconnect() {
return reconnect(null);
}
/**
* 手动重连指定客户端
*/
public boolean reconnect(String clientName) {
MqttClient client = getClient(clientName);
if (client == null) {
return false;
}
try { try {
if (!mqttClient.isConnected()) { if (!client.isConnected()) {
mqttClient.reconnect(); client.reconnect();
log.info("手动重连成功"); log.info("MQTT 客户端 [{}] 手动重连成功", clientName != null ? clientName : "默认");
return true; return true;
} }
return false; return false;
} catch (MqttException e) { } catch (MqttException e) {
log.error("手动重连失败", e); log.error("MQTT 客户端 [{}] 手动重连失败", clientName, e);
return false; return false;
} }
} }
/** /**
* 断开连接 * 断开默认客户端连接
*/ */
public void disconnect() { public void disconnect() {
try { disconnect(null);
if (mqttClient.isConnected()) {
// 发送离线状态
if (mqttProperties.getTopics().getStatus() != null) {
sendMessage(mqttProperties.getTopics().getStatus(), "offline", 1, true);
} }
mqttClient.disconnect();
log.info("MQTT 连接已断开"); /**
* 断开指定客户端连接
*/
public void disconnect(String clientName) {
MqttClient client = getClient(clientName);
if (client == null) {
return;
}
try {
if (client.isConnected()) {
MqttProperties.MqttClientConfig config = getClientConfig(clientName);
if (config != null && config.getTopics() != null && config.getTopics().getStatus() != null) {
sendMessage(clientName, config.getTopics().getStatus(), "offline", 1, true);
}
client.disconnect();
log.info("MQTT 客户端 [{}] 连接已断开", clientName != null ? clientName : "默认");
} }
} catch (MqttException e) { } catch (MqttException e) {
log.error("断开连接失败", e); log.error("断开连接失败", e);
} }
} }
/**
* 获取客户端
*/
private MqttClient getClient(String clientName) {
if (clientName == null || clientName.isEmpty()) {
return mqttClientManager.getDefaultClient();
}
return mqttClientManager.getClient(clientName);
}
/**
* 获取客户端配置
*/
private MqttProperties.MqttClientConfig getClientConfig(String clientName) {
if (clientName == null || clientName.isEmpty()) {
String defaultClient = mqttProperties.getDefaultClient();
if (defaultClient != null) {
return mqttClientManager.getClientConfig(defaultClient);
}
// 返回第一个配置
if (mqttProperties.getClients() != null && !mqttProperties.getClients().isEmpty()) {
return mqttProperties.getClients().get(0);
}
return null;
}
return mqttClientManager.getClientConfig(clientName);
}
} }

View File

@ -15,7 +15,7 @@ import java.util.List;
*/ */
public interface ISurvIotVirtualDeviceService extends IService<SurvIotVirtualDevice> { public interface ISurvIotVirtualDeviceService extends IService<SurvIotVirtualDevice> {
List<String> getAllMqttTopic(); List<String> getAllMqttTopic(String clientName);
void processPayLoad(String topic, byte[] payload); void processPayLoad(String topic, byte[] payload);
} }

View File

@ -9,8 +9,12 @@ import com.lanhai.constant.PollutionConstants;
import com.lanhai.entity.*; import com.lanhai.entity.*;
import com.lanhai.o.iot.lhiot.ResponseCmd; import com.lanhai.o.iot.lhiot.ResponseCmd;
import com.lanhai.o.iot.pbs.WaterCommonTransVo; import com.lanhai.o.iot.pbs.WaterCommonTransVo;
import com.lanhai.o.iot.renke.DataItem;
import com.lanhai.o.iot.renke.RegisterItem;
import com.lanhai.o.iot.renke.RenkeDataRealTimeDetail;
import com.lanhai.service.*; import com.lanhai.service.*;
import com.lanhai.util.LhIotUtil; import com.lanhai.util.LhIotUtil;
import com.lanhai.util.SdrkUtils;
import com.xxl.job.core.context.XxlJobHelper; import com.xxl.job.core.context.XxlJobHelper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -20,8 +24,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Date; import java.util.*;
import java.util.List;
/** /**
* 处理业务的服务 * 处理业务的服务
@ -107,14 +110,14 @@ public class CommonServiceImpl implements ICommonService {
} }
public void processMqttData(String topic,String mqttMessage) { public void processMqttData(String clientName,String topic,String mqttMessage) {
//1. 检查主题所属确定如何执行后续逻辑 //1. 检查主题所属确定如何执行后续逻辑
List<SurvDeviceDeploy> deployList = deviceDeployService.lambdaQuery() List<SurvDeviceDeploy> deployList = deviceDeployService.lambdaQuery()
.eq(SurvDeviceDeploy::getDeviceReverseIotUrl,topic) .eq(SurvDeviceDeploy::getDeviceReverseIotUrl,topic)
.list(); .list();
; ;
log.error("===================主题:{},设备数量:{}==============================",topic,deployList.size()); log.error("============客户端:{}=======主题:{},设备数量:{}==============================",clientName,topic,deployList.size());
XxlJobHelper.log("===================主题:{},设备数量:{}==============================",topic,deployList.size()); XxlJobHelper.log("============客户端:{}=======主题:{},设备数量:{}==============================",clientName,topic,deployList.size());
if(!deployList.isEmpty()){ if(!deployList.isEmpty()){
SurvDeviceDeploy survDeviceDeploy = deployList.get(0); SurvDeviceDeploy survDeviceDeploy = deployList.get(0);
@ -126,19 +129,20 @@ public class CommonServiceImpl implements ICommonService {
waterCommonTransVo = LhIotUtil.transData(zhibiaoList,mqttMessage); waterCommonTransVo = LhIotUtil.transData(zhibiaoList,mqttMessage);
break; break;
} }
log.error("----------------------查询到设备:{},回执:{}----------------------------",survDeviceDeploy.getId()+"_"+survDeviceDeploy.getDeployDes(), JSONUtil.toJsonStr(waterCommonTransVo)); log.error("------------客户端:{}----------查询到设备:{},回执:{}----------------------------",clientName,survDeviceDeploy.getId()+"_"+survDeviceDeploy.getDeployDes(), JSONUtil.toJsonStr(waterCommonTransVo));
XxlJobHelper.log("----------------------查询到设备:{},回执:{}----------------------------",survDeviceDeploy.getId()+"_"+survDeviceDeploy.getDeployDes(), JSONUtil.toJsonStr(waterCommonTransVo)); XxlJobHelper.log("-------------客户端:{}---------查询到设备:{},回执:{}----------------------------",clientName,survDeviceDeploy.getId()+"_"+survDeviceDeploy.getDeployDes(), JSONUtil.toJsonStr(waterCommonTransVo));
if(waterCommonTransVo!=null){ if(waterCommonTransVo!=null){
LocalDateTime nowTime =LocalDateTime.now(); LocalDateTime nowTime =LocalDateTime.now();
List<SurvDeviceDeploy> updateList = new ArrayList<>();
//遍历保存所有租户数据 //遍历保存所有租户数据
for (SurvDeviceDeploy deploy : deployList) { for (SurvDeviceDeploy deploy : deployList) {
log.error("###########################保存数据中-----设备:{}#####################################",deploy.getDeployCode()+"__"+deploy.getDeployDes()); log.error("#############客户端:{}##############保存数据中-----设备:{}#####################################",clientName,deploy.getDeployCode()+"__"+deploy.getDeployDes());
XxlJobHelper.log("###########################保存数据中-----设备:{}#####################################",deploy.getDeployCode()+"__"+deploy.getDeployDes()); XxlJobHelper.log("###############客户端:{}############保存数据中-----设备:{}#####################################",clientName,deploy.getDeployCode()+"__"+deploy.getDeployDes());
SurvStationInfo survStationInfo = survStationInfoService.getByCode(deploy.getStationCode()); SurvStationInfo survStationInfo = survStationInfoService.getByCode(deploy.getStationCode());
String stationName = survStationInfo!=null?survStationInfo.getStationName():"站点"; String stationName = survStationInfo!=null?survStationInfo.getStationName():"站点";
if(PollutionConstants.WATER_ORIENT.equals(deploy.getDeployType())){ if(PollutionConstants.WATER_ORIENT.equals(deploy.getDeployType())){
log.error("^^^^^^^^^^^^^^^^面源数据保存:{}^^^^^^^^^^^^^^^^^",deploy.getDeployCode()+"__"+deploy.getDeployDes()); log.error("^^^^^^^^^^客户端:{}^^^^^^面源数据保存:{}^^^^^^^^^^^^^^^^^",clientName,deploy.getDeployCode()+"__"+deploy.getDeployDes());
XxlJobHelper.log("^^^^^^^^^^^^^^^^面源数据保存:{}^^^^^^^^^^^^^^^^^",deploy.getDeployCode()+"__"+deploy.getDeployDes()); XxlJobHelper.log("^^^^^^^^^客户端:{}^^^^^^^面源数据保存:{}^^^^^^^^^^^^^^^^^",clientName,deploy.getDeployCode()+"__"+deploy.getDeployDes());
SurvTransdataOrientwater oldData = transdataOrientwaterService.getOneByDeviceId(deploy.getId()); SurvTransdataOrientwater oldData = transdataOrientwaterService.getOneByDeviceId(deploy.getId());
if(oldData!=null){ if(oldData!=null){
transdataOrientwaterService.removeById(oldData.getId()); transdataOrientwaterService.removeById(oldData.getId());
@ -151,7 +155,7 @@ public class CommonServiceImpl implements ICommonService {
orientwater.setStationName(stationName); orientwater.setStationName(stationName);
orientwater.setDeviceName(deploy.getDeployDes()); orientwater.setDeviceName(deploy.getDeployDes());
orientwater.setDeviceId(deploy.getId()); orientwater.setDeviceId(deploy.getId());
orientwater.setCreatedBy("task");//创建人 orientwater.setCreatedBy("lhmqtt");//创建人
orientwater.setCreateTime(nowTime);//创建时间 orientwater.setCreateTime(nowTime);//创建时间
orientwater.setStationId(survStationInfo.getId()); orientwater.setStationId(survStationInfo.getId());
orientwater.setDataType(deploy.getDeploySecondaryType()); orientwater.setDataType(deploy.getDeploySecondaryType());
@ -164,9 +168,11 @@ public class CommonServiceImpl implements ICommonService {
hisOrientWater.setTransDate(nowTime); hisOrientWater.setTransDate(nowTime);
hisdataOrientwaterService.save(hisOrientWater); hisdataOrientwaterService.save(hisOrientWater);
updateList.add(deploy);
} else if (PollutionConstants.WATER_LIVE.equals(deploy.getDeployType())) { } else if (PollutionConstants.WATER_LIVE.equals(deploy.getDeployType())) {
log.error("^^^^^^^^^^^^^^^^畜禽数据保存:{}^^^^^^^^^^^^^^^^^",deploy.getDeployCode()+"__"+deploy.getDeployDes()); log.error("^^^^^^^^^客户端:{}^^^^^^^畜禽数据保存:{}^^^^^^^^^^^^^^^^^",clientName,deploy.getDeployCode()+"__"+deploy.getDeployDes());
XxlJobHelper.log("^^^^^^^^^^^^^^^^畜禽数据保存:{}^^^^^^^^^^^^^^^^^",deploy.getDeployCode()+"__"+deploy.getDeployDes()); XxlJobHelper.log("^^^^^^^^客户端:{}^^^^^^^^畜禽数据保存:{}^^^^^^^^^^^^^^^^^",clientName,deploy.getDeployCode()+"__"+deploy.getDeployDes());
SurvTransdataLivestockwater oldData = transdataLivestockwaterService.getOneByDeviceId(deploy.getId()); SurvTransdataLivestockwater oldData = transdataLivestockwaterService.getOneByDeviceId(deploy.getId());
if(oldData!=null){ if(oldData!=null){
transdataLivestockwaterService.removeById(oldData.getId()); transdataLivestockwaterService.removeById(oldData.getId());
@ -179,7 +185,7 @@ public class CommonServiceImpl implements ICommonService {
livestockwater.setStationName(stationName); livestockwater.setStationName(stationName);
livestockwater.setDeviceName(deploy.getDeployDes()); livestockwater.setDeviceName(deploy.getDeployDes());
livestockwater.setDeviceId(deploy.getId()); livestockwater.setDeviceId(deploy.getId());
livestockwater.setCreatedBy("task");//创建人 livestockwater.setCreatedBy("lhmqtt");//创建人
livestockwater.setCreateTime(nowTime);//创建时间 livestockwater.setCreateTime(nowTime);//创建时间
livestockwater.setDataType(deploy.getDeploySecondaryType()); livestockwater.setDataType(deploy.getDeploySecondaryType());
livestockwater.setStationId(survStationInfo.getId()); livestockwater.setStationId(survStationInfo.getId());
@ -191,13 +197,27 @@ public class CommonServiceImpl implements ICommonService {
hisdataLivestockwater.setId(IdUtil.getSnowflakeNextIdStr()); hisdataLivestockwater.setId(IdUtil.getSnowflakeNextIdStr());
hisdataLivestockwater.setTransDate(nowTime); hisdataLivestockwater.setTransDate(nowTime);
hisdataLivestockwaterService.save(hisdataLivestockwater); hisdataLivestockwaterService.save(hisdataLivestockwater);
updateList.add(deploy);
} }
} }
if(!updateList.isEmpty()){//更新设备时间
List<SurvDeviceDeploy> upd = new ArrayList<>();
Date now = new Date();
for (SurvDeviceDeploy deviceDeploy : updateList) {
SurvDeviceDeploy ents = new SurvDeviceDeploy();
ents.setId(deviceDeploy.getId());
ents.setLastsyncTime(now);
upd.add(ents);
}
deviceDeployService.updateBatchById(upd);
}
}else{ }else{
log.error("主题:{}--消息:{},解析失败,任务中断。",topic,mqttMessage); log.error("客户端:{},主题:{}--消息:{},解析失败,任务中断。",clientName,topic,mqttMessage);
XxlJobHelper.log("主题:{}--消息:{},解析失败,任务中断。",topic,mqttMessage); XxlJobHelper.log("客户端:{},主题:{}--消息:{},解析失败,任务中断。",clientName,topic,mqttMessage);
} }
} }
@ -206,4 +226,82 @@ public class CommonServiceImpl implements ICommonService {
//2. 检查有 //2. 检查有
} }
public void processRenkeMqttData(String clientName,String topic,String mqttMessage) {
//1.数据过滤根据消息内的设备地址筛选出对应的设备
RenkeDataRealTimeDetail realTimeDetail = JSONUtil.toBean(mqttMessage,RenkeDataRealTimeDetail.class);
if(realTimeDetail!=null){
if(realTimeDetail.getDeviceAddr()!=null){
String deviceAddr = realTimeDetail.getDeviceAddr().toString();
//2. 匹配设备
List<SurvDeviceDeploy> deployList = deviceDeployService.lambdaQuery()
.in(SurvDeviceDeploy::getProtocolCode,IotConstants.renke_standard)
.eq(SurvDeviceDeploy::getDeployCode,deviceAddr)
.list();
;
log.error("============客户端:{}=======主题:{},设备号:{},设备数量:{}==============================",clientName,topic,deviceAddr,deployList.size());
if(!deployList.isEmpty()){
List<SurvDeviceDeploy> updateList = new ArrayList<>();
Map<String, SurvDeviceDeploy> deviceMap = new HashMap<>();
Map<String, List<SurvDeviceDeploy>> allDeviceMap = new HashMap<>();
Map<String,SurvDeviceDeploy> deviceDeployMap = new HashMap<>();
for (SurvDeviceDeploy singleDevice : deployList) {
SurvDeviceDeploy checkDeploy = deviceMap.get(singleDevice.getDeployCode());
Boolean checkResult = Boolean.TRUE;
List<SurvDeviceDeploy> codeDeviceLsit =allDeviceMap.get(singleDevice.getDeployCode());
deviceDeployMap.put(singleDevice.getDeployCode() + "_" + singleDevice.getDeployType(),singleDevice);
if(codeDeviceLsit==null){
codeDeviceLsit = new ArrayList<>();
}
codeDeviceLsit.add(singleDevice);
allDeviceMap.put(singleDevice.getDeployCode(),codeDeviceLsit);
if (checkDeploy != null) {
log.error("发现重复设备,编号:{},已有类型:{},现类型:{}", singleDevice.getDeployCode(), checkDeploy.getDeployType(), singleDevice.getDeployType());
if (PollutionConstants.WATER_QULITY.equals(checkDeploy.getDeployType())) {//如果Map中已有水类型同编号的设备则不进行替换
checkResult = Boolean.FALSE;
}
}
if (checkResult) {//无异常则进行替换或保存
deviceMap.put(singleDevice.getDeployCode(), singleDevice);
}
}
for (Map.Entry<String, SurvDeviceDeploy> deployEntry : deviceMap.entrySet()) {
SurvDeviceDeploy deploy = deployEntry.getValue();
List<RenkeDataRealTimeDetail> datas = new ArrayList<>();
datas.add(realTimeDetail);
boolean isOk = SdrkUtils.processMqttSurvData(deploy,allDeviceMap,deviceDeployMap,datas);
if(isOk) {
updateList.add(deploy);
}
}
if(!updateList.isEmpty()){//更新设备时间
List<SurvDeviceDeploy> upd = new ArrayList<>();
Date nowTime = new Date();
for(SurvDeviceDeploy deploy:updateList){
SurvDeviceDeploy ents = new SurvDeviceDeploy();
ents.setId(deploy.getId());
ents.setLastsyncTime(nowTime);
upd.add(ents);
}
deviceDeployService.updateBatchById(upd);
}
}
}
}else{
log.error("客户端:{},主题:{}--消息:{},解析失败,任务中断。",clientName,topic,mqttMessage);
}
}
} }

View File

@ -44,15 +44,32 @@ public class SurvIotVirtualDeviceServiceImpl extends ServiceImpl<SurvIotVirtualD
private SurvTransdataOrientwaterServiceImpl orientwaterService; private SurvTransdataOrientwaterServiceImpl orientwaterService;
@Autowired @Autowired
private SurvTransdataLivestockwaterServiceImpl livestockwaterService; private SurvTransdataLivestockwaterServiceImpl livestockwaterService;
@Autowired
private SurvConfigServiceImpl configService;
@Override @Override
public List<String> getAllMqttTopic() { public List<String> getAllMqttTopic(String clientName) {
List<String> topics = new ArrayList<>(); List<String> topics = new ArrayList<>();
//获取所有的mqtt连接配置
List<SurvConfig> configs = configService
.lambdaQuery()
.eq(SurvConfig::getIsDel,0)
.eq(SurvConfig::getConfigValueSe2, clientName)//匹配客户端名称
.eq(SurvConfig::getConfigSubType, IotConstants.CONFIG_TYPE_MQTT)
.list();
List<String> mqttConfigs = new ArrayList<>();
if(!configs.isEmpty()){
mqttConfigs = configs.stream().map(SurvConfig::getId).collect(Collectors.toList());
}
log.error("客户端:{}查询到已配置的mqtt配置:{}个",clientName,mqttConfigs.size());
//已部署设备中配置的主题 //已部署设备中配置的主题
List<SurvDeviceDeploy> deploys = deviceDeployService.lambdaQuery() List<SurvDeviceDeploy> deploys = deviceDeployService.lambdaQuery()
.eq(SurvDeviceDeploy::getIsDel,0) .eq(SurvDeviceDeploy::getIsDel,0)
.eq(SurvDeviceDeploy::getRunStatus,0) .eq(SurvDeviceDeploy::getRunStatus,0)
.eq(SurvDeviceDeploy::getProtocolType, IotProtocolType.MQTT.getCode()) // .eq(SurvDeviceDeploy::getProtocolType, IotProtocolType.MQTT.getCode())
.in(SurvDeviceDeploy::getSurvConfigId,mqttConfigs)
.list(); .list();
if(!deploys.isEmpty()){ if(!deploys.isEmpty()){
for (SurvDeviceDeploy deploy : deploys) { for (SurvDeviceDeploy deploy : deploys) {

View File

@ -142,6 +142,7 @@ public class SurvTransdataSoilServiceImpl extends ServiceImpl<SurvTransdataSoilM
BeanUtil.copyProperties(soil,hisdataSoil); BeanUtil.copyProperties(soil,hisdataSoil);
hisdataSoil.setId(IdUtil.getSnowflakeNextIdStr()); hisdataSoil.setId(IdUtil.getSnowflakeNextIdStr());
hisdataSoil.setCreateTime(nowTime); hisdataSoil.setCreateTime(nowTime);
hisdataSoil.setTransDate(nowTime);
hisdataSoilService.save(hisdataSoil); hisdataSoilService.save(hisdataSoil);
}else{ }else{
String dateStr = kDateTime!=null?DateUtil.format(kDateTime,"yyyy-MM-dd HH:mm:ss"):""; String dateStr = kDateTime!=null?DateUtil.format(kDateTime,"yyyy-MM-dd HH:mm:ss"):"";
@ -220,7 +221,6 @@ public class SurvTransdataSoilServiceImpl extends ServiceImpl<SurvTransdataSoilM
hisdataAir.setId(IdUtil.getSnowflakeNextIdStr()); hisdataAir.setId(IdUtil.getSnowflakeNextIdStr());
hisdataAir.setCreateTime(nowTime); hisdataAir.setCreateTime(nowTime);
hisdataAir.setTransDate(nowTime); hisdataAir.setTransDate(nowTime);
hisdataAir.setDataDateTime(nowTime);
hisdataAirService.save(hisdataAir); hisdataAirService.save(hisdataAir);
}else{ }else{
log.error("****** 跳过,数据日期为:{},已存在于空气历史表******",formatAirTime); log.error("****** 跳过,数据日期为:{},已存在于空气历史表******",formatAirTime);
@ -310,6 +310,7 @@ public class SurvTransdataSoilServiceImpl extends ServiceImpl<SurvTransdataSoilM
BeanUtil.copyProperties(soil,hisdataSoil); BeanUtil.copyProperties(soil,hisdataSoil);
hisdataSoil.setId(IdUtil.getSnowflakeNextIdStr()); hisdataSoil.setId(IdUtil.getSnowflakeNextIdStr());
hisdataSoil.setCreateTime(nowTime); hisdataSoil.setCreateTime(nowTime);
hisdataSoil.setTransDate(nowTime);
hisdataSoilService.save(hisdataSoil); hisdataSoilService.save(hisdataSoil);
}else{ }else{
String dateStr = kDateTime!=null?DateUtil.format(kDateTime,"yyyy-MM-dd HH:mm:ss"):""; String dateStr = kDateTime!=null?DateUtil.format(kDateTime,"yyyy-MM-dd HH:mm:ss"):"";
@ -387,6 +388,7 @@ public class SurvTransdataSoilServiceImpl extends ServiceImpl<SurvTransdataSoilM
BeanUtil.copyProperties(air,hisdataAir); BeanUtil.copyProperties(air,hisdataAir);
hisdataAir.setId(IdUtil.getSnowflakeNextIdStr()); hisdataAir.setId(IdUtil.getSnowflakeNextIdStr());
hisdataAir.setCreateTime(nowTime); hisdataAir.setCreateTime(nowTime);
hisdataAir.setTransDate(nowTime);
hisdataAirService.save(hisdataAir); hisdataAirService.save(hisdataAir);
}else{ }else{
String dateStr = airkDateTime!=null?DateUtil.format(airkDateTime,"yyyy-MM-dd HH:mm:ss"):""; String dateStr = airkDateTime!=null?DateUtil.format(airkDateTime,"yyyy-MM-dd HH:mm:ss"):"";

View File

@ -66,12 +66,12 @@ public class MultithreadTask {
deviceType.add(PollutionConstants.AIR_SURV); deviceType.add(PollutionConstants.AIR_SURV);
deviceType.add(PollutionConstants.SOIL_SURV); deviceType.add(PollutionConstants.SOIL_SURV);
deviceType.add(PollutionConstants.WATER_QULITY); deviceType.add(PollutionConstants.WATER_QULITY);
deviceType.add(PollutionConstants.FLOWMETER); // deviceType.add(PollutionConstants.FLOWMETER); 改用mqtt
List<String> protocolList = new ArrayList<String>(){ List<String> protocolList = new ArrayList<String>(){
{add(IotConstants.xph_v2); {add(IotConstants.xph_v2);
add(IotConstants.tuya_standard); add(IotConstants.tuya_standard);
add(IotConstants.renke_standard); // add(IotConstants.renke_standard); 改用mqtt
} }
}; };
List<SurvDeviceDeploy> deploys = deviceDeployService.getDeviceByType(protocolList,deviceType); List<SurvDeviceDeploy> deploys = deviceDeployService.getDeviceByType(protocolList,deviceType);

View File

@ -801,4 +801,58 @@ public class DateUtils extends PropertyEditorSupport {
public static long getDaysDiff(Date startDate, Date endDate) { public static long getDaysDiff(Date startDate, Date endDate) {
return getDateDiff(startDate, endDate, TimeUnit.DAYS); return getDateDiff(startDate, endDate, TimeUnit.DAYS);
} }
/**
* 计算目标时间相对于基准时间的秒数差并标明正负
*
* @param baseTime 基准时间相当于"当前时间"
* @param targetTime 目标时间
* @return 秒数正数表示 targetTime baseTime 之后未来
* 负数表示 targetTime baseTime 之前过去
* 0 表示两者相同或差值小于1秒
* @throws IllegalArgumentException 如果任一参数为 null
*/
public static long getSecondsBetween(Date baseTime, Date targetTime) {
if (baseTime == null || targetTime == null) {
throw new IllegalArgumentException("baseTime and targetTime cannot be null");
}
long diffMillis = targetTime.getTime() - baseTime.getTime();
return TimeUnit.MILLISECONDS.toSeconds(diffMillis);
}
/**
* 精确版本返回 double保留毫秒级精度
*
* @param baseTime 基准时间
* @param targetTime 目标时间
* @return 秒数double正数未来负数过去
*/
public static double getSecondsBetweenPrecise(Date baseTime, Date targetTime) {
if (baseTime == null || targetTime == null) {
throw new IllegalArgumentException("baseTime and targetTime cannot be null");
}
long diffMillis = targetTime.getTime() - baseTime.getTime();
return diffMillis / 1000.0;
}
/**
* 获取带正负号描述的字符串便于日志输出
*
* @param baseTime 基准时间
* @param targetTime 目标时间
* @return 描述字符串 "+30秒""-15秒""0秒"
*/
public static String getSecondsDesc(Date baseTime, Date targetTime) {
long seconds = getSecondsBetween(baseTime, targetTime);
if (seconds > 0) {
return "+" + seconds + "";
} else if (seconds < 0) {
return seconds + ""; // 已经是负号
} else {
return "0秒";
}
}
} }

View File

@ -20,6 +20,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import java.text.SimpleDateFormat;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
@ -68,6 +69,39 @@ public class SdrkUtils {
return b; return b;
} }
public static boolean processMqttSurvData(SurvDeviceDeploy deploy, Map<String, List<SurvDeviceDeploy>> allDeviceMap, Map<String, SurvDeviceDeploy> deviceDeployMap, List<RenkeDataRealTimeDetail> datas) {
List<SurvDeviceDeploy> allDeployList = allDeviceMap.get(deploy.getDeployCode());
deploy.setDeviceList(allDeployList);
log.error("========正在执行仁科mqtt=======,设备编号:{},类型:{}==========", deploy.getDeployCode(), deploy.getDeployType());
boolean b = false;
if(datas!=null){
if(!datas.isEmpty()){
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//此处至少有一条数据所以直接处理
for (SurvDeviceDeploy survDeviceDeploy : deploy.getDeviceList()) {
//校验设备上次数据时间超过3分钟才入库
if(survDeviceDeploy.getLastsyncTime() != null){
long seconds = DateUtils.getSecondsBetween(now,survDeviceDeploy.getLastsyncTime());
if(seconds>-180){//时间间隔小于3分钟跳过
log.error("=======跳过仁科mqtt数据设备号{}-{},上次数据时间:{}==========",deploy.getId(),deploy.getDeployCode(),sdf.format(survDeviceDeploy.getLastsyncTime()));
continue;
}
}
survDeviceDeploy.setScEquZhibiaoList(scEquZhibiaoService.getListByEquid(survDeviceDeploy.getId()));
saveData(survDeviceDeploy,deviceDeployMap,datas);
b = true;
}
}
}
return b;
}
public static void saveData(SurvDeviceDeploy deploy, Map<String, SurvDeviceDeploy> deviceDeployMap, List<RenkeDataRealTimeDetail> datas) { public static void saveData(SurvDeviceDeploy deploy, Map<String, SurvDeviceDeploy> deviceDeployMap, List<RenkeDataRealTimeDetail> datas) {
if(datas!=null && !datas.isEmpty()){ if(datas!=null && !datas.isEmpty()){
//复用新普惠构造方式传入参数 //复用新普惠构造方式传入参数
@ -96,8 +130,10 @@ public class SdrkUtils {
} }
if(dataMap.size()>1){//不值包含mn if(dataMap.size()>1){//不值包含mn
if(DeviceDeployEnum.SURV_SOIL.getType().equals(deploy.getDeployType())){//土壤监测设备 if(DeviceDeployEnum.SURV_SOIL.getType().equals(deploy.getDeployType()) || DeviceDeployEnum.SURV_AIR.getType().equals(deploy.getDeployType())){//土壤/空气监测设备
survTransdataSoilService.saveBaowen(dataMap, deploy,deviceDeployMap); survTransdataSoilService.saveBaowen(dataMap, deploy,deviceDeployMap);
} else if (DeviceDeployEnum.WATER_QULITY.getType().equals(deploy.getDeployType())) {//水监测设备
survTransdataSoilService.saveWaterBaowen(dataMap, deploy,deviceDeployMap);
} else if(DeviceDeployEnum.FLOWMETER.getType().equals(deploy.getDeployType())){ } else if(DeviceDeployEnum.FLOWMETER.getType().equals(deploy.getDeployType())){
flowmeterService.saveBaowen(dataMap, deploy,deviceDeployMap); flowmeterService.saveBaowen(dataMap, deploy,deviceDeployMap);
} }
@ -243,4 +279,6 @@ public class SdrkUtils {
return null; return null;
} }
} }

View File

@ -7,7 +7,7 @@ server:
spring: spring:
datasource: datasource:
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://172.27.17.3:13306/fx_nsp?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true url: jdbc:mysql://172.27.17.13:13306/fx_nsp?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: user_fx username: user_fx
password: user_fx password: user_fx
type: com.alibaba.druid.pool.DruidDataSource type: com.alibaba.druid.pool.DruidDataSource
@ -77,13 +77,47 @@ xxl:
logpath: /logs/xxl-job/jobhandler logpath: /logs/xxl-job/jobhandler
logretentiondays: 30 logretentiondays: 30
mqtt: mqtt:
host: tcp://mqtt.ilhzn.cn:10007 enabled: true
userName: lhzn.mqtt # 指定默认客户端名称(可选)
passWord: lhzn.2025 default-client: broker1
# 多客户端配置
clients:
- name: lhiotMqtt
enabled: true
broker:
url: "tcp://mqtt.ilhzn.cn:10007"
client:
id: fxgather-client-${random.uuid}
clean-session: true
connection:
timeout: 10
keep-alive: 30
automatic-reconnect: true
auth:
username: "lhzn.mqtt"
password: "lhzn.2025"
topics:
status: "device/status"
qos: 1 qos: 1
clientId: fxgather-client-${random.uuid} #ClientId_local必须唯一。 retained: false
timeout: 10 # 超时时间
keepalive: 30 # 保持连接时间 - name: renkeMqtt
clearSession: false # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) enabled: true
broker:
url: "tcp://rtd.mqtt.0531yun.com:1883"
client:
id: fxgather-client-${random.uuid}
clean-session: true
connection:
timeout: 10
keep-alive: 30
automatic-reconnect: true
auth:
username: "h250830lhzn"
password: "h250830lhzn"
topics:
status: "device/status2"
qos: 1
retained: false

View File

@ -79,26 +79,46 @@ xxl:
logretentiondays: 30 logretentiondays: 30
# 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
mqtt: mqtt:
enabled: true
# 指定默认客户端名称(可选)
default-client: broker1
# 多客户端配置
clients:
- name: lhiotMqtt
enabled: true enabled: true
broker: broker:
url: tcp://mqtt.ilhzn.cn:10007 url: "tcp://mqtt.ilhzn.cn:10007"
# 多个broker配置: tcp://broker1:1883,tcp://broker2:1883
client: client:
id: lanhai-mqtt-client-${random.uuid} id: fxgather-client-${random.uuid}
clean-session: false clean-session: true
connection: connection:
timeout: 30 timeout: 10
keep-alive: 60 keep-alive: 30
max-reconnect-delay: 128000 # 最大重连延迟(ms)
automatic-reconnect: true automatic-reconnect: true
auth: auth:
username: lhzn.mqtt username: "lhzn.mqtt"
password: lhzn.2025 password: "lhzn.2025"
topics: topics:
send: "lanhai/mqtt/send" status: "device/status"
receive: "lanhai/mqtt/receive" qos: 1
status: "lanhai/mqtt/status" retained: false
device: "lanhai/device/+/command"
- name: renkeMqtt
enabled: true
broker:
url: "tcp://rtd.mqtt.0531yun.com:1883"
client:
id: fxgather-client-${random.uuid}
clean-session: true
connection:
timeout: 10
keep-alive: 30
automatic-reconnect: true
auth:
username: "h250830lhzn"
password: "h250830lhzn"
topics:
status: "device/status2"
qos: 1 qos: 1
retained: false retained: false

View File

@ -35,12 +35,10 @@ public class Test2 {
// survTransdataSoilService.saveBaowen(map); // survTransdataSoilService.saveBaowen(map);
// ip:110.179.80.65,port:51077 // ip:110.179.80.65,port:51077
String hostAddress = "110.179.80.65";//ip:117.132.191.89 long now = -400;
String port = String.valueOf(51077);//port:8515 long f= -300;
System.out.println("ip:"+hostAddress+",port:"+port); System.out.println(f < now);
ISurvDeviceDeployService deviceDeployService = SpringContextUtil.getBean(ISurvDeviceDeployService.class);
SurvDeviceDeploy deviceDeploy = deviceDeployService.getOneByIpPort(hostAddress,port);
System.out.println(deviceDeploy);
} }
} }

View File

@ -0,0 +1,10 @@
package com.lanhai.test;
public class testway {
public static void main(String[] args) {
long now = -300;
long f= -400;
System.out.println(f < now);
}
}