From 34f1a2ed71d5d09f48061a56a208eeaa0b5d7edf Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 17 Aug 2025 22:04:59 +0800 Subject: [PATCH] perf:【IoT 物联网】场景联动规则匹配接口拆分使职责更清晰 --- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/AbstractIotSceneRuleMatcher.java | 174 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcher.java | 83 ++++++----------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherManager.java | 85 ++++++++++++++----------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/CurrentTimeConditionMatcher.java | 27 +++++++++++---------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DevicePropertyConditionMatcher.java | 29 ++++++++++++----------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DeviceStateConditionMatcher.java | 25 ++++++++++--------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotSceneRuleConditionMatcher.java | 38 ++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceEventPostTriggerMatcher.java | 27 +++++++++++---------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DevicePropertyPostTriggerMatcher.java | 31 +++++++++++++------------------ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceServiceInvokeTriggerMatcher.java | 21 ++++++++------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceStateUpdateTriggerMatcher.java | 27 +++++++++++---------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotSceneRuleTriggerMatcher.java | 38 ++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/TimerTriggerMatcher.java | 19 +++++++------------ 14 files changed, 363 insertions(+), 445 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/AbstractIotSceneRuleMatcher.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotSceneRuleConditionMatcher.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotSceneRuleTriggerMatcher.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/AbstractIotSceneRuleMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/AbstractIotSceneRuleMatcher.java deleted file mode 100644 index 5d48bba..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/AbstractIotSceneRuleMatcher.java +++ /dev/null @@ -1,174 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule.scene.matcher; - -import cn.hutool.core.util.NumberUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; -import lombok.extern.slf4j.Slf4j; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; - -/** - * IoT 场景规则匹配器抽象基类 - *

- * 提供通用的条件评估逻辑和工具方法,支持触发器和条件两种匹配类型 - * - * @author HUIHUI - */ -@Slf4j -public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher { - - // TODO @puhui999:这个是不是也是【通用】条件哈? - - /** - * 评估条件是否匹配 - * - * @param sourceValue 源值(来自消息) - * @param operator 操作符 - * @param paramValue 参数值(来自条件配置) - * @return 是否匹配 - */ - @SuppressWarnings("DataFlowIssue") - protected boolean evaluateCondition(Object sourceValue, String operator, String paramValue) { - try { - // 1. 校验操作符是否合法 - IotSceneRuleConditionOperatorEnum operatorEnum = IotSceneRuleConditionOperatorEnum.operatorOf(operator); - if (operatorEnum == null) { - log.warn("[evaluateCondition][存在错误的操作符({})]", operator); - return false; - } - - // 2. 构建 Spring 表达式变量 - Map springExpressionVariables = new HashMap<>(); - springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue); - - // 处理参数值 - if (StrUtil.isNotBlank(paramValue)) { - // 处理多值情况(如 IN、BETWEEN 操作符) - // TODO @puhui999:使用这个,会不会有问题?例如说:string 恰好有 , 分隔? - if (paramValue.contains(",")) { - List paramValues = StrUtil.split(paramValue, ','); - springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, - convertList(paramValues, NumberUtil::parseDouble)); - } else { - // 处理单值情况 - springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE, - NumberUtil.parseDouble(paramValue)); - } - } - - // 3. 计算 Spring 表达式 - return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables); - } catch (Exception e) { - log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}", - sourceValue, operator, paramValue, e); - return false; - } - } - - // ========== 【触发器】相关工具方法 ========== - - /** - * 检查基础触发器参数是否有效 - * - * @param trigger 触发器配置 - * @return 是否有效 - */ - protected boolean isBasicTriggerValid(IotSceneRuleDO.Trigger trigger) { - return trigger != null && trigger.getType() != null; - } - - /** - * 检查触发器操作符和值是否有效 - * - * @param trigger 触发器配置 - * @return 是否有效 - */ - protected boolean isTriggerOperatorAndValueValid(IotSceneRuleDO.Trigger trigger) { - return StrUtil.isNotBlank(trigger.getOperator()) && StrUtil.isNotBlank(trigger.getValue()); - } - - /** - * 记录触发器匹配成功日志 - * - * @param message 设备消息 - * @param trigger 触发器配置 - */ - protected void logTriggerMatchSuccess(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { - log.debug("[{}][消息({}) 匹配触发器({}) 成功]", getMatcherName(), message.getRequestId(), trigger.getType()); - } - - /** - * 记录触发器匹配失败日志 - * - * @param message 设备消息 - * @param trigger 触发器配置 - * @param reason 失败原因 - */ - protected void logTriggerMatchFailure(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger, String reason) { - log.debug("[{}][消息({}) 匹配触发器({}) 失败: {}]", getMatcherName(), message.getRequestId(), trigger.getType(), reason); - } - - // ========== 【条件】相关工具方法 ========== - - /** - * 检查基础条件参数是否有效 - * - * @param condition 触发条件 - * @return 是否有效 - */ - protected boolean isBasicConditionValid(IotSceneRuleDO.TriggerCondition condition) { - return condition != null && condition.getType() != null; - } - - /** - * 检查条件操作符和参数是否有效 - * - * @param condition 触发条件 - * @return 是否有效 - */ - protected boolean isConditionOperatorAndParamValid(IotSceneRuleDO.TriggerCondition condition) { - return StrUtil.isNotBlank(condition.getOperator()) && StrUtil.isNotBlank(condition.getParam()); - } - - /** - * 记录条件匹配成功日志 - * - * @param message 设备消息 - * @param condition 触发条件 - */ - protected void logConditionMatchSuccess(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { - log.debug("[{}][消息({}) 匹配条件({}) 成功]", getMatcherName(), message.getRequestId(), condition.getType()); - } - - /** - * 记录条件匹配失败日志 - * - * @param message 设备消息 - * @param condition 触发条件 - * @param reason 失败原因 - */ - protected void logConditionMatchFailure(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition, String reason) { - log.debug("[{}][消息({}) 匹配条件({}) 失败: {}]", getMatcherName(), message.getRequestId(), condition.getType(), reason); - } - - // ========== 【通用】工具方法 ========== - - /** - * 检查标识符是否匹配 - * - * @param expectedIdentifier 期望的标识符 - * @param actualIdentifier 实际的标识符 - * @return 是否匹配 - */ - protected boolean isIdentifierMatched(String expectedIdentifier, String actualIdentifier) { - return StrUtil.isNotBlank(expectedIdentifier) && expectedIdentifier.equals(actualIdentifier); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcher.java index fb86fa9..f799a45 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcher.java @@ -1,92 +1,21 @@ package cn.iocoder.yudao.module.iot.service.rule.scene.matcher; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotSceneRuleConditionMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger.IotSceneRuleTriggerMatcher; /** - * IoT 场景规则匹配器统一接口 + * IoT 场景规则匹配器基础接口 *

- * 支持触发器匹配和条件匹配两种类型,遵循策略模式设计 + * 定义所有匹配器的通用行为,包括优先级、名称和启用状态 *

- * 匹配器类型说明: - * - 触发器匹配器:用于匹配主触发条件(如设备消息类型、定时器等) - * - 条件匹配器:用于匹配子条件(如设备状态、属性值、时间条件等) + * - {@link IotSceneRuleTriggerMatcher} 触发器匹配器 + * - {@link IotSceneRuleConditionMatcher} 条件匹配器 * * @author HUIHUI */ public interface IotSceneRuleMatcher { /** - * 匹配器类型枚举 - */ - enum MatcherTypeEnum { - - /** - * 触发器匹配器 - 用于匹配主触发条件 - */ - TRIGGER, - - /** - * 条件匹配器 - 用于匹配子条件 - */ - CONDITION - - } - - /** - * 获取匹配器类型 - * - * @return 匹配器类型 - */ - MatcherTypeEnum getMatcherType(); - - // TODO @puhui999:【重要】有个思路,IotSceneRuleMatcher 拆分成 2 种 mather 接口;然后 AbstractIotSceneRuleMatcher 是个 Helper 工具类; - - // TODO @puhui999:是不是和 AbstractSceneRuleMatcher 一样,分下块; - - /** - * 获取支持的触发器类型(仅触发器匹配器需要实现) - * - * @return 触发器类型枚举,条件匹配器返回 null - */ - default IotSceneRuleTriggerTypeEnum getSupportedTriggerType() { - return null; - } - - /** - * 获取支持的条件类型(仅条件匹配器需要实现) - * - * @return 条件类型枚举,触发器匹配器返回 null - */ - default IotSceneRuleConditionTypeEnum getSupportedConditionType() { - return null; - } - - /** - * 检查触发器是否匹配消息(仅触发器匹配器需要实现) - * - * @param message 设备消息 - * @param trigger 触发器配置 - * @return 是否匹配 - */ - default boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { - throw new UnsupportedOperationException("触发器匹配方法仅支持触发器匹配器"); - } - - /** - * 检查条件是否匹配消息(仅条件匹配器需要实现) - * - * @param message 设备消息 - * @param condition 触发条件 - * @return 是否匹配 - */ - default boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { - throw new UnsupportedOperationException("条件匹配方法仅支持条件匹配器"); - } - - /** * 获取匹配优先级(数值越小优先级越高) *

* 用于在多个匹配器支持同一类型时确定优先级 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java new file mode 100644 index 0000000..dc67237 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java @@ -0,0 +1,184 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene.matcher; + +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * IoT 场景规则匹配器工具类 + *

+ * 提供通用的条件评估逻辑和工具方法,供触发器和条件匹配器使用 + *

+ * 该类包含了匹配器实现中常用的工具方法,如条件评估、参数校验、日志记录等 + * + * @author HUIHUI + */ +@Slf4j +public final class IotSceneRuleMatcherHelper { + + /** + * 私有构造函数,防止实例化 + */ + private IotSceneRuleMatcherHelper() { + } + + /** + * 评估条件是否匹配 + * + * @param sourceValue 源值(来自消息) + * @param operator 操作符 + * @param paramValue 参数值(来自条件配置) + * @return 是否匹配 + */ + @SuppressWarnings("DataFlowIssue") + public static boolean evaluateCondition(Object sourceValue, String operator, String paramValue) { + try { + // 1. 校验操作符是否合法 + IotSceneRuleConditionOperatorEnum operatorEnum = IotSceneRuleConditionOperatorEnum.operatorOf(operator); + if (operatorEnum == null) { + log.warn("[evaluateCondition][存在错误的操作符({})]", operator); + return false; + } + + // 2. 构建 Spring 表达式变量 + Map springExpressionVariables = new HashMap<>(); + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue); + + // 处理参数值 + if (StrUtil.isNotBlank(paramValue)) { + // 处理多值情况(如 IN、BETWEEN 操作符) + // TODO @puhui999:使用这个,会不会有问题?例如说:string 恰好有 , 分隔? + if (paramValue.contains(",")) { + List paramValues = StrUtil.split(paramValue, ','); + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, + convertList(paramValues, NumberUtil::parseDouble)); + } else { + // 处理单值情况 + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE, + NumberUtil.parseDouble(paramValue)); + } + } + + // 3. 计算 Spring 表达式 + return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables); + } catch (Exception e) { + log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}", + sourceValue, operator, paramValue, e); + return false; + } + } + + // ========== 【触发器】相关工具方法 ========== + + /** + * 检查基础触发器参数是否有效 + * + * @param trigger 触发器配置 + * @return 是否有效 + */ + public static boolean isBasicTriggerValid(IotSceneRuleDO.Trigger trigger) { + return trigger != null && trigger.getType() != null; + } + + /** + * 检查触发器操作符和值是否有效 + * + * @param trigger 触发器配置 + * @return 是否有效 + */ + public static boolean isTriggerOperatorAndValueValid(IotSceneRuleDO.Trigger trigger) { + return StrUtil.isNotBlank(trigger.getOperator()) && StrUtil.isNotBlank(trigger.getValue()); + } + + /** + * 记录触发器匹配成功日志 + * + * @param matcherName 匹配器名称 + * @param message 设备消息 + * @param trigger 触发器配置 + */ + public static void logTriggerMatchSuccess(String matcherName, IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { + log.debug("[{}][消息({}) 匹配触发器({}) 成功]", matcherName, message.getRequestId(), trigger.getType()); + } + + /** + * 记录触发器匹配失败日志 + * + * @param matcherName 匹配器名称 + * @param message 设备消息 + * @param trigger 触发器配置 + * @param reason 失败原因 + */ + public static void logTriggerMatchFailure(String matcherName, IotDeviceMessage message, IotSceneRuleDO.Trigger trigger, String reason) { + log.debug("[{}][消息({}) 匹配触发器({}) 失败: {}]", matcherName, message.getRequestId(), trigger.getType(), reason); + } + + // ========== 【条件】相关工具方法 ========== + + /** + * 检查基础条件参数是否有效 + * + * @param condition 触发条件 + * @return 是否有效 + */ + public static boolean isBasicConditionValid(IotSceneRuleDO.TriggerCondition condition) { + return condition != null && condition.getType() != null; + } + + /** + * 检查条件操作符和参数是否有效 + * + * @param condition 触发条件 + * @return 是否有效 + */ + public static boolean isConditionOperatorAndParamValid(IotSceneRuleDO.TriggerCondition condition) { + return StrUtil.isNotBlank(condition.getOperator()) && StrUtil.isNotBlank(condition.getParam()); + } + + /** + * 记录条件匹配成功日志 + * + * @param matcherName 匹配器名称 + * @param message 设备消息 + * @param condition 触发条件 + */ + public static void logConditionMatchSuccess(String matcherName, IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { + log.debug("[{}][消息({}) 匹配条件({}) 成功]", matcherName, message.getRequestId(), condition.getType()); + } + + /** + * 记录条件匹配失败日志 + * + * @param matcherName 匹配器名称 + * @param message 设备消息 + * @param condition 触发条件 + * @param reason 失败原因 + */ + public static void logConditionMatchFailure(String matcherName, IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition, String reason) { + log.debug("[{}][消息({}) 匹配条件({}) 失败: {}]", matcherName, message.getRequestId(), condition.getType(), reason); + } + + // ========== 【通用】工具方法 ========== + + /** + * 检查标识符是否匹配 + * + * @param expectedIdentifier 期望的标识符 + * @param actualIdentifier 实际的标识符 + * @return 是否匹配 + */ + public static boolean isIdentifierMatched(String expectedIdentifier, String actualIdentifier) { + return StrUtil.isNotBlank(expectedIdentifier) && expectedIdentifier.equals(actualIdentifier); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherManager.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherManager.java index a73e915..d077579 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherManager.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherManager.java @@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotSceneRuleConditionMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger.IotSceneRuleTriggerMatcher; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -30,14 +32,14 @@ public class IotSceneRuleMatcherManager { * Key: 触发器类型枚举 * Value: 对应的匹配器实例 */ - private final Map triggerMatchers; + private final Map triggerMatchers; /** * 条件匹配器映射表 * Key: 条件类型枚举 * Value: 对应的匹配器实例 */ - private final Map conditionMatchers; + private final Map conditionMatchers; /** * 所有匹配器列表(按优先级排序) @@ -60,18 +62,20 @@ public class IotSceneRuleMatcherManager { .collect(Collectors.toList()); // 分离触发器匹配器和条件匹配器 - List triggerMatchers = this.allMatchers.stream() - .filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherTypeEnum.TRIGGER) + List triggerMatchers = this.allMatchers.stream() + .filter(matcher -> matcher instanceof IotSceneRuleTriggerMatcher) + .map(matcher -> (IotSceneRuleTriggerMatcher) matcher) .toList(); - List conditionMatchers = this.allMatchers.stream() - .filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherTypeEnum.CONDITION) + List conditionMatchers = this.allMatchers.stream() + .filter(matcher -> matcher instanceof IotSceneRuleConditionMatcher) + .map(matcher -> (IotSceneRuleConditionMatcher) matcher) .toList(); // 构建触发器匹配器映射表 // TODO @puhui999:convertMap() this.triggerMatchers = triggerMatchers.stream() .collect(Collectors.toMap( - IotSceneRuleMatcher::getSupportedTriggerType, + IotSceneRuleTriggerMatcher::getSupportedTriggerType, Function.identity(), (existing, replacement) -> { log.warn("[IotSceneRuleMatcherManager][触发器类型({})存在多个匹配器,使用优先级更高的: {}]", @@ -84,7 +88,7 @@ public class IotSceneRuleMatcherManager { // 构建条件匹配器映射表 this.conditionMatchers = conditionMatchers.stream() .collect(Collectors.toMap( - IotSceneRuleMatcher::getSupportedConditionType, + IotSceneRuleConditionMatcher::getSupportedConditionType, Function.identity(), (existing, replacement) -> { log.warn("[IotSceneRuleMatcherManager][条件类型({})存在多个匹配器,使用优先级更高的: {}]", @@ -124,7 +128,7 @@ public class IotSceneRuleMatcherManager { log.warn("[isMatched][未知的触发器类型: {}]", trigger.getType()); return false; } - IotSceneRuleMatcher matcher = triggerMatchers.get(triggerType); + IotSceneRuleTriggerMatcher matcher = triggerMatchers.get(triggerType); if (matcher == null) { log.warn("[isMatched][触发器类型({})没有对应的匹配器]", triggerType); return false; @@ -159,7 +163,7 @@ public class IotSceneRuleMatcherManager { return false; } - IotSceneRuleMatcher matcher = conditionMatchers.get(conditionType); + IotSceneRuleConditionMatcher matcher = conditionMatchers.get(conditionType); if (matcher == null) { log.warn("[isConditionMatched][条件类型({})没有对应的匹配器]", conditionType); return false; @@ -205,65 +209,4 @@ public class IotSceneRuleMatcherManager { return new HashSet<>(conditionMatchers.keySet()); } - // TODO @puhui999:用不到的方法,可以去掉先哈; - - /** - * 获取指定触发器类型的匹配器 - * - * @param triggerType 触发器类型 - * @return 匹配器实例,如果不存在则返回 null - */ - public IotSceneRuleMatcher getTriggerMatcher(IotSceneRuleTriggerTypeEnum triggerType) { - return triggerMatchers.get(triggerType); - } - - /** - * 获取指定条件类型的匹配器 - * - * @param conditionType 条件类型 - * @return 匹配器实例,如果不存在则返回 null - */ - public IotSceneRuleMatcher getConditionMatcher(IotSceneRuleConditionTypeEnum conditionType) { - return conditionMatchers.get(conditionType); - } - - // TODO @puhui999:是不是不用这个哈;直接 @Getter,单测直接处理; - /** - * 获取所有匹配器的统计信息 - * - * @return 统计信息映射表 - */ - public Map getMatcherStatistics() { - Map statistics = new HashMap<>(); - statistics.put("totalMatchers", allMatchers.size()); - statistics.put("triggerMatchers", triggerMatchers.size()); - statistics.put("conditionMatchers", conditionMatchers.size()); - statistics.put("supportedTriggerTypes", getSupportedTriggerTypes()); - statistics.put("supportedConditionTypes", getSupportedConditionTypes()); - - // 触发器匹配器详情 - Map triggerMatcherDetails = new HashMap<>(); - triggerMatchers.forEach((type, matcher) -> { - Map detail = new HashMap<>(); - detail.put("matcherName", matcher.getMatcherName()); - detail.put("priority", matcher.getPriority()); - detail.put("enabled", matcher.isEnabled()); - triggerMatcherDetails.put(type.name(), detail); - }); - statistics.put("triggerMatcherDetails", triggerMatcherDetails); - - // 条件匹配器详情 - Map conditionMatcherDetails = new HashMap<>(); - conditionMatchers.forEach((type, matcher) -> { - Map detail = new HashMap<>(); - detail.put("matcherName", matcher.getMatcherName()); - detail.put("priority", matcher.getPriority()); - detail.put("enabled", matcher.isEnabled()); - conditionMatcherDetails.put(type.name(), detail); - }); - statistics.put("conditionMatcherDetails", conditionMatcherDetails); - - return statistics; - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/CurrentTimeConditionMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/CurrentTimeConditionMatcher.java index 1ddfe71..b282153 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/CurrentTimeConditionMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/CurrentTimeConditionMatcher.java @@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.AbstractIotSceneRuleMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -21,7 +21,7 @@ import java.time.format.DateTimeFormatter; */ @Component @Slf4j -public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { +public class CurrentTimeConditionMatcher implements IotSceneRuleConditionMatcher { /** * 时间格式化器 - HH:mm:ss @@ -34,11 +34,6 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { private static final DateTimeFormatter TIME_FORMATTER_SHORT = DateTimeFormatter.ofPattern("HH:mm"); @Override - public MatcherTypeEnum getMatcherType() { - return MatcherTypeEnum.CONDITION; - } - - @Override public IotSceneRuleConditionTypeEnum getSupportedConditionType() { return IotSceneRuleConditionTypeEnum.CURRENT_TIME; } @@ -46,14 +41,14 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { @Override public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { // 1. 基础参数校验 - if (!isBasicConditionValid(condition)) { - logConditionMatchFailure(message, condition, "条件基础参数无效"); + if (!IotSceneRuleMatcherHelper.isBasicConditionValid(condition)) { + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "条件基础参数无效"); return false; } // 2. 检查操作符和参数是否有效 - if (!isConditionOperatorAndParamValid(condition)) { - logConditionMatchFailure(message, condition, "操作符或参数无效"); + if (!IotSceneRuleMatcherHelper.isConditionOperatorAndParamValid(condition)) { + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "操作符或参数无效"); return false; } @@ -71,17 +66,17 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { matched = matchTime(now.toLocalTime(), operator, param); } else { // 其他操作符,使用通用条件评估器 - matched = evaluateCondition(now.toEpochSecond(java.time.ZoneOffset.of("+8")), operator, param); + matched = IotSceneRuleMatcherHelper.evaluateCondition(now.toEpochSecond(java.time.ZoneOffset.of("+8")), operator, param); } if (matched) { - logConditionMatchSuccess(message, condition); + IotSceneRuleMatcherHelper.logConditionMatchSuccess(getMatcherName(), message, condition); } else { - logConditionMatchFailure(message, condition, "时间条件不匹配"); + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "时间条件不匹配"); } } catch (Exception e) { log.error("[CurrentTimeConditionMatcher][时间条件匹配异常] operator: {}, param: {}", operator, param, e); - logConditionMatchFailure(message, condition, "时间条件匹配异常: " + e.getMessage()); + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "时间条件匹配异常: " + e.getMessage()); matched = false; } return matched; @@ -92,7 +87,7 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { */ private boolean matchDateTime(LocalDateTime now, String operator, String param) { long currentTimestamp = now.toEpochSecond(java.time.ZoneOffset.of("+8")); - return evaluateCondition(currentTimestamp, operator.substring("date_time_".length()), param); + return IotSceneRuleMatcherHelper.evaluateCondition(currentTimestamp, operator.substring("date_time_".length()), param); } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DevicePropertyConditionMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DevicePropertyConditionMatcher.java index 8ba2bfb..5ede1c2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DevicePropertyConditionMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DevicePropertyConditionMatcher.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.AbstractIotSceneRuleMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper; import org.springframework.stereotype.Component; /** @@ -15,12 +15,7 @@ import org.springframework.stereotype.Component; * @author HUIHUI */ @Component -public class DevicePropertyConditionMatcher extends AbstractIotSceneRuleMatcher { - - @Override - public MatcherTypeEnum getMatcherType() { - return MatcherTypeEnum.CONDITION; - } +public class DevicePropertyConditionMatcher implements IotSceneRuleConditionMatcher { @Override public IotSceneRuleConditionTypeEnum getSupportedConditionType() { @@ -31,37 +26,37 @@ public class DevicePropertyConditionMatcher extends AbstractIotSceneRuleMatcher @Override public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { // 1. 基础参数校验 - if (!isBasicConditionValid(condition)) { - logConditionMatchFailure(message, condition, "条件基础参数无效"); + if (!IotSceneRuleMatcherHelper.isBasicConditionValid(condition)) { + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "条件基础参数无效"); return false; } // 2. 检查标识符是否匹配 String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message); - if (!isIdentifierMatched(condition.getIdentifier(), messageIdentifier)) { - logConditionMatchFailure(message, condition, "标识符不匹配,期望: " + condition.getIdentifier() + ", 实际: " + messageIdentifier); + if (!IotSceneRuleMatcherHelper.isIdentifierMatched(condition.getIdentifier(), messageIdentifier)) { + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "标识符不匹配,期望: " + condition.getIdentifier() + ", 实际: " + messageIdentifier); return false; } // 3. 检查操作符和参数是否有效 - if (!isConditionOperatorAndParamValid(condition)) { - logConditionMatchFailure(message, condition, "操作符或参数无效"); + if (!IotSceneRuleMatcherHelper.isConditionOperatorAndParamValid(condition)) { + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "操作符或参数无效"); return false; } // 4. 获取属性值 Object propertyValue = message.getData(); if (propertyValue == null) { - logConditionMatchFailure(message, condition, "消息中属性值为空"); + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "消息中属性值为空"); return false; } // 5. 使用条件评估器进行匹配 - boolean matched = evaluateCondition(propertyValue, condition.getOperator(), condition.getParam()); + boolean matched = IotSceneRuleMatcherHelper.evaluateCondition(propertyValue, condition.getOperator(), condition.getParam()); if (matched) { - logConditionMatchSuccess(message, condition); + IotSceneRuleMatcherHelper.logConditionMatchSuccess(getMatcherName(), message, condition); } else { - logConditionMatchFailure(message, condition, "设备属性条件不匹配"); + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "设备属性条件不匹配"); } return matched; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DeviceStateConditionMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DeviceStateConditionMatcher.java index 8bffae9..56063c8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DeviceStateConditionMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/DeviceStateConditionMatcher.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.AbstractIotSceneRuleMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper; import org.springframework.stereotype.Component; /** @@ -14,12 +14,7 @@ import org.springframework.stereotype.Component; * @author HUIHUI */ @Component -public class DeviceStateConditionMatcher extends AbstractIotSceneRuleMatcher { - - @Override - public MatcherTypeEnum getMatcherType() { - return MatcherTypeEnum.CONDITION; - } +public class DeviceStateConditionMatcher implements IotSceneRuleConditionMatcher { @Override public IotSceneRuleConditionTypeEnum getSupportedConditionType() { @@ -29,14 +24,14 @@ public class DeviceStateConditionMatcher extends AbstractIotSceneRuleMatcher { @Override public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { // 1. 基础参数校验 - if (!isBasicConditionValid(condition)) { - logConditionMatchFailure(message, condition, "条件基础参数无效"); + if (!IotSceneRuleMatcherHelper.isBasicConditionValid(condition)) { + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "条件基础参数无效"); return false; } // 2. 检查操作符和参数是否有效 - if (!isConditionOperatorAndParamValid(condition)) { - logConditionMatchFailure(message, condition, "操作符或参数无效"); + if (!IotSceneRuleMatcherHelper.isConditionOperatorAndParamValid(condition)) { + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "操作符或参数无效"); return false; } @@ -44,16 +39,16 @@ public class DeviceStateConditionMatcher extends AbstractIotSceneRuleMatcher { // 设备状态通常在消息的 data 字段中 Object stateValue = message.getData(); if (stateValue == null) { - logConditionMatchFailure(message, condition, "消息中设备状态值为空"); + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "消息中设备状态值为空"); return false; } // 4. 使用条件评估器进行匹配 - boolean matched = evaluateCondition(stateValue, condition.getOperator(), condition.getParam()); + boolean matched = IotSceneRuleMatcherHelper.evaluateCondition(stateValue, condition.getOperator(), condition.getParam()); if (matched) { - logConditionMatchSuccess(message, condition); + IotSceneRuleMatcherHelper.logConditionMatchSuccess(getMatcherName(), message, condition); } else { - logConditionMatchFailure(message, condition, "设备状态条件不匹配"); + IotSceneRuleMatcherHelper.logConditionMatchFailure(getMatcherName(), message, condition, "设备状态条件不匹配"); } return matched; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotSceneRuleConditionMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotSceneRuleConditionMatcher.java new file mode 100644 index 0000000..2e44b11 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotSceneRuleConditionMatcher.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition; + +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcher; + +/** + * IoT 场景规则条件匹配器接口 + *

+ * 专门处理子条件的匹配逻辑,如设备状态、属性值、时间条件等 + *

+ * 条件匹配器负责判断设备消息是否满足场景规则的附加条件, + * 在触发器匹配成功后进行进一步的条件筛选 + * + * @author HUIHUI + */ +public interface IotSceneRuleConditionMatcher extends IotSceneRuleMatcher { + + /** + * 获取支持的条件类型 + * + * @return 条件类型枚举 + */ + IotSceneRuleConditionTypeEnum getSupportedConditionType(); + + /** + * 检查条件是否匹配消息 + *

+ * 判断设备消息是否满足指定的触发条件 + * + * @param message 设备消息 + * @param condition 触发条件 + * @return 是否匹配 + */ + boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceEventPostTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceEventPostTriggerMatcher.java index edd5ea3..957348e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceEventPostTriggerMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceEventPostTriggerMatcher.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.AbstractIotSceneRuleMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper; import org.springframework.stereotype.Component; /** @@ -17,7 +17,7 @@ import org.springframework.stereotype.Component; * @author HUIHUI */ @Component -public class DeviceEventPostTriggerMatcher extends AbstractIotSceneRuleMatcher { +public class DeviceEventPostTriggerMatcher implements IotSceneRuleTriggerMatcher { /** * 设备事件上报消息方法 @@ -25,11 +25,6 @@ public class DeviceEventPostTriggerMatcher extends AbstractIotSceneRuleMatcher { private static final String DEVICE_EVENT_POST_METHOD = IotDeviceMessageMethodEnum.EVENT_POST.getMethod(); @Override - public MatcherTypeEnum getMatcherType() { - return MatcherTypeEnum.TRIGGER; - } - - @Override public IotSceneRuleTriggerTypeEnum getSupportedTriggerType() { return IotSceneRuleTriggerTypeEnum.DEVICE_EVENT_POST; } @@ -37,21 +32,21 @@ public class DeviceEventPostTriggerMatcher extends AbstractIotSceneRuleMatcher { @Override public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { // 1. 基础参数校验 - if (!isBasicTriggerValid(trigger)) { - logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); + if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "触发器基础参数无效"); return false; } // 2. 检查消息方法是否匹配 if (!DEVICE_EVENT_POST_METHOD.equals(message.getMethod())) { - logTriggerMatchFailure(message, trigger, "消息方法不匹配,期望: " + DEVICE_EVENT_POST_METHOD + ", 实际: " + message.getMethod()); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "消息方法不匹配,期望: " + DEVICE_EVENT_POST_METHOD + ", 实际: " + message.getMethod()); return false; } // 3. 检查标识符是否匹配 String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message); - if (!isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) { - logTriggerMatchFailure(message, trigger, "标识符不匹配,期望: " + trigger.getIdentifier() + ", 实际: " + messageIdentifier); + if (!IotSceneRuleMatcherHelper.isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "标识符不匹配,期望: " + trigger.getIdentifier() + ", 实际: " + messageIdentifier); return false; } @@ -60,18 +55,18 @@ public class DeviceEventPostTriggerMatcher extends AbstractIotSceneRuleMatcher { if (StrUtil.isNotBlank(trigger.getOperator()) && StrUtil.isNotBlank(trigger.getValue())) { Object eventData = message.getData(); if (eventData == null) { - logTriggerMatchFailure(message, trigger, "消息中事件数据为空"); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "消息中事件数据为空"); return false; } - boolean matched = evaluateCondition(eventData, trigger.getOperator(), trigger.getValue()); + boolean matched = IotSceneRuleMatcherHelper.evaluateCondition(eventData, trigger.getOperator(), trigger.getValue()); if (!matched) { - logTriggerMatchFailure(message, trigger, "事件数据条件不匹配"); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "事件数据条件不匹配"); return false; } } - logTriggerMatchSuccess(message, trigger); + IotSceneRuleMatcherHelper.logTriggerMatchSuccess(getMatcherName(), message, trigger); return true; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DevicePropertyPostTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DevicePropertyPostTriggerMatcher.java index b01f7f4..1163887 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DevicePropertyPostTriggerMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DevicePropertyPostTriggerMatcher.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.AbstractIotSceneRuleMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper; import org.springframework.stereotype.Component; /** @@ -16,7 +16,7 @@ import org.springframework.stereotype.Component; * @author HUIHUI */ @Component -public class DevicePropertyPostTriggerMatcher extends AbstractIotSceneRuleMatcher { +public class DevicePropertyPostTriggerMatcher implements IotSceneRuleTriggerMatcher { /** * 设备属性上报消息方法 @@ -25,11 +25,6 @@ public class DevicePropertyPostTriggerMatcher extends AbstractIotSceneRuleMatche private static final String DEVICE_PROPERTY_POST_METHOD = IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod(); @Override - public MatcherTypeEnum getMatcherType() { - return MatcherTypeEnum.TRIGGER; - } - - @Override public IotSceneRuleTriggerTypeEnum getSupportedTriggerType() { return IotSceneRuleTriggerTypeEnum.DEVICE_PROPERTY_POST; } @@ -37,43 +32,43 @@ public class DevicePropertyPostTriggerMatcher extends AbstractIotSceneRuleMatche @Override public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { // 1. 基础参数校验 - if (!isBasicTriggerValid(trigger)) { - logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); + if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "触发器基础参数无效"); return false; } // 2. 检查消息方法是否匹配 if (!DEVICE_PROPERTY_POST_METHOD.equals(message.getMethod())) { - logTriggerMatchFailure(message, trigger, "消息方法不匹配,期望: " + DEVICE_PROPERTY_POST_METHOD + ", 实际: " + message.getMethod()); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "消息方法不匹配,期望: " + DEVICE_PROPERTY_POST_METHOD + ", 实际: " + message.getMethod()); return false; } // 3. 检查标识符是否匹配 String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message); - if (!isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) { - logTriggerMatchFailure(message, trigger, "标识符不匹配,期望: " + trigger.getIdentifier() + ", 实际: " + messageIdentifier); + if (!IotSceneRuleMatcherHelper.isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "标识符不匹配,期望: " + trigger.getIdentifier() + ", 实际: " + messageIdentifier); return false; } // 4. 检查操作符和值是否有效 - if (!isTriggerOperatorAndValueValid(trigger)) { - logTriggerMatchFailure(message, trigger, "操作符或值无效"); + if (!IotSceneRuleMatcherHelper.isTriggerOperatorAndValueValid(trigger)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "操作符或值无效"); return false; } // 5. 获取属性值 Object propertyValue = message.getData(); if (propertyValue == null) { - logTriggerMatchFailure(message, trigger, "消息中属性值为空"); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "消息中属性值为空"); return false; } // 6. 使用条件评估器进行匹配 - boolean matched = evaluateCondition(propertyValue, trigger.getOperator(), trigger.getValue()); + boolean matched = IotSceneRuleMatcherHelper.evaluateCondition(propertyValue, trigger.getOperator(), trigger.getValue()); if (matched) { - logTriggerMatchSuccess(message, trigger); + IotSceneRuleMatcherHelper.logTriggerMatchSuccess(getMatcherName(), message, trigger); } else { - logTriggerMatchFailure(message, trigger, "属性值条件不匹配"); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "属性值条件不匹配"); } return matched; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceServiceInvokeTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceServiceInvokeTriggerMatcher.java index 074d4af..c349fd2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceServiceInvokeTriggerMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceServiceInvokeTriggerMatcher.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.AbstractIotSceneRuleMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper; import org.springframework.stereotype.Component; /** @@ -16,7 +16,7 @@ import org.springframework.stereotype.Component; * @author HUIHUI */ @Component -public class DeviceServiceInvokeTriggerMatcher extends AbstractIotSceneRuleMatcher { +public class DeviceServiceInvokeTriggerMatcher implements IotSceneRuleTriggerMatcher { /** * 设备服务调用消息方法 @@ -24,11 +24,6 @@ public class DeviceServiceInvokeTriggerMatcher extends AbstractIotSceneRuleMatch private static final String DEVICE_SERVICE_INVOKE_METHOD = IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod(); @Override - public MatcherTypeEnum getMatcherType() { - return MatcherTypeEnum.TRIGGER; - } - - @Override public IotSceneRuleTriggerTypeEnum getSupportedTriggerType() { return IotSceneRuleTriggerTypeEnum.DEVICE_SERVICE_INVOKE; } @@ -36,28 +31,28 @@ public class DeviceServiceInvokeTriggerMatcher extends AbstractIotSceneRuleMatch @Override public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { // 1. 基础参数校验 - if (!isBasicTriggerValid(trigger)) { - logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); + if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "触发器基础参数无效"); return false; } // 2. 检查消息方法是否匹配 if (!DEVICE_SERVICE_INVOKE_METHOD.equals(message.getMethod())) { - logTriggerMatchFailure(message, trigger, "消息方法不匹配,期望: " + DEVICE_SERVICE_INVOKE_METHOD + ", 实际: " + message.getMethod()); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "消息方法不匹配,期望: " + DEVICE_SERVICE_INVOKE_METHOD + ", 实际: " + message.getMethod()); return false; } // 3. 检查标识符是否匹配 String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message); - if (!isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) { - logTriggerMatchFailure(message, trigger, "标识符不匹配,期望: " + trigger.getIdentifier() + ", 实际: " + messageIdentifier); + if (!IotSceneRuleMatcherHelper.isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "标识符不匹配,期望: " + trigger.getIdentifier() + ", 实际: " + messageIdentifier); return false; } // 4. 对于服务调用触发器,通常只需要匹配服务标识符即可 // 不需要检查操作符和值,因为服务调用本身就是触发条件 - logTriggerMatchSuccess(message, trigger); + IotSceneRuleMatcherHelper.logTriggerMatchSuccess(getMatcherName(), message, trigger); return true; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceStateUpdateTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceStateUpdateTriggerMatcher.java index 68d9ca4..a435002 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceStateUpdateTriggerMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/DeviceStateUpdateTriggerMatcher.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.AbstractIotSceneRuleMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper; import org.springframework.stereotype.Component; /** @@ -15,7 +15,7 @@ import org.springframework.stereotype.Component; * @author HUIHUI */ @Component -public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher { +public class DeviceStateUpdateTriggerMatcher implements IotSceneRuleTriggerMatcher { // TODO @puhui999:是不是不用枚举哈; /** @@ -24,11 +24,6 @@ public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher private static final String DEVICE_STATE_UPDATE_METHOD = IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod(); @Override - public MatcherTypeEnum getMatcherType() { - return MatcherTypeEnum.TRIGGER; - } - - @Override public IotSceneRuleTriggerTypeEnum getSupportedTriggerType() { return IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE; } @@ -36,36 +31,36 @@ public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher @Override public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { // 1. 基础参数校验 - if (!isBasicTriggerValid(trigger)) { - logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); + if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "触发器基础参数无效"); return false; } // 2. 检查消息方法是否匹配 if (!DEVICE_STATE_UPDATE_METHOD.equals(message.getMethod())) { - logTriggerMatchFailure(message, trigger, "消息方法不匹配,期望: " + DEVICE_STATE_UPDATE_METHOD + ", 实际: " + message.getMethod()); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "消息方法不匹配,期望: " + DEVICE_STATE_UPDATE_METHOD + ", 实际: " + message.getMethod()); return false; } // 3. 检查操作符和值是否有效 - if (!isTriggerOperatorAndValueValid(trigger)) { - logTriggerMatchFailure(message, trigger, "操作符或值无效"); + if (!IotSceneRuleMatcherHelper.isTriggerOperatorAndValueValid(trigger)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "操作符或值无效"); return false; } // 4. 获取设备状态值 Object stateValue = message.getData(); if (stateValue == null) { - logTriggerMatchFailure(message, trigger, "消息中设备状态值为空"); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "消息中设备状态值为空"); return false; } // 5. 使用条件评估器进行匹配 - boolean matched = evaluateCondition(stateValue, trigger.getOperator(), trigger.getValue()); + boolean matched = IotSceneRuleMatcherHelper.evaluateCondition(stateValue, trigger.getOperator(), trigger.getValue()); if (matched) { - logTriggerMatchSuccess(message, trigger); + IotSceneRuleMatcherHelper.logTriggerMatchSuccess(getMatcherName(), message, trigger); } else { - logTriggerMatchFailure(message, trigger, "状态值条件不匹配"); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "状态值条件不匹配"); } return matched; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotSceneRuleTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotSceneRuleTriggerMatcher.java new file mode 100644 index 0000000..3224217 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotSceneRuleTriggerMatcher.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger; + +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcher; + +/** + * IoT 场景规则触发器匹配器接口 + *

+ * 专门处理主触发条件的匹配逻辑,如设备消息类型、定时器等 + *

+ * 触发器匹配器负责判断设备消息是否满足场景规则的主触发条件, + * 是场景规则执行的第一道门槛 + * + * @author HUIHUI + */ +public interface IotSceneRuleTriggerMatcher extends IotSceneRuleMatcher { + + /** + * 获取支持的触发器类型 + * + * @return 触发器类型枚举 + */ + IotSceneRuleTriggerTypeEnum getSupportedTriggerType(); + + /** + * 检查触发器是否匹配消息 + *

+ * 判断设备消息是否满足指定的触发器条件 + * + * @param message 设备消息 + * @param trigger 触发器配置 + * @return 是否匹配 + */ + boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/TimerTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/TimerTriggerMatcher.java index 1ae0cee..6dfd3fc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/TimerTriggerMatcher.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/TimerTriggerMatcher.java @@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.AbstractIotSceneRuleMatcher; +import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper; import org.springframework.stereotype.Component; /** @@ -16,12 +16,7 @@ import org.springframework.stereotype.Component; * @author HUIHUI */ @Component -public class TimerTriggerMatcher extends AbstractIotSceneRuleMatcher { - - @Override - public MatcherTypeEnum getMatcherType() { - return MatcherTypeEnum.TRIGGER; - } +public class TimerTriggerMatcher implements IotSceneRuleTriggerMatcher { @Override public IotSceneRuleTriggerTypeEnum getSupportedTriggerType() { @@ -31,14 +26,14 @@ public class TimerTriggerMatcher extends AbstractIotSceneRuleMatcher { @Override public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { // 1. 基础参数校验 - if (!isBasicTriggerValid(trigger)) { - logTriggerMatchFailure(message, trigger, "触发器基础参数无效"); + if (!IotSceneRuleMatcherHelper.isBasicTriggerValid(trigger)) { + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "触发器基础参数无效"); return false; } // 2. 检查 CRON 表达式是否存在 if (StrUtil.isBlank(trigger.getCronExpression())) { - logTriggerMatchFailure(message, trigger, "定时触发器缺少 CRON 表达式"); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "定时触发器缺少 CRON 表达式"); return false; } @@ -47,11 +42,11 @@ public class TimerTriggerMatcher extends AbstractIotSceneRuleMatcher { // 4. 可以添加 CRON 表达式格式验证 if (!isValidCronExpression(trigger.getCronExpression())) { - logTriggerMatchFailure(message, trigger, "CRON 表达式格式无效: " + trigger.getCronExpression()); + IotSceneRuleMatcherHelper.logTriggerMatchFailure(getMatcherName(), message, trigger, "CRON 表达式格式无效: " + trigger.getCronExpression()); return false; } - logTriggerMatchSuccess(message, trigger); + IotSceneRuleMatcherHelper.logTriggerMatchSuccess(getMatcherName(), message, trigger); return true; } -- libgit2 0.21.4