From 9be7d6fac003b9d011288a0a0194126242001a0d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 25 Jan 2026 21:57:22 +0800 Subject: [PATCH] =?UTF-8?q?review=EF=BC=88iot=EF=BC=89=EF=BC=9A=E3=80=90?= =?UTF-8?q?=E5=9C=BA=E6=99=AF=E8=81=94=E5=8A=A8=E3=80=91=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=9A=84=20review=20=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../action/IotWebSocketDataRuleAction.java | 1 + .../action/websocket/IotWebSocketClient.java | 4 +-- .../rule/scene/IotSceneRuleTimeHelper.java | 10 ++++-- .../IotDeviceServiceInvokeTriggerMatcher.java | 10 +++--- .../timer/IotTimerConditionEvaluator.java | 32 +++++++++---------- .../iot/core/util/IotDeviceMessageUtils.java | 9 +++--- 6 files changed, 34 insertions(+), 32 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotWebSocketDataRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotWebSocketDataRuleAction.java index ebfe1f8c10..7471642434 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotWebSocketDataRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotWebSocketDataRuleAction.java @@ -97,6 +97,7 @@ public class IotWebSocketDataRuleAction extends } } + // TODO @puhui999:为什么这里要加锁呀? /** * 使用锁进行重连,保证同一服务器地址的重连操作线程安全 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/websocket/IotWebSocketClient.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/websocket/IotWebSocketClient.java index e898f61cb8..8eba723733 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/websocket/IotWebSocketClient.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/websocket/IotWebSocketClient.java @@ -67,7 +67,6 @@ public class IotWebSocketClient { // 使用 CountDownLatch 等待连接完成 CountDownLatch connectLatch = new CountDownLatch(1); AtomicBoolean connectSuccess = new AtomicBoolean(false); - // 创建 WebSocket 连接 webSocket = okHttpClient.newWebSocket(request, new IotWebSocketListener(connectLatch, connectSuccess)); @@ -77,7 +76,6 @@ public class IotWebSocketClient { close(); throw new Exception("WebSocket 连接超时或失败,服务器地址: " + serverUrl); } - log.info("[connect][WebSocket 客户端连接成功,服务器地址: {}]", serverUrl); } catch (Exception e) { close(); @@ -126,6 +124,7 @@ public class IotWebSocketClient { try { if (webSocket != null) { // 发送正常关闭帧,状态码 1000 表示正常关闭 + // TODO @puhui999:有没 1000 的枚举哈?在 okhttp 里 webSocket.close(1000, "客户端主动关闭"); webSocket = null; } @@ -163,6 +162,7 @@ public class IotWebSocketClient { /** * OkHttp WebSocket 监听器 */ + @SuppressWarnings("NullableProblems") private class IotWebSocketListener extends WebSocketListener { private final CountDownLatch connectLatch; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java index 8d1c1f6292..df1ac239b3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java @@ -4,6 +4,8 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.text.CharPool; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotCurrentTimeConditionMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotTimerConditionEvaluator; import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; @@ -15,8 +17,7 @@ import java.util.List; /** * IoT 场景规则时间匹配工具类 *

