From 9900f4b007a2c7c3f8ce4b375ff3fa706d75b381 Mon Sep 17 00:00:00 2001 From: liyongde <1419499670@qq.com> Date: Fri, 20 Mar 2026 17:19:29 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E8=AE=BE=E5=A4=87=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E4=B8=8E=E8=87=AA=E5=8A=A8=E5=A1=AB=E5=85=85/?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/cache/CacheRefreshController.java | 76 ++++++++ .../iot/core/cache/MetadataCacheManager.java | 163 ++++++++++++++++++ .../nl/iot/core/driver/bo/ConnectSiteDO.java | 60 +++++++ ...{DeviceBO.java => DeviceConnectionBO.java} | 4 +- .../core/driver/bo/DeviceInfoReadCacheDo.java | 23 +++ .../org/nl/iot/core/driver/entity/RValue.java | 6 +- .../modbustcp/ModBusProtocolDriverImpl.java | 30 ++-- .../modbustcp/util/ModBusTcpUtils.java | 13 +- .../opcda/OpcDaProtocolDriverImpl.java | 58 +++---- .../opcua/OpcUaProtocolDriverImpl.java | 20 +-- .../plcs7/PlcS7ProtocolDriverImpl.java | 34 ++-- .../protocol/plcs7/util/PlcS7Utils.java | 10 +- .../driver/service/DriverCustomService.java | 14 +- .../schedule/AutoReadAllSignalTaskRunner.java | 54 ++++++ .../modular/iot/mapper/IotConfigMapper.java | 4 + .../iot/mapper/mapping/IotConfigMapper.xml | 26 +++ .../modular/iot/service/IotConfigService.java | 9 + .../service/impl/IotConfigServiceImpl.java | 10 +- nl-web-app/src/test/java/org/nl/ApiTest.java | 67 ++++--- 19 files changed, 546 insertions(+), 135 deletions(-) create mode 100644 nl-iot/src/main/java/org/nl/iot/core/cache/CacheRefreshController.java create mode 100644 nl-iot/src/main/java/org/nl/iot/core/cache/MetadataCacheManager.java create mode 100644 nl-iot/src/main/java/org/nl/iot/core/driver/bo/ConnectSiteDO.java rename nl-iot/src/main/java/org/nl/iot/core/driver/bo/{DeviceBO.java => DeviceConnectionBO.java} (91%) create mode 100644 nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceInfoReadCacheDo.java create mode 100644 nl-iot/src/main/java/org/nl/iot/core/schedule/AutoReadAllSignalTaskRunner.java create mode 100644 nl-iot/src/main/java/org/nl/iot/modular/iot/mapper/mapping/IotConfigMapper.xml diff --git a/nl-iot/src/main/java/org/nl/iot/core/cache/CacheRefreshController.java b/nl-iot/src/main/java/org/nl/iot/core/cache/CacheRefreshController.java new file mode 100644 index 0000000..fa3b9d1 --- /dev/null +++ b/nl-iot/src/main/java/org/nl/iot/core/cache/CacheRefreshController.java @@ -0,0 +1,76 @@ +package org.nl.iot.core.cache; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.nl.common.pojo.CommonResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 缓存刷新控制器 + * 提供手动刷新缓存的接口 + * + * @author: lyd + * @date: 2026/03/20 + */ +@Slf4j +@RestController +@RequestMapping("/iot/cache") +@Tag(name = "IoT缓存管理") +public class CacheRefreshController { + + @Autowired + private MetadataCacheManager cacheManager; + + @Operation(summary = "刷新所有缓存") + @PostMapping("/refresh/all") + public CommonResult refreshAll() { + try { + cacheManager.refreshAll(); + return CommonResult.ok("缓存刷新成功"); + } catch (Exception e) { + log.error("刷新缓存失败", e); + return CommonResult.error("缓存刷新失败: " + e.getMessage()); + } + } + + @Operation(summary = "刷新指定设备缓存") + @PostMapping("/refresh/device/{deviceCode}") + public CommonResult refreshDevice(@PathVariable String deviceCode) { + try { +// cacheManager.refreshDevice(deviceCode); +// cacheManager.refreshDevicePoints(deviceCode); + return CommonResult.ok("设备缓存刷新成功"); + } catch (Exception e) { + log.error("刷新设备缓存失败", e); + return CommonResult.error("设备缓存刷新失败: " + e.getMessage()); + } + } + + @Operation(summary = "清空所有缓存") + @PostMapping("/clear") + public CommonResult clearAll() { + try { + cacheManager.clearAll(); + return CommonResult.ok("缓存清空成功"); + } catch (Exception e) { + log.error("清空缓存失败", e); + return CommonResult.error("缓存清空失败: " + e.getMessage()); + } + } + + @Operation(summary = "获取缓存统计信息") + @GetMapping("/stats") + public CommonResult> getCacheStats() { + try { + Map stats = cacheManager.getCacheStats(); + return CommonResult.data(stats); + } catch (Exception e) { + log.error("获取缓存统计失败", e); + return CommonResult.error("获取缓存统计失败: " + e.getMessage()); + } + } +} diff --git a/nl-iot/src/main/java/org/nl/iot/core/cache/MetadataCacheManager.java b/nl-iot/src/main/java/org/nl/iot/core/cache/MetadataCacheManager.java new file mode 100644 index 0000000..9865984 --- /dev/null +++ b/nl-iot/src/main/java/org/nl/iot/core/cache/MetadataCacheManager.java @@ -0,0 +1,163 @@ +package org.nl.iot.core.cache; + +import lombok.extern.slf4j.Slf4j; +import org.nl.iot.core.driver.bo.ConnectSiteDO; +import org.nl.iot.core.driver.bo.DeviceConnectionBO; +import org.nl.iot.core.driver.bo.DeviceInfoReadCacheDo; +import org.nl.iot.core.driver.bo.SiteBO; +import org.nl.iot.modular.iot.service.IotConfigService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 元数据缓存管理器 + * 启动时加载设备和点位信息到内存,避免频繁查询数据库 + * + * @author: lyd + * @date: 2026/03/20 + */ +@Slf4j +@Component +public class MetadataCacheManager implements CommandLineRunner { + + @Autowired + private IotConfigService configService; + + private final Map deviceInfoCache = new ConcurrentHashMap<>(); + + @Override + public void run(String... args) throws Exception { + log.info("开始加载IoT元数据到内存..."); + long startTime = System.currentTimeMillis(); + + try { + loadMetadata(); + long duration = System.currentTimeMillis() - startTime; + log.info("IoT元数据加载完成,耗时: {}ms, 设备信息缓存数: {}", + duration, deviceInfoCache.size()); + } catch (Exception e) { + log.error("IoT元数据加载失败", e); + throw e; + } + } + + /** + * 加载所有元数据 + */ + public void loadMetadata() { + // 加载设备信息映射 + loadDeviceInfoMap(); + } + + private void loadDeviceInfoMap() { + // 获取所有设备 + List devices = configService.getAllDeviceInfo(); + + if (devices == null || devices.isEmpty()) { + log.warn("未查询到设备信息"); + return; + } + + deviceInfoCache.clear(); + + // 按 connectCode.deviceCode 分组 + Map> groupedDevices = devices.stream() + .collect(Collectors.groupingBy(device -> + device.getConnectCode() + "." + device.getDeviceCode() + )); + + // 构建缓存 + for (Map.Entry> entry : groupedDevices.entrySet()) { + String key = entry.getKey(); + List deviceList = entry.getValue(); + + if (deviceList.isEmpty()) { + continue; + } + + // 取第一个元素构建设备连接信息(同一组的连接信息相同) + ConnectSiteDO firstDevice = deviceList.get(0); + + // 构建 DeviceConnectionBO + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() + .id(firstDevice.getConnectId()) + .code(firstDevice.getDeviceCode()) + .host(firstDevice.getHost()) + .port(firstDevice.getPort()) + .protocol(firstDevice.getProtocol()) + .collectMode(firstDevice.getCollectMode()) + .properties(firstDevice.getProperties()) + .build(); + + // 构建 SiteBO 列表 + List siteBOList = deviceList.stream() + .map(device -> SiteBO.builder() + .deviceCode(device.getDeviceCode()) + .alias(device.getAlias()) + .registerAddress(device.getRegisterAddress()) + .aliasName(device.getAliasName()) + .dataType(device.getDataType()) + .readonly(device.getReadonly()) + .build()) + .collect(Collectors.toList()); + + // 构建 DeviceInfoReadCacheDo 并存入缓存 + DeviceInfoReadCacheDo cacheData = DeviceInfoReadCacheDo.builder() + .deviceConnectionBO(deviceConnectionBO) + .siteBOS(siteBOList) + .build(); + + deviceInfoCache.put(key, cacheData); + } + + log.info("加载设备信息映射完成,数量: {}", deviceInfoCache.size()); + } + + // ==================== 公共查询方法 ==================== + + /** + * 根据 connectCode.deviceCode 获取设备信息缓存 + */ + public DeviceInfoReadCacheDo getDeviceInfoCache(String connectCode, String deviceCode) { + String key = connectCode + "." + deviceCode; + return deviceInfoCache.get(key); + } + + /** + * 获取所有设备信息缓存 + * 防御性拷贝设计 模式 + */ + public Map getAllDeviceInfoCache() { + return new HashMap<>(deviceInfoCache); + } + + /** + * 刷新所有缓存 + */ + public void refreshAll() { + log.info("开始刷新所有元数据缓存..."); + loadMetadata(); + } + + /** + * 清空所有缓存 + */ + public void clearAll() { + deviceInfoCache.clear(); + log.info("已清空所有元数据缓存"); + } + + /** + * 获取缓存统计信息 + */ + public Map getCacheStats() { + Map stats = new HashMap<>(); + stats.put("deviceInfoCacheCount", deviceInfoCache.size()); + return stats; + } +} diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/bo/ConnectSiteDO.java b/nl-iot/src/main/java/org/nl/iot/core/driver/bo/ConnectSiteDO.java new file mode 100644 index 0000000..5967f78 --- /dev/null +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/bo/ConnectSiteDO.java @@ -0,0 +1,60 @@ +package org.nl.iot.core.driver.bo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +/** + * 连接+配置实体 + * @Author: liyongde + * @Date: 2026/3/20 15:08 + * @Modified By: + */ +@Getter +@Setter +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class ConnectSiteDO { + /** ----- 连接信息 ----- **/ + @Schema(description = "连接ID") + private String connectId; + + @Schema(description = "连接编码") + private String connectCode; + + @Schema(description = "主机地址/IP") + private String host; + + @Schema(description = "端口") + private Integer port; + + @Schema(description = "协议") + private String protocol; + + @Schema(description = "采集模式 - 暂时用不到") + private String collectMode; + + @Schema(description = "扩展参数(JSON)") + private String properties; + + /** ----- 信号点位信息 ----- **/ + + @Schema(description = "设备号 - iot_device 的code") + private String deviceCode; + + @Schema(description = "信号别名") + private String alias; + + @Schema(description = "寄存器地址") + private String registerAddress; + + @Schema(description = "别名含义") + private String aliasName; + + @Schema(description = "数据类型") + private String dataType; + + @Schema(description = "只读(1只读/0可写)") + private Boolean readonly; +} diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceBO.java b/nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceConnectionBO.java similarity index 91% rename from nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceBO.java rename to nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceConnectionBO.java index 7511194..e01cfa5 100644 --- a/nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceBO.java +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceConnectionBO.java @@ -6,7 +6,7 @@ import lombok.*; import java.io.Serializable; /** - * 设备BO + * 设备连接BO * @author: lyd * @date: 2026/3/11 */ @@ -16,7 +16,7 @@ import java.io.Serializable; @ToString @NoArgsConstructor @AllArgsConstructor -public class DeviceBO implements Serializable { +public class DeviceConnectionBO implements Serializable { @Schema(description = "连接ID") private String id; diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceInfoReadCacheDo.java b/nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceInfoReadCacheDo.java new file mode 100644 index 0000000..b5d9075 --- /dev/null +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/bo/DeviceInfoReadCacheDo.java @@ -0,0 +1,23 @@ +package org.nl.iot.core.driver.bo; + +import lombok.*; + +import java.util.List; + +/** + * 设备读取的缓存实体 + * @Author: liyongde + * @Date: 2026/3/20 14:57 + * @Modified By: + */ +@Getter +@Setter +@Builder +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class DeviceInfoReadCacheDo { + + private DeviceConnectionBO deviceConnectionBO; + private List siteBOS; +} diff --git a/nl-iot/src/main/java/org/nl/iot/core/driver/entity/RValue.java b/nl-iot/src/main/java/org/nl/iot/core/driver/entity/RValue.java index 17fffb7..4b0ce82 100644 --- a/nl-iot/src/main/java/org/nl/iot/core/driver/entity/RValue.java +++ b/nl-iot/src/main/java/org/nl/iot/core/driver/entity/RValue.java @@ -1,10 +1,8 @@ package org.nl.iot.core.driver.entity; import lombok.*; -import org.nl.iot.core.driver.bo.DeviceBO; +import org.nl.iot.core.driver.bo.DeviceConnectionBO; import org.nl.iot.core.driver.bo.SiteBO; -import org.nl.iot.modular.iot.entity.IotConfig; -import org.nl.iot.modular.iot.entity.IotConnect; /** * 读数据的值 @@ -22,7 +20,7 @@ public class RValue { /** * 连接参数 */ - private DeviceBO deviceBO; + private DeviceConnectionBO deviceConnectionBO; /** * 配置 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 c5d86b6..5345e39 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 @@ -14,7 +14,7 @@ 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; +import org.nl.iot.core.driver.bo.DeviceConnectionBO; import org.nl.iot.core.driver.bo.MetadataEventDTO; import org.nl.iot.core.driver.bo.SiteBO; import org.nl.iot.core.driver.entity.RValue; @@ -67,22 +67,22 @@ public class ModBusProtocolDriverImpl extends AbstractProtocolDriver batchRead(DeviceBO device, List points) { + public List batchRead(DeviceConnectionBO device, List points) { return batchReadValue(getConnector(device), device, points); } @Override - public Boolean write(DeviceBO device, WValue wValue) { + public Boolean write(DeviceConnectionBO device, WValue wValue) { return writeValue(getConnector(device), device, wValue); } @Override - public List batchWrite(DeviceBO device, List wValue) { + public List batchWrite(DeviceConnectionBO device, List wValue) { return batchWriteValue(getConnector(device), wValue); } @@ -122,13 +122,13 @@ public class ModBusProtocolDriverImpl extends AbstractProtocolDriver batchReadValue(PlcConnection modbusMaster, DeviceBO deviceBO, List points) { + public List batchReadValue(PlcConnection modbusMaster, DeviceConnectionBO deviceConnectionBO, List points) { // 1. 解析配置 PlcReadRequest.Builder readBuilder = doBuildReadRequest(modbusMaster, points); // 3. 执行请求 @@ -182,16 +182,16 @@ public class ModBusProtocolDriverImpl extends AbstractProtocolDriver { server = new Server(connectionInformation, Executors.newSingleThreadScheduledExecutor()); try { server.connect(); - addOpcDaConnection(deviceBO.getId(), server); + addOpcDaConnection(deviceConnectionBO.getId(), server); } catch (AlreadyConnectedException | UnknownHostException | JIException e) { - removeConnection(deviceBO.getId()); + removeConnection(deviceConnectionBO.getId()); log.error("Connect opc da server error: {}", e.getMessage(), e); throw new CommonException(e.getMessage()); } @@ -129,9 +129,9 @@ public class OpcDaProtocolDriverImpl extends AbstractProtocolDriver { * 该方法通过给定的 OPC DA 服务器和位号配置, 获取对应的 Item 对象, 并读取其值。 * 如果在读取过程中发生异常, 将断开服务器连接并抛出 {@link ReadPointException}。 */ - private String readValue(Server server, DeviceBO deviceBO, SiteBO siteBO) { + private String readValue(Server server, DeviceConnectionBO deviceConnectionBO, SiteBO siteBO) { try { - Item item = getItem(server, deviceBO, siteBO); + Item item = getItem(server, deviceConnectionBO, siteBO); return readItem(item); } catch (NotConnectedException | JIException | AddFailedException | DuplicateGroupException | UnknownHostException e) { @@ -142,13 +142,13 @@ public class OpcDaProtocolDriverImpl extends AbstractProtocolDriver { } @SneakyThrows - private List batchReadValue(Server server, DeviceBO deviceBO, List points) { + private List batchReadValue(Server server, DeviceConnectionBO deviceConnectionBO, List points) { List res = new ArrayList<>(); - Map itemsMap = getItems(server, deviceBO, points); + Map itemsMap = getItems(server, deviceConnectionBO, points); for (Item item : itemsMap.values()) { RValue rValue = new RValue(); - rValue.setDeviceBO(deviceBO); - SiteBO site = findSite(points, deviceBO, item.getId()); + rValue.setDeviceConnectionBO(deviceConnectionBO); + SiteBO site = findSite(points, deviceConnectionBO, item.getId()); rValue.setSiteBO(ObjectUtil.isNotEmpty(site) ? site : null); try { // 组装数据 @@ -164,7 +164,7 @@ public class OpcDaProtocolDriverImpl extends AbstractProtocolDriver { return res; } - public List batchWriteValue(DeviceBO device, List wValues) { + public List batchWriteValue(DeviceConnectionBO device, List wValues) { Server server = getConnector(device); List list = new ArrayList<>(); for (WValue wValue : wValues) { @@ -185,35 +185,35 @@ public class OpcDaProtocolDriverImpl extends AbstractProtocolDriver { * 如果组不存在, 则创建新的组;如果组已存在, 则直接使用该组。 * */ - public Item getItem(Server server, DeviceBO deviceBO, SiteBO siteBO) throws NotConnectedException, JIException, UnknownHostException, DuplicateGroupException, AddFailedException { + public Item getItem(Server server, DeviceConnectionBO deviceConnectionBO, SiteBO siteBO) throws NotConnectedException, JIException, UnknownHostException, DuplicateGroupException, AddFailedException { Group group; - String groupName = deviceBO.getCode(); + String groupName = deviceConnectionBO.getCode(); try { group = server.findGroup(groupName); } catch (UnknownGroupException e) { group = server.addGroup(groupName); } - return group.addItem(groupName + "." + siteBO.getDeviceCode() + "." + siteBO.getAlias()); + return group.addItem(groupName + "." + groupName + "." + siteBO.getDeviceCode() + "." + siteBO.getAlias()); } @SneakyThrows - public Map getItems(Server server, DeviceBO deviceBO, List points) { + public Map getItems(Server server, DeviceConnectionBO deviceConnectionBO, List points) { Group group; - String groupName = deviceBO.getCode(); + String groupName = deviceConnectionBO.getCode(); try { group = server.findGroup(groupName); } catch (UnknownGroupException e) { group = server.addGroup(groupName); } String[] arr = points.stream() - .map(site -> groupName + "." + site.getDeviceCode() + "." + site.getAlias()) + .map(site -> groupName + "." + groupName + "." + site.getDeviceCode() + "." + site.getAlias()) .toArray(String[]::new); return group.addItems(arr); } - public SiteBO findSite(List points, DeviceBO deviceBO, String key) { + public SiteBO findSite(List points, DeviceConnectionBO deviceConnectionBO, String key) { for (SiteBO point : points) { - String itemKey = deviceBO.getCode() + "." + point.getDeviceCode() + "." + point.getAlias(); + String itemKey = deviceConnectionBO.getCode() + "." + point.getDeviceCode() + "." + point.getAlias(); if (itemKey.equals(key)) { return point; } @@ -249,9 +249,9 @@ public class OpcDaProtocolDriverImpl extends AbstractProtocolDriver { * @return boolean 返回写入操作是否成功 * @throws WritePointException 如果写入位号值时发生异常, 则抛出此异常 */ - private Boolean writeValue(Server server, DeviceBO deviceBO, WValue wValue) { + private Boolean writeValue(Server server, DeviceConnectionBO deviceConnectionBO, WValue wValue) { try { - Item item = getItem(server, deviceBO, wValue.getPoint()); + Item item = getItem(server, deviceConnectionBO, wValue.getPoint()); return writeItem(item, wValue); } catch (NotConnectedException | AddFailedException | DuplicateGroupException | UnknownHostException | JIException e) { 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 b127090..7679ad3 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 @@ -16,7 +16,7 @@ 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; +import org.nl.iot.core.driver.bo.DeviceConnectionBO; import org.nl.iot.core.driver.bo.MetadataEventDTO; import org.nl.iot.core.driver.bo.SiteBO; import org.nl.iot.core.driver.entity.RValue; @@ -82,23 +82,23 @@ public class OpcUaProtocolDriverImpl extends AbstractProtocolDriver } @Override - public RValue read(DeviceBO device, SiteBO point) { + public RValue read(DeviceConnectionBO device, SiteBO point) { return readValue(device, point); } @Override - public Boolean write(DeviceBO device, WValue wValue) { + public Boolean write(DeviceConnectionBO device, WValue wValue) { OpcUaClient client = getConnector(device); return writeValue(client, device, wValue); } @Override - public List batchRead(DeviceBO device, List point) { + public List batchRead(DeviceConnectionBO device, List point) { return batchReadValue(getConnector(device), device, point); } @Override - public List batchWrite(DeviceBO device, List wValue) { + public List batchWrite(DeviceConnectionBO device, List wValue) { int maxRetries = 2; // 最大重试次数 for (int retry = 0; retry <= maxRetries; retry++) { @@ -139,7 +139,7 @@ public class OpcUaProtocolDriverImpl extends AbstractProtocolDriver /** * 获取 OPC UA 客户端连接 */ - private OpcUaClient getConnector(DeviceBO device) { + private OpcUaClient getConnector(DeviceConnectionBO device) { log.debug("OPC UA server connection info: {}", device); OpcUaClient opcUaClient = connectMap.get(device.getId()); @@ -183,7 +183,7 @@ public class OpcUaProtocolDriverImpl extends AbstractProtocolDriver * @param point 点位配置信息 * @return 读取到的节点值 */ - private RValue readValue(DeviceBO device, SiteBO point) { + private RValue readValue(DeviceConnectionBO device, SiteBO point) { int maxRetries = 2; // 最大重试次数 for (int retry = 0; retry <= maxRetries; retry++) { @@ -236,7 +236,7 @@ public class OpcUaProtocolDriverImpl extends AbstractProtocolDriver * @param point * @return */ - private List batchReadValue(OpcUaClient connector, DeviceBO device, List points) { + private List batchReadValue(OpcUaClient connector, DeviceConnectionBO device, List points) { return batchReadNodes(connector, device, points); } @@ -247,7 +247,7 @@ public class OpcUaProtocolDriverImpl extends AbstractProtocolDriver * @param points 点位列表 * @return 读取结果列表(顺序与nodeIds一致) */ - private List batchReadNodes(OpcUaClient client, DeviceBO device, List points) { + private List batchReadNodes(OpcUaClient client, DeviceConnectionBO device, List points) { List list = new ArrayList<>(); int maxRetries = 2; // 最大重试次数 @@ -348,7 +348,7 @@ public class OpcUaProtocolDriverImpl extends AbstractProtocolDriver /** * 写入 OPC UA 节点的值 */ - private boolean writeValue(OpcUaClient client, DeviceBO device, WValue wValue) { + private boolean writeValue(OpcUaClient client, DeviceConnectionBO device, WValue wValue) { try { NodeId nodeId = NodeId.parse(wValue.getPoint().getRegisterAddress()); // 确保客户端已连接,设置超时时间 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 8be325c..fa95b2d 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 @@ -14,7 +14,7 @@ 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; +import org.nl.iot.core.driver.bo.DeviceConnectionBO; import org.nl.iot.core.driver.bo.MetadataEventDTO; import org.nl.iot.core.driver.bo.SiteBO; import org.nl.iot.core.driver.entity.RValue; @@ -76,7 +76,7 @@ public class PlcS7ProtocolDriverImpl extends AbstractProtocolDriver batchRead(DeviceBO device, List points) { + public List batchRead(DeviceConnectionBO device, List points) { try { return batchReadValue(getS7Connector(device), device, points); } catch (Exception e) { @@ -121,21 +121,21 @@ public class PlcS7ProtocolDriverImpl extends AbstractProtocolDriver batchWrite(DeviceBO device, List wValue) { + public List batchWrite(DeviceConnectionBO device, List wValue) { return batchWriteValue(getS7Connector(device), wValue); } /** * 获取 PLC S7 连接器 */ - private PlcConnection getS7Connector(DeviceBO deviceBO) { + private PlcConnection getS7Connector(DeviceConnectionBO deviceConnectionBO) { try { - String deviceId = deviceBO.getId(); + String deviceId = deviceConnectionBO.getId(); PlcConnection connection = connectMap.get(deviceId); // 检查连接是否有效(核心修复:判断连接是否存在且未关闭) @@ -150,14 +150,14 @@ public class PlcS7ProtocolDriverImpl extends AbstractProtocolDriver batchReadValue(PlcConnection s7Connection, DeviceBO deviceBO, List points) { + public List batchReadValue(PlcConnection s7Connection, DeviceConnectionBO deviceConnectionBO, List points) { List list = new ArrayList<>(); try { // 1. 解析配置 @@ -231,17 +231,17 @@ public class PlcS7ProtocolDriverImpl extends AbstractProtocolDriver batchRead(DeviceBO device, List point); + List batchRead(DeviceConnectionBO device, List point); /** * 执行写操作 */ - Boolean write(DeviceBO device, WValue wValue); + Boolean write(DeviceConnectionBO device, WValue wValue); /** * 批量写 @@ -63,6 +59,6 @@ public interface DriverCustomService { * @param wValue * @return */ - List batchWrite(DeviceBO device, List wValue); + List batchWrite(DeviceConnectionBO device, List wValue); } diff --git a/nl-iot/src/main/java/org/nl/iot/core/schedule/AutoReadAllSignalTaskRunner.java b/nl-iot/src/main/java/org/nl/iot/core/schedule/AutoReadAllSignalTaskRunner.java new file mode 100644 index 0000000..de8dd53 --- /dev/null +++ b/nl-iot/src/main/java/org/nl/iot/core/schedule/AutoReadAllSignalTaskRunner.java @@ -0,0 +1,54 @@ +package org.nl.iot.core.schedule; + +import lombok.extern.slf4j.Slf4j; +import org.nl.common.timer.CommonTimerTaskRunner; +import org.nl.iot.core.cache.MetadataCacheManager; +import org.nl.iot.core.driver.DriverCustomFactory; +import org.nl.iot.core.driver.bo.DeviceConnectionBO; +import org.nl.iot.core.driver.bo.DeviceInfoReadCacheDo; +import org.nl.iot.core.driver.bo.SiteBO; +import org.nl.iot.core.driver.entity.RValue; +import org.nl.iot.core.driver.service.DriverCustomService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +/** + * 定时器 + *

定时读取设备数据 + *

组装的数据:连接编码.设备编码.信号编码 -> 对应的值(已经String化) + * @Author: liyongde + * @Date: 2026/3/20 16:14 + * @Modified By: + */ +@Slf4j +@Component +public class AutoReadAllSignalTaskRunner implements CommonTimerTaskRunner { + @Autowired + private MetadataCacheManager metadataCacheManager; + @Autowired + private DriverCustomFactory driverCustomFactory; + + @Override + public void action(String extJson) { + Map allDeviceInfoCache = metadataCacheManager.getAllDeviceInfoCache(); + if (allDeviceInfoCache.isEmpty()) { + log.error("设备缓存为空..."); + return; + } + // 读取 + for (Map.Entry entry : allDeviceInfoCache.entrySet()) { + // 获取Map的Key(这里Key是设备ID,和实体中的deviceId可能相同/不同) + String key = entry.getKey(); + // 获取Map的Value(设备信息对象) + DeviceInfoReadCacheDo deviceInfo = entry.getValue(); + DeviceConnectionBO deviceConnectionBO = deviceInfo.getDeviceConnectionBO(); + List siteBOS = deviceInfo.getSiteBOS(); + DriverCustomService driver = driverCustomFactory.getDriver(deviceConnectionBO.getProtocol()); + List list = driver.batchRead(deviceConnectionBO, siteBOS); + // 组装数据 + } + } +} diff --git a/nl-iot/src/main/java/org/nl/iot/modular/iot/mapper/IotConfigMapper.java b/nl-iot/src/main/java/org/nl/iot/modular/iot/mapper/IotConfigMapper.java index ef5c63e..aaeb444 100644 --- a/nl-iot/src/main/java/org/nl/iot/modular/iot/mapper/IotConfigMapper.java +++ b/nl-iot/src/main/java/org/nl/iot/modular/iot/mapper/IotConfigMapper.java @@ -2,12 +2,16 @@ package org.nl.iot.modular.iot.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; +import org.nl.iot.core.driver.bo.ConnectSiteDO; import org.nl.iot.modular.iot.entity.IotConfig; +import java.util.List; + /** * 信号配置表Mapper */ @Mapper public interface IotConfigMapper extends BaseMapper { + List getAllDeviceInfo(); } diff --git a/nl-iot/src/main/java/org/nl/iot/modular/iot/mapper/mapping/IotConfigMapper.xml b/nl-iot/src/main/java/org/nl/iot/modular/iot/mapper/mapping/IotConfigMapper.xml new file mode 100644 index 0000000..8c30e78 --- /dev/null +++ b/nl-iot/src/main/java/org/nl/iot/modular/iot/mapper/mapping/IotConfigMapper.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/nl-iot/src/main/java/org/nl/iot/modular/iot/service/IotConfigService.java b/nl-iot/src/main/java/org/nl/iot/modular/iot/service/IotConfigService.java index 6121d1f..9dbbc57 100644 --- a/nl-iot/src/main/java/org/nl/iot/modular/iot/service/IotConfigService.java +++ b/nl-iot/src/main/java/org/nl/iot/modular/iot/service/IotConfigService.java @@ -3,9 +3,12 @@ package org.nl.iot.modular.iot.service; import com.baomidou.mybatisplus.extension.service.IService; import cn.hutool.json.JSONObject; import jakarta.servlet.http.HttpServletResponse; +import org.nl.iot.core.driver.bo.ConnectSiteDO; import org.nl.iot.modular.iot.entity.IotConfig; import org.springframework.web.multipart.MultipartFile; +import java.util.List; + /** * 信号配置表Service接口 */ @@ -20,4 +23,10 @@ public interface IotConfigService extends IService { * 导入信号配置 */ JSONObject importConfig(MultipartFile file); + + /** + * 获取所有的设备+连接+配置的关联数据 + * @return + */ + List getAllDeviceInfo(); } diff --git a/nl-iot/src/main/java/org/nl/iot/modular/iot/service/impl/IotConfigServiceImpl.java b/nl-iot/src/main/java/org/nl/iot/modular/iot/service/impl/IotConfigServiceImpl.java index a5ac7c6..da18aa8 100644 --- a/nl-iot/src/main/java/org/nl/iot/modular/iot/service/impl/IotConfigServiceImpl.java +++ b/nl-iot/src/main/java/org/nl/iot/modular/iot/service/impl/IotConfigServiceImpl.java @@ -1,15 +1,16 @@ package org.nl.iot.modular.iot.service.impl; -import com.alibaba.excel.EasyExcel; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import cn.hutool.core.util.ObjectUtil; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; +import com.alibaba.excel.EasyExcel; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.servlet.http.HttpServletResponse; import org.nl.common.exception.CommonException; import org.nl.common.util.CommonDownloadUtil; import org.nl.common.util.CommonResponseUtil; +import org.nl.iot.core.driver.bo.ConnectSiteDO; import org.nl.iot.modular.iot.entity.IotConfig; import org.nl.iot.modular.iot.mapper.IotConfigMapper; import org.nl.iot.modular.iot.param.IotConfigImportParam; @@ -74,6 +75,11 @@ public class IotConfigServiceImpl extends ServiceImpl getAllDeviceInfo() { + return this.baseMapper.getAllDeviceInfo(); + } + private JSONObject doImport(IotConfigImportParam param, int index) { if (ObjectUtil.hasEmpty(param.getConnectId(), param.getSubDeviceId(), param.getAlias(), param.getRegisterAddress(), param.getAliasName(), param.getDataType())) { diff --git a/nl-web-app/src/test/java/org/nl/ApiTest.java b/nl-web-app/src/test/java/org/nl/ApiTest.java index 482b41c..a76b6dc 100644 --- a/nl-web-app/src/test/java/org/nl/ApiTest.java +++ b/nl-web-app/src/test/java/org/nl/ApiTest.java @@ -6,7 +6,7 @@ import org.junit.runner.RunWith; import org.nl.common.exception.CommonException; import org.nl.iot.core.driver.DriverCustomFactory; import org.nl.iot.core.driver.ProtocolType; -import org.nl.iot.core.driver.bo.DeviceBO; +import org.nl.iot.core.driver.bo.DeviceConnectionBO; import org.nl.iot.core.driver.bo.SiteBO; import org.nl.iot.core.driver.entity.RValue; import org.nl.iot.core.driver.entity.WResponse; @@ -23,7 +23,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -84,7 +83,7 @@ public class ApiTest { System.out.println("数据类型: " + config.getDataType()); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -104,7 +103,7 @@ public class ApiTest { .build(); // 调用驱动读取数据 - RValue result = modBusProtocolDriver.read(deviceBO, siteBO); + RValue result = modBusProtocolDriver.read(deviceConnectionBO, siteBO); System.out.println("读取成功!"); System.out.println("读取结果: " + result.getValue()); @@ -153,7 +152,7 @@ public class ApiTest { System.out.println("数据类型: " + config.getDataType()); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -183,7 +182,7 @@ public class ApiTest { System.out.println("写入值: " + writeValue); // 调用驱动写入数据 - Boolean result = modBusProtocolDriver.write(deviceBO, wValue); + Boolean result = modBusProtocolDriver.write(deviceConnectionBO, wValue); if (result != null && result) { System.out.println("写入成功!"); @@ -269,7 +268,7 @@ public class ApiTest { System.out.println("连接信息: " + connect.getHost() + ":" + connect.getPort()); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -321,7 +320,7 @@ public class ApiTest { } // 调用驱动批量读取数据 - List result = modBusProtocolDriver.batchRead(deviceBO, siteBOList); + List result = modBusProtocolDriver.batchRead(deviceConnectionBO, siteBOList); System.out.println("批量读取成功!"); System.out.println("读取结果:"); @@ -401,7 +400,7 @@ public class ApiTest { System.out.println("连接信息: " + connect.getHost() + ":" + connect.getPort()); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -458,7 +457,7 @@ public class ApiTest { } // 调用驱动批量写入数据 - List result = modBusProtocolDriver.batchWrite(deviceBO, wValueList); + List result = modBusProtocolDriver.batchWrite(deviceConnectionBO, wValueList); System.out.println("批量写入完成!"); System.out.println("写入结果:"); @@ -547,7 +546,7 @@ public class ApiTest { System.out.println("插槽号: " + properties.getString("remote-slot")); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -583,7 +582,7 @@ public class ApiTest { .readonly(config2.getReadonly()) .build(); - RValue result2 = plcS7ProtocolDriver.read(deviceBO, siteBO2); + RValue result2 = plcS7ProtocolDriver.read(deviceConnectionBO, siteBO2); System.out.println("地址: " + config2.getRegisterAddress()); System.out.println("数据类型: " + config2.getDataType()); System.out.println("读取结果: " + result2.getValue()); @@ -677,7 +676,7 @@ public class ApiTest { System.out.println("控制器类型: " + properties.getString("controller-type")); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -721,7 +720,7 @@ public class ApiTest { } // 调用驱动批量读取数据 - List result = plcS7ProtocolDriver.batchRead(deviceBO, siteBOList); + List result = plcS7ProtocolDriver.batchRead(deviceConnectionBO, siteBOList); System.out.println("批量读取完成!"); System.out.println("读取结果:"); @@ -783,7 +782,7 @@ public class ApiTest { System.out.println("数据类型: " + config.getDataType()); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -813,7 +812,7 @@ public class ApiTest { System.out.println("写入值: " + writeValue); // 调用驱动写入数据 - Boolean result = plcS7ProtocolDriver.write(deviceBO, wValue); + Boolean result = plcS7ProtocolDriver.write(deviceConnectionBO, wValue); if (result != null && result) { System.out.println("写入成功!"); @@ -892,7 +891,7 @@ public class ApiTest { System.out.println("控制器类型: " + properties.getString("controller-type")); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -949,7 +948,7 @@ public class ApiTest { } // 调用驱动批量写入数据 - List result = plcS7ProtocolDriver.batchWrite(deviceBO, wValueList); + List result = plcS7ProtocolDriver.batchWrite(deviceConnectionBO, wValueList); System.out.println("批量写入完成!"); System.out.println("写入结果:"); @@ -1032,7 +1031,7 @@ public class ApiTest { System.out.println("服务器路径: " + properties.getString("path")); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -1071,7 +1070,7 @@ public class ApiTest { .readonly(config2.getReadonly()) .build(); - RValue result2 = opcUaProtocolDriver.read(deviceBO, siteBO2); + RValue result2 = opcUaProtocolDriver.read(deviceConnectionBO, siteBO2); System.out.println("节点ID: " + config2.getRegisterAddress()); System.out.println("数据类型: " + config2.getDataType()); System.out.println("读取结果: " + result2.getValue()); @@ -1180,7 +1179,7 @@ public class ApiTest { System.out.println("服务器路径: " + properties.getString("path")); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -1232,7 +1231,7 @@ public class ApiTest { } // 调用驱动批量读取数据 - List result = opcUaProtocolDriver.batchRead(deviceBO, siteBOList); + List result = opcUaProtocolDriver.batchRead(deviceConnectionBO, siteBOList); System.out.println("批量读取完成!"); System.out.println("读取结果:"); @@ -1293,7 +1292,7 @@ public class ApiTest { System.out.println("数据类型: " + config.getDataType()); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -1323,7 +1322,7 @@ public class ApiTest { System.out.println("写入值: " + writeValue); // 调用驱动写入数据 - Boolean result = opcUaProtocolDriver.write(deviceBO, wValue); + Boolean result = opcUaProtocolDriver.write(deviceConnectionBO, wValue); if (result != null && result) { System.out.println("写入成功!"); @@ -1400,7 +1399,7 @@ public class ApiTest { System.out.println("服务器路径: " + properties.getString("path")); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -1457,7 +1456,7 @@ public class ApiTest { } // 调用驱动批量写入数据 - List result = opcUaProtocolDriver.batchWrite(deviceBO, wValueList); + List result = opcUaProtocolDriver.batchWrite(deviceConnectionBO, wValueList); System.out.println("批量写入完成!"); System.out.println("写入结果:"); @@ -1529,7 +1528,7 @@ public class ApiTest { System.out.println("数据类型: " + config.getDataType()); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -1549,7 +1548,7 @@ public class ApiTest { .build(); // 调用驱动读取数据 - RValue result = opcDaProtocolDriver.read(deviceBO, siteBO); + RValue result = opcDaProtocolDriver.read(deviceConnectionBO, siteBO); System.out.println("读取成功!"); System.out.println("读取结果: " + result.getValue()); @@ -1608,7 +1607,7 @@ public class ApiTest { System.out.println("数据类型: " + config.getDataType()); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -1638,7 +1637,7 @@ public class ApiTest { System.out.println("写入值: " + writeValue); // 调用驱动写入数据 - Boolean result = opcDaProtocolDriver.write(deviceBO, wValue); + Boolean result = opcDaProtocolDriver.write(deviceConnectionBO, wValue); if (result != null && result) { System.out.println("写入成功!"); @@ -1730,7 +1729,7 @@ public class ApiTest { System.out.println("用户名: " + properties.getString("username")); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -1782,7 +1781,7 @@ public class ApiTest { } // 调用驱动批量读取数据 - List result = opcDaProtocolDriver.batchRead(deviceBO, siteBOList); + List result = opcDaProtocolDriver.batchRead(deviceConnectionBO, siteBOList); System.out.println("批量读取完成!"); System.out.println("读取结果:"); @@ -1885,7 +1884,7 @@ public class ApiTest { System.out.println("用户名: " + properties.getString("username")); // 转换为DeviceBO - DeviceBO deviceBO = DeviceBO.builder() + DeviceConnectionBO deviceConnectionBO = DeviceConnectionBO.builder() .id(String.valueOf(connect.getId())) .code(connect.getCode()) .properties(connect.getProperties()) @@ -1942,7 +1941,7 @@ public class ApiTest { } // 调用驱动批量写入数据 - List result = opcDaProtocolDriver.batchWrite(deviceBO, wValueList); + List result = opcDaProtocolDriver.batchWrite(deviceConnectionBO, wValueList); System.out.println("批量写入完成!"); System.out.println("写入结果:");