diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/AbstractProtocolDriver.java b/nl-iot/src/main/java/org/nl/iot/core/driver/AbstractProtocolDriver.java new file mode 100644 index 0000000..980f7f8 --- /dev/null +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/AbstractProtocolDriver.java @@ -0,0 +1,70 @@ +package org.nl.iot.core.driver; + +import lombok.extern.slf4j.Slf4j; +import org.nl.common.exception.CommonException; +import org.nl.iot.core.driver.service.DriverCustomService; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 抽象驱动类 + * @Author: liyongde + * @Date: 2026/3/19 16:06 + * @Modified By: + */ +@Slf4j +public abstract class AbstractProtocolDriver implements DriverCustomService { + + protected Map connectMap = new ConcurrentHashMap<>();; + + // 注入映射管理器 + protected final ConnectionProtocolMappingManager mappingManager; + + // 构造方法注入 + public AbstractProtocolDriver(ConnectionProtocolMappingManager mappingManager) { + this.mappingManager = mappingManager; + } + + /** + * 创建连接(统一方法,自动注册映射) + * @param connectionId 连接ID(原key) + * @param protocolCode 协议编码 + * @param connection 连接对象 + */ + public void addConnection(String connectionId, String protocolCode, T connection) { + if (connection == null) { + throw new CommonException("连接对象不能为空"); + } + connectMap.put(connectionId, connection); + // 注册连接ID与协议的映射 + mappingManager.registerMapping(connectionId, protocolCode); + log.info("新增连接:协议={},连接ID={}", protocolCode, connectionId); + } + + /** + * 重写删除方法:删除连接后同步清理映射 + */ + public void removeConnection(String connectionId) { + if (connectMap.isEmpty() || !connectMap.containsKey(connectionId)) { + log.warn("连接ID={}不存在,无需删除", connectionId); + return; + } + // 1. 删除连接对象 + T connection = connectMap.remove(connectionId); + closeConnection(connection); + // 2. 清理映射关系 + mappingManager.removeMapping(connectionId); + log.info("删除连接成功:连接ID={}", connectionId); + } + + /** + * 抽象方法:子类实现具体的连接关闭逻辑(类型安全) + * @param connection 要关闭的连接对象 + */ + protected abstract void closeConnection(T connection); + + // 保留event方法的抽象(子类必须实现) +// @Override +// public abstract void event(MetadataEventDTO metadataEvent); +} diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/ConnectionProtocolMappingManager.java b/nl-iot/src/main/java/org/nl/iot/core/driver/ConnectionProtocolMappingManager.java new file mode 100644 index 0000000..1ab799b --- /dev/null +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/ConnectionProtocolMappingManager.java @@ -0,0 +1,72 @@ +package org.nl.iot.core.driver; + +import lombok.extern.slf4j.Slf4j; +import org.nl.common.exception.CommonException; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 全局连接ID-协议编码映射管理器 + * 核心作用:记录每个连接ID所属的协议编码,解决删除时"只知ID不知协议"的问题 + * @Author: liyongde + * @Date: 2026/3/19 16:30 + * @Modified By: + */ +@Slf4j +@Component +public class ConnectionProtocolMappingManager { + + /** + * 映射表:连接ID → 协议编码(如 "conn_123" → "MODBUS") + */ + private final Map connectionId2ProtocolCode = new ConcurrentHashMap<>(); + + /** + * 注册连接ID与协议编码的映射(创建连接时调用) + */ + public void registerMapping(String connectionId, String protocolCode) { + if (connectionId == null || connectionId.trim().isEmpty()) { + throw new CommonException("连接ID不能为空"); + } + if (protocolCode == null || protocolCode.trim().isEmpty()) { + throw new CommonException("协议编码不能为空"); + } + String upperCode = protocolCode.trim().toUpperCase(); + connectionId2ProtocolCode.put(connectionId.trim(), upperCode); + log.debug("注册连接映射:连接ID={} → 协议编码={}", connectionId, upperCode); + } + + /** + * 根据连接ID获取协议编码(删除连接时调用) + */ + public String getProtocolCodeByConnectionId(String connectionId) { + if (connectionId == null || connectionId.trim().isEmpty()) { + throw new CommonException("连接ID不能为空"); + } + String protocolCode = connectionId2ProtocolCode.get(connectionId.trim()); + if (protocolCode == null) { + throw new CommonException("未找到连接ID[" + connectionId + "]对应的协议编码"); + } + return protocolCode; + } + + /** + * 删除映射关系(连接删除后同步清理) + */ + public void removeMapping(String connectionId) { + if (connectionId == null) { + return; + } + connectionId2ProtocolCode.remove(connectionId.trim()); + log.debug("移除连接映射:连接ID={}", connectionId); + } + + /** + * 检查连接ID是否已注册 + */ + public boolean containsMapping(String connectionId) { + return connectionId != null && connectionId2ProtocolCode.containsKey(connectionId.trim()); + } +} diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/DriverConnectionManager.java b/nl-iot/src/main/java/org/nl/iot/core/driver/DriverConnectionManager.java new file mode 100644 index 0000000..39c5e20 --- /dev/null +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/DriverConnectionManager.java @@ -0,0 +1,45 @@ +package org.nl.iot.core.driver; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.nl.common.exception.CommonException; +import org.nl.iot.core.driver.service.DriverCustomService; +import org.springframework.stereotype.Component; + +/** + * + * @Author: liyongde + * @Date: 2026/3/19 16:49 + * @Modified By: + */ +@Slf4j +@Component +public class DriverConnectionManager { + + @Resource + private DriverCustomFactory driverCustomFactory; + @Resource + private ConnectionProtocolMappingManager mappingManager; + + /** + * 核心方法:仅传入连接ID,自动删除对应协议的连接 + * (无需知道协议编码,完全适配你的场景) + */ + public void removeConnectionById(String connectionId) { + // 1. 校验参数 + if (connectionId == null || connectionId.trim().isEmpty()) { + throw new CommonException("连接ID不能为空"); + } + // 2. 根据连接ID获取协议编码 + String protocolCode = mappingManager.getProtocolCodeByConnectionId(connectionId); + // 3. 通过工厂类获取对应驱动 + DriverCustomService driver = driverCustomFactory.getDriver(protocolCode); + if (!(driver instanceof AbstractProtocolDriver)) { + throw new CommonException("驱动类[" + driver.getClass().getSimpleName() + "]未继承AbstractProtocolDriver"); + } + // 4. 强转并调用删除方法 + AbstractProtocolDriver abstractDriver = (AbstractProtocolDriver) driver; + abstractDriver.removeConnection(connectionId); + log.info("删除连接完成:连接ID={},协议编码={}", connectionId, protocolCode); + } +} diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/modbustcp/ModBusProtocolDriverImpl.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/modbustcp/ModBusProtocolDriverImpl.java index 09c92af..c5d86b6 100644 --- a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/modbustcp/ModBusProtocolDriverImpl.java +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/modbustcp/ModBusProtocolDriverImpl.java @@ -1,6 +1,5 @@ package org.nl.iot.core.driver.protocol.modbustcp; -import jakarta.annotation.PostConstruct; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.plc4x.java.DefaultPlcDriverManager; @@ -11,6 +10,8 @@ import org.apache.plc4x.java.api.messages.PlcWriteRequest; import org.apache.plc4x.java.api.messages.PlcWriteResponse; import org.apache.plc4x.java.api.types.PlcResponseCode; import org.apache.plc4x.java.api.value.PlcValue; +import org.nl.iot.core.driver.AbstractProtocolDriver; +import org.nl.iot.core.driver.ConnectionProtocolMappingManager; import org.nl.iot.core.driver.ProtocolDriver; import org.nl.iot.core.driver.ProtocolType; import org.nl.iot.core.driver.bo.DeviceBO; @@ -19,16 +20,16 @@ import org.nl.iot.core.driver.bo.SiteBO; import org.nl.iot.core.driver.entity.RValue; import org.nl.iot.core.driver.entity.WResponse; import org.nl.iot.core.driver.entity.WValue; -import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum; -import org.nl.iot.core.driver.util.JavaToPlcValueConvertUtil; import org.nl.iot.core.driver.protocol.modbustcp.util.ModBusTcpUtils; +import org.nl.iot.core.driver.util.JavaToPlcValueConvertUtil; import org.nl.iot.core.driver.util.PlcValueConvertUtil; -import org.nl.iot.core.driver.service.DriverCustomService; import org.springframework.stereotype.Service; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; /** @@ -39,14 +40,14 @@ import java.util.concurrent.TimeUnit; @Slf4j @Service @ProtocolDriver(ProtocolType.MODBUS) -public class ModBusProtocolDriverImpl implements DriverCustomService { +public class ModBusProtocolDriverImpl extends AbstractProtocolDriver { - private Map connectMap; + public ModBusProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) { + super(mappingManager); + } @Override - @PostConstruct public void initial() { - connectMap = new ConcurrentHashMap<>(16); } @Override @@ -56,13 +57,13 @@ public class ModBusProtocolDriverImpl implements DriverCustomService { @Override public void event(MetadataEventDTO metadataEvent) { - MetadataOperateTypeEnum operateType = metadataEvent.getOperateType(); - log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType); - - // When the device is updated or deleted, remove the corresponding connection handle - if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) { - connectMap.remove(metadataEvent.getConnectId()); - } +// MetadataOperateTypeEnum operateType = metadataEvent.getOperateType(); +// log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType); +// +// // When the device is updated or deleted, remove the corresponding connection handle +// if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) { +// connectMap.remove(metadataEvent.getConnectId()); +// } } @Override @@ -85,6 +86,14 @@ public class ModBusProtocolDriverImpl implements DriverCustomService { return batchWriteValue(getConnector(device), wValue); } + @Override + protected void closeConnection(PlcConnection connection) { + try { + connection.close(); + } catch (Exception e) { + log.warn("关闭失败:{}", e.getMessage()); + } + } @SneakyThrows public static List batchWriteValue(PlcConnection modbusMaster, List wValues) { List res = new ArrayList<>(); @@ -119,6 +128,7 @@ public class ModBusProtocolDriverImpl implements DriverCustomService { try { if (Objects.isNull(modbusMaster)) { modbusMaster = new DefaultPlcDriverManager().getConnection(ModBusTcpUtils.buildModBusPlcUrl(deviceBO)); + createModBusConnection(deviceBO.getId(), modbusMaster); } } catch (Exception e) { throw new RuntimeException(e); @@ -126,6 +136,12 @@ public class ModBusProtocolDriverImpl implements DriverCustomService { return modbusMaster; } + // 业务中创建连接时,调用父类的addConnection方法 + public void createModBusConnection(String connectionId, PlcConnection connection) { + // 传入协议编码(MODBUS)和连接ID、连接对象 + addConnection(connectionId, ProtocolType.MODBUS.getMainCode(), connection); + } + @SneakyThrows public String readValue(PlcConnection modbusMaster, SiteBO point) { // 1. 解析配置 diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcda/OpcDaProtocolDriverImpl.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcda/OpcDaProtocolDriverImpl.java index 7ab2e5c..6a21e05 100644 --- a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcda/OpcDaProtocolDriverImpl.java +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcda/OpcDaProtocolDriverImpl.java @@ -2,12 +2,13 @@ package org.nl.iot.core.driver.protocol.opcda; import cn.hutool.core.util.ObjectUtil; import com.alibaba.fastjson.JSONObject; -import jakarta.annotation.PostConstruct; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.jinterop.dcom.common.JIException; import org.jinterop.dcom.core.JIVariant; import org.nl.common.exception.CommonException; +import org.nl.iot.core.driver.AbstractProtocolDriver; +import org.nl.iot.core.driver.ConnectionProtocolMappingManager; import org.nl.iot.core.driver.ProtocolDriver; import org.nl.iot.core.driver.ProtocolType; import org.nl.iot.core.driver.bo.DeviceBO; @@ -16,14 +17,12 @@ import org.nl.iot.core.driver.bo.SiteBO; import org.nl.iot.core.driver.entity.RValue; import org.nl.iot.core.driver.entity.WResponse; import org.nl.iot.core.driver.entity.WValue; -import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum; import org.nl.iot.core.driver.enums.PointTypeFlagEnum; import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.common.AlreadyConnectedException; import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.common.ConnectionInformation; import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.common.NotConnectedException; import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.da.*; import org.nl.iot.core.driver.protocol.opcda.util.JIVariantToStringUtil; -import org.nl.iot.core.driver.service.DriverCustomService; import org.springframework.stereotype.Service; import java.net.UnknownHostException; @@ -31,29 +30,19 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; @Slf4j @Service @ProtocolDriver(ProtocolType.OPCDA) -public class OpcDaProtocolDriverImpl implements DriverCustomService { - /** - * Opc Da Server Map - */ - private Map connectMap; +public class OpcDaProtocolDriverImpl extends AbstractProtocolDriver { + + public OpcDaProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) { + super(mappingManager); + } - @PostConstruct @Override public void initial() { - /* - * 驱动初始化逻辑 - * - * 提示: 此处逻辑仅供参考, 请务必结合实际应用场景进行修改。 - * 驱动启动时会自动执行该方法, 您可以在此处执行特定的初始化操作。 - * - */ - connectMap = new ConcurrentHashMap<>(16); } @Override @@ -63,12 +52,21 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService { @Override public void event(MetadataEventDTO metadataEvent) { - MetadataOperateTypeEnum operateType = metadataEvent.getOperateType(); - log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType); +// MetadataOperateTypeEnum operateType = metadataEvent.getOperateType(); +// log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType); +// +// // When the device is updated or deleted, remove the corresponding connection handle +// if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) { +// connectMap.remove(metadataEvent.getConnectId()); +// } + } - // When the device is updated or deleted, remove the corresponding connection handle - if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) { - connectMap.remove(metadataEvent.getConnectId()); + @Override + protected void closeConnection(Server server) { + try { + server.disconnect(); + } catch (Exception e) { + log.warn("关闭失败:{}", e.getMessage()); } } @@ -109,9 +107,9 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService { server = new Server(connectionInformation, Executors.newSingleThreadScheduledExecutor()); try { server.connect(); - connectMap.put(deviceBO.getId(), server); + addOpcDaConnection(deviceBO.getId(), server); } catch (AlreadyConnectedException | UnknownHostException | JIException e) { - connectMap.entrySet().removeIf(next -> next.getKey().equals(deviceBO.getId())); + removeConnection(deviceBO.getId()); log.error("Connect opc da server error: {}", e.getMessage(), e); throw new CommonException(e.getMessage()); } @@ -119,6 +117,12 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService { return server; } + // 业务中创建连接时,调用父类的addConnection方法 + public void addOpcDaConnection(String connectionId, Server connection) { + // 传入协议编码(OpcDa)和连接ID、连接对象 + addConnection(connectionId, ProtocolType.OPCDA.getMainCode(), connection); + } + /** * 从 OPC DA 服务器读取位号值 *

diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcua/OpcUaProtocolDriverImpl.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcua/OpcUaProtocolDriverImpl.java index aefd046..b127090 100644 --- a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcua/OpcUaProtocolDriverImpl.java +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/opcua/OpcUaProtocolDriverImpl.java @@ -1,11 +1,9 @@ package org.nl.iot.core.driver.protocol.opcua; import com.alibaba.fastjson.JSONObject; -import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider; -import org.eclipse.milo.opcua.stack.core.AttributeId; import org.eclipse.milo.opcua.stack.core.UaException; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; @@ -13,8 +11,9 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode; import org.eclipse.milo.opcua.stack.core.types.builtin.Variant; import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned; import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn; -import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue; import org.nl.common.exception.CommonException; +import org.nl.iot.core.driver.AbstractProtocolDriver; +import org.nl.iot.core.driver.ConnectionProtocolMappingManager; import org.nl.iot.core.driver.ProtocolDriver; import org.nl.iot.core.driver.ProtocolType; import org.nl.iot.core.driver.bo.DeviceBO; @@ -25,49 +24,38 @@ import org.nl.iot.core.driver.entity.WResponse; import org.nl.iot.core.driver.entity.WValue; import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum; import org.nl.iot.core.driver.enums.PointTypeFlagEnum; -import org.nl.iot.core.driver.service.DriverCustomService; import org.springframework.stereotype.Service; -import jakarta.annotation.PreDestroy; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.concurrent.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; @Slf4j @Service @ProtocolDriver(ProtocolType.OPCUA) -public class OpcUaProtocolDriverImpl implements DriverCustomService { - private Map connectMap; +public class OpcUaProtocolDriverImpl extends AbstractProtocolDriver { - @PostConstruct - @Override - public void initial() { - /* - * 驱动初始化逻辑 - * - * 提示: 此处逻辑仅供参考, 请务必结合实际应用场景进行修改。 - * 驱动启动时会自动执行该方法, 您可以在此处执行特定的初始化操作。 - * - */ - connectMap = new ConcurrentHashMap<>(16); + public OpcUaProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) { + super(mappingManager); } -// @PreDestroy -// public void destroy() { -// // 应用关闭时清理所有连接 -// log.info("Cleaning up OPC UA connections..."); -// connectMap.values().forEach(client -> { -// try { -// client.disconnect().get(5, TimeUnit.SECONDS); -// } catch (Exception e) { -// log.warn("Error disconnecting OPC UA client during cleanup: {}", e.getMessage()); -// } -// }); -// connectMap.clear(); -// log.info("OPC UA connections cleanup completed"); -// } + @Override + public void initial() { + + } + + @Override + protected void closeConnection(OpcUaClient client) { + try { + client.disconnect().get(5, TimeUnit.SECONDS); + } catch (Exception e) { + log.error("Error disconnecting OPC UA client during cleanup: {}", e.getMessage()); + } + } @Override public void schedule() { @@ -171,10 +159,10 @@ public class OpcUaProtocolDriverImpl implements DriverCustomService { .setSessionTimeout(Unsigned.uint(60000)) // 设置会话超时时间为 60 秒 .build() ); - connectMap.put(device.getId(), opcUaClient); + addOPCUAConnection(device.getId(), opcUaClient); log.info("Created new OPC UA client for device: {}", device.getId()); } catch (UaException e) { - connectMap.entrySet().removeIf(next -> next.getKey().equals(device.getId())); + removeConnection(device.getId()); log.error("Failed to create OPC UA client: {}", e.getMessage(), e); throw new IllegalArgumentException(e.getMessage()); } @@ -182,6 +170,12 @@ public class OpcUaProtocolDriverImpl implements DriverCustomService { return opcUaClient; } + // 业务中创建连接时,调用父类的addConnection方法 + public void addOPCUAConnection(String connectionId, OpcUaClient connection) { + // 传入协议编码(OPCUA)和连接ID、连接对象 + addConnection(connectionId, ProtocolType.OPCUA.getMainCode(), connection); + } + /** * 读取 OPC UA 节点的值 * diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/PlcS7ProtocolDriverImpl.java b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/PlcS7ProtocolDriverImpl.java index 45b500f..8be325c 100644 --- a/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/PlcS7ProtocolDriverImpl.java +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/protocol/plcs7/PlcS7ProtocolDriverImpl.java @@ -1,6 +1,5 @@ package org.nl.iot.core.driver.protocol.plcs7; -import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.apache.plc4x.java.DefaultPlcDriverManager; import org.apache.plc4x.java.api.PlcConnection; @@ -11,6 +10,8 @@ import org.apache.plc4x.java.api.messages.PlcWriteResponse; import org.apache.plc4x.java.api.types.PlcResponseCode; import org.apache.plc4x.java.api.value.PlcValue; import org.nl.common.exception.CommonException; +import org.nl.iot.core.driver.AbstractProtocolDriver; +import org.nl.iot.core.driver.ConnectionProtocolMappingManager; import org.nl.iot.core.driver.ProtocolDriver; import org.nl.iot.core.driver.ProtocolType; import org.nl.iot.core.driver.bo.DeviceBO; @@ -19,15 +20,17 @@ import org.nl.iot.core.driver.bo.SiteBO; import org.nl.iot.core.driver.entity.RValue; import org.nl.iot.core.driver.entity.WResponse; import org.nl.iot.core.driver.entity.WValue; -import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum; +import org.nl.iot.core.driver.protocol.plcs7.util.PlcS7Utils; import org.nl.iot.core.driver.util.JavaToPlcValueConvertUtil; import org.nl.iot.core.driver.util.PlcValueConvertUtil; -import org.nl.iot.core.driver.protocol.plcs7.util.PlcS7Utils; -import org.nl.iot.core.driver.service.DriverCustomService; import org.springframework.stereotype.Service; -import java.util.*; -import java.util.concurrent.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; /** * @@ -37,18 +40,14 @@ import java.util.concurrent.*; @Slf4j @Service @ProtocolDriver(ProtocolType.PLCS7) -public class PlcS7ProtocolDriverImpl implements DriverCustomService { +public class PlcS7ProtocolDriverImpl extends AbstractProtocolDriver { - /** - * Plc Connector Map - * 仅供参考 - */ - private Map connectMap; + public PlcS7ProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) { + super(mappingManager); + } - @PostConstruct @Override public void initial() { - connectMap = new ConcurrentHashMap<>(16); } @Override @@ -58,12 +57,21 @@ public class PlcS7ProtocolDriverImpl implements DriverCustomService { @Override public void event(MetadataEventDTO metadataEvent) { - MetadataOperateTypeEnum operateType = metadataEvent.getOperateType(); - log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType); +// MetadataOperateTypeEnum operateType = metadataEvent.getOperateType(); +// log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType); +// +// // When the device is updated or deleted, remove the corresponding connection handle +// if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) { +// connectMap.remove(metadataEvent.getConnectId()); +// } + } - // When the device is updated or deleted, remove the corresponding connection handle - if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) { - connectMap.remove(metadataEvent.getConnectId()); + @Override + protected void closeConnection(PlcConnection connection) { + try { + connection.close(); + } catch (Exception e) { + log.warn("关闭失败:{}", e.getMessage()); } } @@ -145,7 +153,7 @@ public class PlcS7ProtocolDriverImpl implements DriverCustomService { String connectionUrl = PlcS7Utils.getS7ConnectionUrl(deviceBO); log.info("创建S7连接,deviceId: {}, url: {}", deviceId, connectionUrl); connection = new DefaultPlcDriverManager().getConnection(connectionUrl); - connectMap.put(deviceId, connection); + addPlcS7Connection(deviceBO.getId(), connection); } return connection; } catch (Exception e) { @@ -154,6 +162,12 @@ public class PlcS7ProtocolDriverImpl implements DriverCustomService { } } + // 业务中创建连接时,调用父类的addConnection方法 + public void addPlcS7Connection(String connectionId, PlcConnection connection) { + // 传入协议编码(PLCS7)和连接ID、连接对象 + addConnection(connectionId, ProtocolType.PLCS7.getMainCode(), connection); + } + public static PlcReadRequest.Builder doBuildReadRequest(PlcConnection s7Connection, List points) { try { PlcReadRequest.Builder readBuilder = s7Connection.readRequestBuilder(); diff --git a/nl-iot/src/main/java/org/nl/iot/modular/iot/controller/IotConnectController.java b/nl-iot/src/main/java/org/nl/iot/modular/iot/controller/IotConnectController.java index b491693..b125d6a 100644 --- a/nl-iot/src/main/java/org/nl/iot/modular/iot/controller/IotConnectController.java +++ b/nl-iot/src/main/java/org/nl/iot/modular/iot/controller/IotConnectController.java @@ -16,8 +16,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.nl.common.pojo.CommonResult; +import org.nl.iot.core.driver.DriverConnectionManager; import org.nl.iot.modular.iot.entity.IotConnect; import org.nl.iot.modular.iot.entity.IotConfig; import org.nl.iot.modular.iot.service.IotConfigService; @@ -43,6 +45,8 @@ public class IotConnectController { @Autowired private IotConfigService iotConfigService; + @Resource + private DriverConnectionManager connectionManager; /** * 获取连接列表 @@ -92,6 +96,7 @@ public class IotConnectController { @PostMapping("/edit") public CommonResult edit(@RequestBody IotConnect connect) { iotConnectService.updateById(connect); + connectionManager.removeConnectionById(connect.getId().toString()); return CommonResult.ok(); } @@ -110,7 +115,7 @@ public class IotConnectController { if (count > 0) { throw new CommonException("连接已被信号配置使用,无法删除"); } - iotConnectService.removeById(connect.getId()); + connectionManager.removeConnectionById(connect.getId().toString()); return CommonResult.ok(); } @@ -128,6 +133,9 @@ public class IotConnectController { throw new CommonException("所选连接存在信号配置,无法删除"); } } + for (Integer id : ids) { + connectionManager.removeConnectionById(String.valueOf(id)); + } iotConnectService.removeBatchByIds(ids); return CommonResult.ok(); }