- * 提供时间条件匹配的通用方法,供 {@link cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotCurrentTimeConditionMatcher} - * 和 {@link cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotTimerConditionEvaluator} 共同使用。 + * 提供时间条件匹配的通用方法,供 {@link IotCurrentTimeConditionMatcher} 和 {@link IotTimerConditionEvaluator} 共同使用。 * * @author HUIHUI */ @@ -33,6 +34,7 @@ public class IotSceneRuleTimeHelper { */ private static final DateTimeFormatter TIME_FORMATTER_SHORT = DateTimeFormatter.ofPattern("HH:mm"); + // TODO @puhui999:可以使用 lombok 简化 private IotSceneRuleTimeHelper() { // 工具类,禁止实例化 } @@ -94,6 +96,7 @@ public class IotSceneRuleTimeHelper { * @param param 参数值 * @return 是否匹配 */ + @SuppressWarnings("EnhancedSwitchMigration") public static boolean matchDateTime(long currentTimestamp, IotSceneRuleConditionOperatorEnum operatorEnum, String param) { try { @@ -133,6 +136,7 @@ public class IotSceneRuleTimeHelper { } long startTimestamp = Long.parseLong(timestampRange.get(0).trim()); long endTimestamp = Long.parseLong(timestampRange.get(1).trim()); + // TODO @puhui999:hutool 里,看看有没 between 方法 return currentTimestamp >= startTimestamp && currentTimestamp <= endTimestamp; } @@ -144,6 +148,7 @@ public class IotSceneRuleTimeHelper { * @param param 参数值 * @return 是否匹配 */ + @SuppressWarnings("EnhancedSwitchMigration") public static boolean matchTime(LocalTime currentTime, IotSceneRuleConditionOperatorEnum operatorEnum, String param) { try { @@ -183,6 +188,7 @@ public class IotSceneRuleTimeHelper { } LocalTime startTime = parseTime(timeRange.get(0).trim()); LocalTime endTime = parseTime(timeRange.get(1).trim()); + // TODO @puhui999:hutool 里,看看有没 between 方法 return !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java index ba3190068d..642fb5ecb5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java @@ -31,13 +31,11 @@ public class IotDeviceServiceInvokeTriggerMatcher implements IotSceneRuleTrigger IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); return false; } - // 1.2 检查消息方法是否匹配 if (!IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod().equals(message.getMethod())) { IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "消息方法不匹配,期望: " + IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod() + ", 实际: " + message.getMethod()); return false; } - // 1.3 检查标识符是否匹配 String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message); if (!IotSceneRuleMatcherHelper.isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) { @@ -73,21 +71,21 @@ public class IotDeviceServiceInvokeTriggerMatcher implements IotSceneRuleTrigger * @return 是否匹配 */ private boolean matchParameterCondition(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { - // 从消息中提取服务调用的输入参数 + // 1.1 从消息中提取服务调用的输入参数 Map inputParams = IotDeviceMessageUtils.extractServiceInputParams(message); + // TODO @puhui999:要考虑 empty 的情况么? if (inputParams == null) { IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "消息中缺少服务输入参数"); return false; } - - // 获取要匹配的参数值(使用 identifier 作为参数名) + // 1.2 获取要匹配的参数值(使用 identifier 作为参数名) Object paramValue = inputParams.get(trigger.getIdentifier()); if (paramValue == null) { IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "服务输入参数中缺少指定参数: " + trigger.getIdentifier()); return false; } - // 使用条件评估器进行匹配 + // 2. 使用条件评估器进行匹配 boolean matched = IotSceneRuleMatcherHelper.evaluateCondition(paramValue, trigger.getOperator(), trigger.getValue()); if (matched) { IotSceneRuleMatcherHelper.logTriggerMatchSuccess(message, trigger); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/timer/IotTimerConditionEvaluator.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/timer/IotTimerConditionEvaluator.java index d8fe8183bf..75f4e2ed51 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/timer/IotTimerConditionEvaluator.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/timer/IotTimerConditionEvaluator.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.scene.timer; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; @@ -40,14 +41,14 @@ public class IotTimerConditionEvaluator { * @param condition 条件配置 * @return 是否满足条件 */ + @SuppressWarnings("EnhancedSwitchMigration") public boolean evaluate(IotSceneRuleDO.TriggerCondition condition) { - // 1. 基础参数校验 + // 1.1 基础参数校验 if (condition == null || condition.getType() == null) { log.warn("[evaluate][条件为空或类型为空]"); return false; } - - // 2. 根据条件类型分发到具体的评估方法 + // 1.2 根据条件类型分发到具体的评估方法 IotSceneRuleConditionTypeEnum conditionType = IotSceneRuleConditionTypeEnum.typeOf(condition.getType()); if (conditionType == null) { @@ -55,6 +56,7 @@ public class IotTimerConditionEvaluator { return false; } + // 2. 分发评估 switch (conditionType) { case DEVICE_PROPERTY: return evaluateDevicePropertyCondition(condition); @@ -89,15 +91,14 @@ public class IotTimerConditionEvaluator { return false; } - // 2. 获取设备最新属性值 + // 2.1 获取设备最新属性值 Map properties = devicePropertyService.getLatestDeviceProperties(condition.getDeviceId()); - if (properties == null || properties.isEmpty()) { + if (CollUtil.isEmpty(properties)) { log.debug("[evaluateDevicePropertyCondition][设备({}) 无属性数据]", condition.getDeviceId()); return false; } - - // 3. 获取指定属性 + // 2.2 获取指定属性 IotDevicePropertyDO property = properties.get(condition.getIdentifier()); if (property == null || property.getValue() == null) { log.debug("[evaluateDevicePropertyCondition][设备({}) 属性({}) 不存在或值为空]", @@ -105,7 +106,7 @@ public class IotTimerConditionEvaluator { return false; } - // 4. 使用现有的条件评估逻辑进行比较 + // 3. 使用现有的条件评估逻辑进行比较 boolean matched = IotSceneRuleMatcherHelper.evaluateCondition( property.getValue(), condition.getOperator(), condition.getParam()); log.debug("[evaluateDevicePropertyCondition][设备({}) 属性({}) 值({}) 操作符({}) 参数({}) 匹配结果: {}]", @@ -131,21 +132,20 @@ public class IotTimerConditionEvaluator { return false; } - // 2. 获取设备信息 + // 2.1 获取设备信息 IotDeviceDO device = deviceService.getDevice(condition.getDeviceId()); if (device == null) { log.debug("[evaluateDeviceStateCondition][设备({}) 不存在]", condition.getDeviceId()); return false; } - - // 3. 获取设备状态 + // 2.2 获取设备状态 Integer state = device.getState(); if (state == null) { log.debug("[evaluateDeviceStateCondition][设备({}) 状态为空]", condition.getDeviceId()); return false; } - // 4. 比较状态 + // 3. 比较状态 boolean matched = IotSceneRuleMatcherHelper.evaluateCondition( state.toString(), condition.getOperator(), condition.getParam()); log.debug("[evaluateDeviceStateCondition][设备({}) 状态({}) 操作符({}) 参数({}) 匹配结果: {}]", @@ -160,26 +160,24 @@ public class IotTimerConditionEvaluator { * @return 是否满足条件 */ private boolean evaluateCurrentTimeCondition(IotSceneRuleDO.TriggerCondition condition) { - // 1. 校验必要参数 + // 1.1 校验必要参数 if (!IotSceneRuleMatcherHelper.isConditionOperatorAndParamValid(condition)) { log.debug("[evaluateCurrentTimeCondition][操作符或参数无效]"); return false; } - - // 2. 验证操作符是否为支持的时间操作符 + // 1.2 验证操作符是否为支持的时间操作符 IotSceneRuleConditionOperatorEnum operatorEnum = IotSceneRuleConditionOperatorEnum.operatorOf(condition.getOperator()); if (operatorEnum == null) { log.debug("[evaluateCurrentTimeCondition][无效的操作符: {}]", condition.getOperator()); return false; } - if (IotSceneRuleTimeHelper.isTimeOperator(operatorEnum)) { log.debug("[evaluateCurrentTimeCondition][不支持的时间操作符: {}]", condition.getOperator()); return false; } - // 3. 执行时间匹配 + // 2. 执行时间匹配 boolean matched = IotSceneRuleTimeHelper.executeTimeMatching(operatorEnum, condition.getParam()); log.debug("[evaluateCurrentTimeCondition][操作符({}) 参数({}) 匹配结果: {}]", condition.getOperator(), condition.getParam(), matched); diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java index 3def053602..a789499a6d 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java @@ -72,7 +72,7 @@ public class IotDeviceMessageUtils { /** * 判断消息中是否包含指定的标识符 - * + *

* 对于不同消息类型的处理: * - EVENT_POST/SERVICE_INVOKE:检查 params.identifier 是否匹配 * - STATE_UPDATE:检查 params.state 是否匹配 @@ -212,8 +212,8 @@ public class IotDeviceMessageUtils { *

* 服务调用消息的 params 结构通常为: * { - * "identifier": "serviceIdentifier", - * "inputData": { ... } 或 "inputParams": { ... } + * "identifier": "serviceIdentifier", + * "inputData": { ... } 或 "inputParams": { ... } * } * * @param message 设备消息 @@ -221,6 +221,7 @@ public class IotDeviceMessageUtils { */ @SuppressWarnings("unchecked") public static Map extractServiceInputParams(IotDeviceMessage message) { + // 1. 参数校验 Object params = message.getParams(); if (params == null) { return null; @@ -235,13 +236,11 @@ public class IotDeviceMessageUtils { if (inputData instanceof Map) { return (Map) inputData; } - // 尝试从 inputParams 字段获取 Object inputParams = paramsMap.get("inputParams"); if (inputParams instanceof Map) { return (Map) inputParams; } - return null; }