|
@@ -9,6 +9,7 @@ import com.usky.cdi.mapper.DmpDeviceMapper;
|
|
|
import com.usky.cdi.mapper.DmpProductMapper;
|
|
import com.usky.cdi.mapper.DmpProductMapper;
|
|
|
import com.usky.cdi.service.config.mqtt.MqttOutConfig;
|
|
import com.usky.cdi.service.config.mqtt.MqttOutConfig;
|
|
|
import com.usky.cdi.service.enums.EnvMonitorMqttTopic;
|
|
import com.usky.cdi.service.enums.EnvMonitorMqttTopic;
|
|
|
|
|
+import com.usky.cdi.service.mqtt.MqttConnectionTool;
|
|
|
import com.usky.cdi.service.util.DeviceDataQuery;
|
|
import com.usky.cdi.service.util.DeviceDataQuery;
|
|
|
import com.usky.cdi.service.util.SnowflakeIdGenerator;
|
|
import com.usky.cdi.service.util.SnowflakeIdGenerator;
|
|
|
import com.usky.cdi.service.vo.IotDataTransferVO;
|
|
import com.usky.cdi.service.vo.IotDataTransferVO;
|
|
@@ -17,17 +18,15 @@ import lombok.extern.slf4j.Slf4j;
|
|
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
|
|
import org.springframework.context.ApplicationContext;
|
|
import org.springframework.context.ApplicationContext;
|
|
|
|
|
+import org.springframework.context.ConfigurableApplicationContext;
|
|
|
import org.springframework.context.support.GenericApplicationContext;
|
|
import org.springframework.context.support.GenericApplicationContext;
|
|
|
-import org.springframework.integration.channel.DirectChannel;
|
|
|
|
|
import org.springframework.integration.dsl.IntegrationFlow;
|
|
import org.springframework.integration.dsl.IntegrationFlow;
|
|
|
import org.springframework.integration.dsl.IntegrationFlows;
|
|
import org.springframework.integration.dsl.IntegrationFlows;
|
|
|
-import org.springframework.integration.endpoint.EventDrivenConsumer;
|
|
|
|
|
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
|
|
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
|
|
|
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
|
|
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
|
|
|
import org.springframework.messaging.MessageChannel;
|
|
import org.springframework.messaging.MessageChannel;
|
|
|
-import org.springframework.messaging.MessageHandler;
|
|
|
|
|
-import org.springframework.messaging.SubscribableChannel;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
import javax.annotation.PostConstruct;
|
|
import javax.annotation.PostConstruct;
|
|
@@ -50,6 +49,9 @@ public class IotDataTransferService {
|
|
|
|
|
|
|
|
private MqttOutConfig.MqttGateway mqttGateway;
|
|
private MqttOutConfig.MqttGateway mqttGateway;
|
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private MqttConnectionTool mqttConnectionTool;
|
|
|
|
|
+
|
|
|
// 注入ApplicationContext,确保总是能获取到
|
|
// 注入ApplicationContext,确保总是能获取到
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private ApplicationContext context;
|
|
private ApplicationContext context;
|
|
@@ -61,7 +63,7 @@ public class IotDataTransferService {
|
|
|
private static final int COMPLETION_TIMEOUT = 5000;
|
|
private static final int COMPLETION_TIMEOUT = 5000;
|
|
|
|
|
|
|
|
// 存储每个任务的MQTT客户端工厂和网关
|
|
// 存储每个任务的MQTT客户端工厂和网关
|
|
|
- private final Map<String, MqttOutConfig.MqttGateway> mqttGatewayMap = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
+ private final Map<String, MqttConnectionTool.MqttGateway> mqttGatewayMap = new ConcurrentHashMap<>();
|
|
|
private final Map<String, DefaultMqttPahoClientFactory> mqttClientFactoryMap = new ConcurrentHashMap<>();
|
|
private final Map<String, DefaultMqttPahoClientFactory> mqttClientFactoryMap = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
private SnowflakeIdGenerator idGenerator;
|
|
private SnowflakeIdGenerator idGenerator;
|
|
@@ -768,6 +770,7 @@ public class IotDataTransferService {
|
|
|
* @param password MQTT密码
|
|
* @param password MQTT密码
|
|
|
*/
|
|
*/
|
|
|
public void synchronizeDeviceData(Integer tenantId, Long engineeringId, String username, String password) {
|
|
public void synchronizeDeviceData(Integer tenantId, Long engineeringId, String username, String password) {
|
|
|
|
|
+ log.info("用户名:{},密码:{}", username, password);
|
|
|
// 参数校验
|
|
// 参数校验
|
|
|
if (engineeringId == null || username == null || password == null) {
|
|
if (engineeringId == null || username == null || password == null) {
|
|
|
log.error("工程ID、MQTT用户名或密码不能为空");
|
|
log.error("工程ID、MQTT用户名或密码不能为空");
|
|
@@ -914,75 +917,21 @@ public class IotDataTransferService {
|
|
|
* @param username MQTT用户名
|
|
* @param username MQTT用户名
|
|
|
* @param password MQTT密码
|
|
* @param password MQTT密码
|
|
|
*/
|
|
*/
|
|
|
- public void createMqttConnection(String username, String password) {
|
|
|
|
|
|
|
+ public synchronized void createMqttConnection(String username, String password) {
|
|
|
|
|
+ log.info("手动创建/刷新 MQTT 连接(含动态 clientId),用户名:{},密码:{}", username, password);
|
|
|
try {
|
|
try {
|
|
|
- // 使用注入的ApplicationContext获取或创建MQTT连接
|
|
|
|
|
- if (this.context == null) {
|
|
|
|
|
- throw new IllegalStateException("ApplicationContext未注入,无法获取MQTT Gateway");
|
|
|
|
|
|
|
+ // 检查MqttConnectionTool是否已注入
|
|
|
|
|
+ if (this.mqttConnectionTool == null) {
|
|
|
|
|
+ throw new IllegalStateException("MqttConnectionTool未注入,无法获取MQTT Gateway");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 检查是否已经为该用户创建了MQTT连接
|
|
|
|
|
- if (!mqttGatewayMap.containsKey(username)) {
|
|
|
|
|
- synchronized (this) {
|
|
|
|
|
- // 双重检查锁定
|
|
|
|
|
- if (!mqttGatewayMap.containsKey(username)) {
|
|
|
|
|
- // 1. 创建新的MQTT客户端工厂
|
|
|
|
|
- DefaultMqttPahoClientFactory mqttClientFactory = new DefaultMqttPahoClientFactory();
|
|
|
|
|
-
|
|
|
|
|
- // 2. 创建并配置MqttConnectOptions
|
|
|
|
|
- MqttConnectOptions options = new MqttConnectOptions();
|
|
|
|
|
- options.setServerURIs(new String[]{MQTT_URL});
|
|
|
|
|
- options.setUserName(username);
|
|
|
|
|
- options.setPassword(password.toCharArray());
|
|
|
|
|
- options.setKeepAliveInterval(KEEP_ALIVE_INTERVAL);
|
|
|
|
|
-
|
|
|
|
|
- // 3. 设置连接选项
|
|
|
|
|
- mqttClientFactory.setConnectionOptions(options);
|
|
|
|
|
-
|
|
|
|
|
- // 4. 创建唯一的客户端ID
|
|
|
|
|
- String clientId = "mqttx-" + username;
|
|
|
|
|
-
|
|
|
|
|
- // 5. 创建MQTT消息处理器
|
|
|
|
|
- MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(clientId, mqttClientFactory);
|
|
|
|
|
- messageHandler.setAsync(true);
|
|
|
|
|
- messageHandler.setDefaultTopic("testTopic");
|
|
|
|
|
-
|
|
|
|
|
- // 6. 获取消息通道
|
|
|
|
|
- MessageChannel mqttOutboundChannel = context.getBean("mqttOutboundChannel", MessageChannel.class);
|
|
|
|
|
-
|
|
|
|
|
- // 7. 注册消息处理器到通道
|
|
|
|
|
- IntegrationFlow flow = IntegrationFlows.from(mqttOutboundChannel)
|
|
|
|
|
- .handle(messageHandler)
|
|
|
|
|
- .get();
|
|
|
|
|
-
|
|
|
|
|
- // 8. 注册IntegrationFlow
|
|
|
|
|
- ((GenericApplicationContext) context).registerBean("mqttFlow-" + username, IntegrationFlow.class, () -> flow);
|
|
|
|
|
- ((GenericApplicationContext) context).refresh();
|
|
|
|
|
|
|
+ // 使用MqttConnectionTool创建或刷新MQTT连接
|
|
|
|
|
+ MqttConnectionTool.MqttGateway gateway = mqttConnectionTool.connectOrRefresh(username, password);
|
|
|
|
|
|
|
|
- // 9. 获取MQTT Gateway实例
|
|
|
|
|
- MqttOutConfig.MqttGateway mqttGateway = context.getBean(MqttOutConfig.MqttGateway.class);
|
|
|
|
|
-
|
|
|
|
|
- // 10. 存储到映射中
|
|
|
|
|
- mqttGatewayMap.put(username, mqttGateway);
|
|
|
|
|
- mqttClientFactoryMap.put(username, mqttClientFactory);
|
|
|
|
|
-
|
|
|
|
|
- log.info("MQTT连接创建成功,用户名:{},客户端ID:{}", username, clientId);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- // 连接已存在,更新密码
|
|
|
|
|
- DefaultMqttPahoClientFactory clientFactory = mqttClientFactoryMap.get(username);
|
|
|
|
|
- if (clientFactory != null) {
|
|
|
|
|
- MqttConnectOptions options = new MqttConnectOptions();
|
|
|
|
|
- options.setServerURIs(new String[]{MQTT_URL});
|
|
|
|
|
- options.setUserName(username);
|
|
|
|
|
- options.setPassword(password.toCharArray());
|
|
|
|
|
- options.setKeepAliveInterval(KEEP_ALIVE_INTERVAL);
|
|
|
|
|
- clientFactory.setConnectionOptions(options);
|
|
|
|
|
- log.info("MQTT连接密码已更新,用户名:{}", username);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
|
|
+ // 存储到映射中
|
|
|
|
|
+ mqttGatewayMap.put(username, gateway);
|
|
|
|
|
+ log.info("MQTT连接创建/刷新成功,用户名:{}", username);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
log.error("初始化MQTT连接失败: {}", e.getMessage(), e);
|
|
log.error("初始化MQTT连接失败: {}", e.getMessage(), e);
|
|
|
throw new RuntimeException("初始化MQTT连接失败", e);
|
|
throw new RuntimeException("初始化MQTT连接失败", e);
|
|
|
}
|
|
}
|
|
@@ -994,7 +943,13 @@ public class IotDataTransferService {
|
|
|
* @return 是否初始化
|
|
* @return 是否初始化
|
|
|
*/
|
|
*/
|
|
|
private boolean validateMqttGateway(String username) {
|
|
private boolean validateMqttGateway(String username) {
|
|
|
- if (username == null || !mqttGatewayMap.containsKey(username) || mqttGatewayMap.get(username) == null) {
|
|
|
|
|
|
|
+ if (username == null) {
|
|
|
|
|
+ log.warn("MQTT Gateway未初始化,无法发送消息,用户名:null");
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 一次性获取网关实例,避免竞态条件
|
|
|
|
|
+ MqttConnectionTool.MqttGateway gateway = mqttGatewayMap.get(username);
|
|
|
|
|
+ if (gateway == null) {
|
|
|
log.warn("MQTT Gateway未初始化,无法发送消息,用户名:{}", username);
|
|
log.warn("MQTT Gateway未初始化,无法发送消息,用户名:{}", username);
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
@@ -1027,7 +982,7 @@ public class IotDataTransferService {
|
|
|
String json = JSON.toJSONString(vo);
|
|
String json = JSON.toJSONString(vo);
|
|
|
String topic = topicEnum.getTopic();
|
|
String topic = topicEnum.getTopic();
|
|
|
// 不再记录每条数据的详情,只记录发送操作
|
|
// 不再记录每条数据的详情,只记录发送操作
|
|
|
- MqttOutConfig.MqttGateway gateway = mqttGatewayMap.get(username);
|
|
|
|
|
|
|
+ MqttConnectionTool.MqttGateway gateway = mqttGatewayMap.get(username);
|
|
|
if (gateway != null) {
|
|
if (gateway != null) {
|
|
|
gateway.sendToMqtt(topic, json);
|
|
gateway.sendToMqtt(topic, json);
|
|
|
} else {
|
|
} else {
|