review(iot):【场景联动】增加相关的 review 说明

This commit is contained in:
YunaiV
2026-01-25 21:57:22 +08:00
parent f3878c3056
commit 9be7d6fac0
6 changed files with 34 additions and 32 deletions

View File

@@ -97,6 +97,7 @@ public class IotWebSocketDataRuleAction extends
}
}
// TODO @puhui999为什么这里要加锁呀
/**
* 使用锁进行重连,保证同一服务器地址的重连操作线程安全
*

View File

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

View File

@@ -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 场景规则时间匹配工具类
* <p>
* 提供时间条件匹配的通用方法,供 {@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 @puhui999hutool 里,看看有没 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 @puhui999hutool 里,看看有没 between 方法
return !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime);
}

View File

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

View File

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

View File

@@ -72,7 +72,7 @@ public class IotDeviceMessageUtils {
/**
* 判断消息中是否包含指定的标识符
*
* <p>
* 对于不同消息类型的处理:
* - EVENT_POST/SERVICE_INVOKE检查 params.identifier 是否匹配
* - STATE_UPDATE检查 params.state 是否匹配
@@ -212,8 +212,8 @@ public class IotDeviceMessageUtils {
* <p>
* 服务调用消息的 params 结构通常为:
* {
* "identifier": "serviceIdentifier",
* "inputData": { ... } 或 "inputParams": { ... }
* "identifier": "serviceIdentifier",
* "inputData": { ... } 或 "inputParams": { ... }
* }
*
* @param message 设备消息
@@ -221,6 +221,7 @@ public class IotDeviceMessageUtils {
*/
@SuppressWarnings("unchecked")
public static Map<String, Object> 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<String, Object>) inputData;
}
// 尝试从 inputParams 字段获取
Object inputParams = paramsMap.get("inputParams");
if (inputParams instanceof Map) {
return (Map<String, Object>) inputParams;
}
return null;
}