fix:协议驱动完善+工厂类

This commit is contained in:
2026-03-20 10:23:41 +08:00
parent c1696110a9
commit 3f8193a593
8 changed files with 322 additions and 99 deletions

View File

@@ -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<T> implements DriverCustomService {
protected Map<String, T> 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);
}

View File

@@ -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<String, String> 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());
}
}

View File

@@ -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);
}
}

View File

@@ -1,6 +1,5 @@
package org.nl.iot.core.driver.protocol.modbustcp; package org.nl.iot.core.driver.protocol.modbustcp;
import jakarta.annotation.PostConstruct;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.plc4x.java.DefaultPlcDriverManager; 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.messages.PlcWriteResponse;
import org.apache.plc4x.java.api.types.PlcResponseCode; import org.apache.plc4x.java.api.types.PlcResponseCode;
import org.apache.plc4x.java.api.value.PlcValue; 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.ProtocolDriver;
import org.nl.iot.core.driver.ProtocolType; import org.nl.iot.core.driver.ProtocolType;
import org.nl.iot.core.driver.bo.DeviceBO; 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.RValue;
import org.nl.iot.core.driver.entity.WResponse; import org.nl.iot.core.driver.entity.WResponse;
import org.nl.iot.core.driver.entity.WValue; 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.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.util.PlcValueConvertUtil;
import org.nl.iot.core.driver.service.DriverCustomService;
import org.springframework.stereotype.Service; 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.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@@ -39,14 +40,14 @@ import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
@Service @Service
@ProtocolDriver(ProtocolType.MODBUS) @ProtocolDriver(ProtocolType.MODBUS)
public class ModBusProtocolDriverImpl implements DriverCustomService { public class ModBusProtocolDriverImpl extends AbstractProtocolDriver<PlcConnection> {
private Map<String, PlcConnection> connectMap; public ModBusProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) {
super(mappingManager);
}
@Override @Override
@PostConstruct
public void initial() { public void initial() {
connectMap = new ConcurrentHashMap<>(16);
} }
@Override @Override
@@ -56,13 +57,13 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
@Override @Override
public void event(MetadataEventDTO metadataEvent) { public void event(MetadataEventDTO metadataEvent) {
MetadataOperateTypeEnum operateType = metadataEvent.getOperateType(); // MetadataOperateTypeEnum operateType = metadataEvent.getOperateType();
log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType); // log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType);
//
// When the device is updated or deleted, remove the corresponding connection handle // // When the device is updated or deleted, remove the corresponding connection handle
if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) { // if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) {
connectMap.remove(metadataEvent.getConnectId()); // connectMap.remove(metadataEvent.getConnectId());
} // }
} }
@Override @Override
@@ -85,6 +86,14 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
return batchWriteValue(getConnector(device), wValue); return batchWriteValue(getConnector(device), wValue);
} }
@Override
protected void closeConnection(PlcConnection connection) {
try {
connection.close();
} catch (Exception e) {
log.warn("关闭失败:{}", e.getMessage());
}
}
@SneakyThrows @SneakyThrows
public static List<WResponse> batchWriteValue(PlcConnection modbusMaster, List<WValue> wValues) { public static List<WResponse> batchWriteValue(PlcConnection modbusMaster, List<WValue> wValues) {
List<WResponse> res = new ArrayList<>(); List<WResponse> res = new ArrayList<>();
@@ -119,6 +128,7 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
try { try {
if (Objects.isNull(modbusMaster)) { if (Objects.isNull(modbusMaster)) {
modbusMaster = new DefaultPlcDriverManager().getConnection(ModBusTcpUtils.buildModBusPlcUrl(deviceBO)); modbusMaster = new DefaultPlcDriverManager().getConnection(ModBusTcpUtils.buildModBusPlcUrl(deviceBO));
createModBusConnection(deviceBO.getId(), modbusMaster);
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@@ -126,6 +136,12 @@ public class ModBusProtocolDriverImpl implements DriverCustomService {
return modbusMaster; return modbusMaster;
} }
// 业务中创建连接时调用父类的addConnection方法
public void createModBusConnection(String connectionId, PlcConnection connection) {
// 传入协议编码MODBUS和连接ID、连接对象
addConnection(connectionId, ProtocolType.MODBUS.getMainCode(), connection);
}
@SneakyThrows @SneakyThrows
public String readValue(PlcConnection modbusMaster, SiteBO point) { public String readValue(PlcConnection modbusMaster, SiteBO point) {
// 1. 解析配置 // 1. 解析配置

View File

@@ -2,12 +2,13 @@ package org.nl.iot.core.driver.protocol.opcda;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.PostConstruct;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jinterop.dcom.common.JIException; import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIVariant; import org.jinterop.dcom.core.JIVariant;
import org.nl.common.exception.CommonException; 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.ProtocolDriver;
import org.nl.iot.core.driver.ProtocolType; import org.nl.iot.core.driver.ProtocolType;
import org.nl.iot.core.driver.bo.DeviceBO; 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.RValue;
import org.nl.iot.core.driver.entity.WResponse; import org.nl.iot.core.driver.entity.WResponse;
import org.nl.iot.core.driver.entity.WValue; 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.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.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.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.common.NotConnectedException;
import org.nl.iot.core.driver.protocol.opcda.org.openscada.opc.lib.da.*; 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.protocol.opcda.util.JIVariantToStringUtil;
import org.nl.iot.core.driver.service.DriverCustomService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.net.UnknownHostException; import java.net.UnknownHostException;
@@ -31,29 +30,19 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@Slf4j @Slf4j
@Service @Service
@ProtocolDriver(ProtocolType.OPCDA) @ProtocolDriver(ProtocolType.OPCDA)
public class OpcDaProtocolDriverImpl implements DriverCustomService { public class OpcDaProtocolDriverImpl extends AbstractProtocolDriver<Server> {
/**
* Opc Da Server Map public OpcDaProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) {
*/ super(mappingManager);
private Map<String, Server> connectMap; }
@PostConstruct
@Override @Override
public void initial() { public void initial() {
/*
* 驱动初始化逻辑
*
* 提示: 此处逻辑仅供参考, 请务必结合实际应用场景进行修改。
* 驱动启动时会自动执行该方法, 您可以在此处执行特定的初始化操作。
*
*/
connectMap = new ConcurrentHashMap<>(16);
} }
@Override @Override
@@ -63,12 +52,21 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService {
@Override @Override
public void event(MetadataEventDTO metadataEvent) { public void event(MetadataEventDTO metadataEvent) {
MetadataOperateTypeEnum operateType = metadataEvent.getOperateType(); // MetadataOperateTypeEnum operateType = metadataEvent.getOperateType();
log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType); // 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 @Override
if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) { protected void closeConnection(Server server) {
connectMap.remove(metadataEvent.getConnectId()); 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()); server = new Server(connectionInformation, Executors.newSingleThreadScheduledExecutor());
try { try {
server.connect(); server.connect();
connectMap.put(deviceBO.getId(), server); addOpcDaConnection(deviceBO.getId(), server);
} catch (AlreadyConnectedException | UnknownHostException | JIException e) { } 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); log.error("Connect opc da server error: {}", e.getMessage(), e);
throw new CommonException(e.getMessage()); throw new CommonException(e.getMessage());
} }
@@ -119,6 +117,12 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService {
return server; return server;
} }
// 业务中创建连接时调用父类的addConnection方法
public void addOpcDaConnection(String connectionId, Server connection) {
// 传入协议编码OpcDa和连接ID、连接对象
addConnection(connectionId, ProtocolType.OPCDA.getMainCode(), connection);
}
/** /**
* 从 OPC DA 服务器读取位号值 * 从 OPC DA 服务器读取位号值
* <p> * <p>

View File

@@ -1,11 +1,9 @@
package org.nl.iot.core.driver.protocol.opcua; package org.nl.iot.core.driver.protocol.opcua;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient; import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider; 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.UaException;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue; import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId; 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.Variant;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned; 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.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.WriteValue;
import org.nl.common.exception.CommonException; 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.ProtocolDriver;
import org.nl.iot.core.driver.ProtocolType; import org.nl.iot.core.driver.ProtocolType;
import org.nl.iot.core.driver.bo.DeviceBO; 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.entity.WValue;
import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum; import org.nl.iot.core.driver.enums.MetadataOperateTypeEnum;
import org.nl.iot.core.driver.enums.PointTypeFlagEnum; import org.nl.iot.core.driver.enums.PointTypeFlagEnum;
import org.nl.iot.core.driver.service.DriverCustomService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import jakarta.annotation.PreDestroy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; 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 @Slf4j
@Service @Service
@ProtocolDriver(ProtocolType.OPCUA) @ProtocolDriver(ProtocolType.OPCUA)
public class OpcUaProtocolDriverImpl implements DriverCustomService { public class OpcUaProtocolDriverImpl extends AbstractProtocolDriver<OpcUaClient> {
private Map<String, OpcUaClient> connectMap;
@PostConstruct public OpcUaProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) {
@Override super(mappingManager);
public void initial() {
/*
* 驱动初始化逻辑
*
* 提示: 此处逻辑仅供参考, 请务必结合实际应用场景进行修改。
* 驱动启动时会自动执行该方法, 您可以在此处执行特定的初始化操作。
*
*/
connectMap = new ConcurrentHashMap<>(16);
} }
// @PreDestroy @Override
// public void destroy() { public void initial() {
// // 应用关闭时清理所有连接
// log.info("Cleaning up OPC UA connections..."); }
// connectMap.values().forEach(client -> {
// try { @Override
// client.disconnect().get(5, TimeUnit.SECONDS); protected void closeConnection(OpcUaClient client) {
// } catch (Exception e) { try {
// log.warn("Error disconnecting OPC UA client during cleanup: {}", e.getMessage()); client.disconnect().get(5, TimeUnit.SECONDS);
// } } catch (Exception e) {
// }); log.error("Error disconnecting OPC UA client during cleanup: {}", e.getMessage());
// connectMap.clear(); }
// log.info("OPC UA connections cleanup completed"); }
// }
@Override @Override
public void schedule() { public void schedule() {
@@ -171,10 +159,10 @@ public class OpcUaProtocolDriverImpl implements DriverCustomService {
.setSessionTimeout(Unsigned.uint(60000)) // 设置会话超时时间为 60 秒 .setSessionTimeout(Unsigned.uint(60000)) // 设置会话超时时间为 60 秒
.build() .build()
); );
connectMap.put(device.getId(), opcUaClient); addOPCUAConnection(device.getId(), opcUaClient);
log.info("Created new OPC UA client for device: {}", device.getId()); log.info("Created new OPC UA client for device: {}", device.getId());
} catch (UaException e) { } 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); log.error("Failed to create OPC UA client: {}", e.getMessage(), e);
throw new IllegalArgumentException(e.getMessage()); throw new IllegalArgumentException(e.getMessage());
} }
@@ -182,6 +170,12 @@ public class OpcUaProtocolDriverImpl implements DriverCustomService {
return opcUaClient; return opcUaClient;
} }
// 业务中创建连接时调用父类的addConnection方法
public void addOPCUAConnection(String connectionId, OpcUaClient connection) {
// 传入协议编码OPCUA和连接ID、连接对象
addConnection(connectionId, ProtocolType.OPCUA.getMainCode(), connection);
}
/** /**
* 读取 OPC UA 节点的值 * 读取 OPC UA 节点的值
* *

View File

@@ -1,6 +1,5 @@
package org.nl.iot.core.driver.protocol.plcs7; package org.nl.iot.core.driver.protocol.plcs7;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.plc4x.java.DefaultPlcDriverManager; import org.apache.plc4x.java.DefaultPlcDriverManager;
import org.apache.plc4x.java.api.PlcConnection; 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.types.PlcResponseCode;
import org.apache.plc4x.java.api.value.PlcValue; import org.apache.plc4x.java.api.value.PlcValue;
import org.nl.common.exception.CommonException; 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.ProtocolDriver;
import org.nl.iot.core.driver.ProtocolType; import org.nl.iot.core.driver.ProtocolType;
import org.nl.iot.core.driver.bo.DeviceBO; 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.RValue;
import org.nl.iot.core.driver.entity.WResponse; import org.nl.iot.core.driver.entity.WResponse;
import org.nl.iot.core.driver.entity.WValue; 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.JavaToPlcValueConvertUtil;
import org.nl.iot.core.driver.util.PlcValueConvertUtil; 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 org.springframework.stereotype.Service;
import java.util.*; import java.util.ArrayList;
import java.util.concurrent.*; 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 @Slf4j
@Service @Service
@ProtocolDriver(ProtocolType.PLCS7) @ProtocolDriver(ProtocolType.PLCS7)
public class PlcS7ProtocolDriverImpl implements DriverCustomService { public class PlcS7ProtocolDriverImpl extends AbstractProtocolDriver<PlcConnection> {
/** public PlcS7ProtocolDriverImpl(ConnectionProtocolMappingManager mappingManager) {
* Plc Connector Map super(mappingManager);
* 仅供参考 }
*/
private Map<String, PlcConnection> connectMap;
@PostConstruct
@Override @Override
public void initial() { public void initial() {
connectMap = new ConcurrentHashMap<>(16);
} }
@Override @Override
@@ -58,12 +57,21 @@ public class PlcS7ProtocolDriverImpl implements DriverCustomService {
@Override @Override
public void event(MetadataEventDTO metadataEvent) { public void event(MetadataEventDTO metadataEvent) {
MetadataOperateTypeEnum operateType = metadataEvent.getOperateType(); // MetadataOperateTypeEnum operateType = metadataEvent.getOperateType();
log.info("Device metadata event: connectId: {}, operate: {}", metadataEvent.getConnectId(), operateType); // 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 @Override
if (MetadataOperateTypeEnum.DELETE.equals(operateType) || MetadataOperateTypeEnum.UPDATE.equals(operateType)) { protected void closeConnection(PlcConnection connection) {
connectMap.remove(metadataEvent.getConnectId()); try {
connection.close();
} catch (Exception e) {
log.warn("关闭失败:{}", e.getMessage());
} }
} }
@@ -145,7 +153,7 @@ public class PlcS7ProtocolDriverImpl implements DriverCustomService {
String connectionUrl = PlcS7Utils.getS7ConnectionUrl(deviceBO); String connectionUrl = PlcS7Utils.getS7ConnectionUrl(deviceBO);
log.info("创建S7连接deviceId: {}, url: {}", deviceId, connectionUrl); log.info("创建S7连接deviceId: {}, url: {}", deviceId, connectionUrl);
connection = new DefaultPlcDriverManager().getConnection(connectionUrl); connection = new DefaultPlcDriverManager().getConnection(connectionUrl);
connectMap.put(deviceId, connection); addPlcS7Connection(deviceBO.getId(), connection);
} }
return connection; return connection;
} catch (Exception e) { } 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<SiteBO> points) { public static PlcReadRequest.Builder doBuildReadRequest(PlcConnection s7Connection, List<SiteBO> points) {
try { try {
PlcReadRequest.Builder readBuilder = s7Connection.readRequestBuilder(); PlcReadRequest.Builder readBuilder = s7Connection.readRequestBuilder();

View File

@@ -16,8 +16,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.nl.common.pojo.CommonResult; 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.IotConnect;
import org.nl.iot.modular.iot.entity.IotConfig; import org.nl.iot.modular.iot.entity.IotConfig;
import org.nl.iot.modular.iot.service.IotConfigService; import org.nl.iot.modular.iot.service.IotConfigService;
@@ -43,6 +45,8 @@ public class IotConnectController {
@Autowired @Autowired
private IotConfigService iotConfigService; private IotConfigService iotConfigService;
@Resource
private DriverConnectionManager connectionManager;
/** /**
* 获取连接列表 * 获取连接列表
@@ -92,6 +96,7 @@ public class IotConnectController {
@PostMapping("/edit") @PostMapping("/edit")
public CommonResult edit(@RequestBody IotConnect connect) { public CommonResult edit(@RequestBody IotConnect connect) {
iotConnectService.updateById(connect); iotConnectService.updateById(connect);
connectionManager.removeConnectionById(connect.getId().toString());
return CommonResult.ok(); return CommonResult.ok();
} }
@@ -110,7 +115,7 @@ public class IotConnectController {
if (count > 0) { if (count > 0) {
throw new CommonException("连接已被信号配置使用,无法删除"); throw new CommonException("连接已被信号配置使用,无法删除");
} }
iotConnectService.removeById(connect.getId()); connectionManager.removeConnectionById(connect.getId().toString());
return CommonResult.ok(); return CommonResult.ok();
} }
@@ -128,6 +133,9 @@ public class IotConnectController {
throw new CommonException("所选连接存在信号配置,无法删除"); throw new CommonException("所选连接存在信号配置,无法删除");
} }
} }
for (Integer id : ids) {
connectionManager.removeConnectionById(String.valueOf(id));
}
iotConnectService.removeBatchByIds(ids); iotConnectService.removeBatchByIds(ids);
return CommonResult.ok(); return CommonResult.ok();
} }