review:【iot 物联网】场景联动相关实现

This commit is contained in:
YunaiV
2025-08-16 20:37:22 +08:00
parent f88d30f103
commit 6791c62858
13 changed files with 65 additions and 62 deletions

View File

@@ -60,7 +60,7 @@ public enum IotSceneRuleTriggerTypeEnum implements ArrayValuable<Integer> {
return ARRAYS; return ARRAYS;
} }
// TODO @puhui999可以参考下别的枚举哈方法名和实现都可以更简洁of(String type) { firstMatch
/** /**
* 根据类型值查找触发器类型枚举 * 根据类型值查找触发器类型枚举
* *

View File

@@ -45,7 +45,6 @@ public class IotRedisRuleAction extends
// 2. 根据数据结构类型执行不同的操作 // 2. 根据数据结构类型执行不同的操作
String messageJson = JsonUtils.toJsonString(message); String messageJson = JsonUtils.toJsonString(message);
IotRedisDataStructureEnum dataStructure = getDataStructureByType(config.getDataStructure()); IotRedisDataStructureEnum dataStructure = getDataStructureByType(config.getDataStructure());
switch (dataStructure) { switch (dataStructure) {
case STREAM: case STREAM:
executeStream(redisTemplate, config, messageJson); executeStream(redisTemplate, config, messageJson);

View File

@@ -58,12 +58,15 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
@Resource @Resource
private IotSceneRuleMapper sceneRuleMapper; private IotSceneRuleMapper sceneRuleMapper;
// TODO @puhui999定时任务基于它调度
@Resource(name = "iotSchedulerManager") @Resource(name = "iotSchedulerManager")
private IotSchedulerManager schedulerManager; private IotSchedulerManager schedulerManager;
@Resource @Resource
private IotProductService productService; private IotProductService productService;
@Resource @Resource
private IotDeviceService deviceService; private IotDeviceService deviceService;
// TODO @puhui999sceneRuleMatcherManager 变量名
@Resource @Resource
private IotSceneRuleMatcherManager matcherManager; private IotSceneRuleMatcherManager matcherManager;
@Resource @Resource
@@ -135,7 +138,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
return sceneRuleMapper.selectListByStatus(status); return sceneRuleMapper.selectListByStatus(status);
} }
// TODO 芋艿,缓存待实现 // TODO 芋艿,缓存待实现 @puhui999
@Override @Override
@TenantIgnore // 忽略租户隔离:因为 IotSceneRuleMessageHandler 调用时,一般未传递租户,所以需要忽略 @TenantIgnore // 忽略租户隔离:因为 IotSceneRuleMessageHandler 调用时,一般未传递租户,所以需要忽略
public List<IotSceneRuleDO> getSceneRuleListByProductIdAndDeviceIdFromCache(Long productId, Long deviceId) { public List<IotSceneRuleDO> getSceneRuleListByProductIdAndDeviceIdFromCache(Long productId, Long deviceId) {
@@ -177,7 +180,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
@Override @Override
public void executeSceneRuleByDevice(IotDeviceMessage message) { public void executeSceneRuleByDevice(IotDeviceMessage message) {
// TODO @芋艿:这里的 tenantId通过设备获取 // TODO @芋艿:这里的 tenantId通过设备获取@puhui999
TenantUtils.execute(message.getTenantId(), () -> { TenantUtils.execute(message.getTenantId(), () -> {
// 1. 获得设备匹配的规则场景 // 1. 获得设备匹配的规则场景
List<IotSceneRuleDO> sceneRules = getMatchedSceneRuleListByMessage(message); List<IotSceneRuleDO> sceneRules = getMatchedSceneRuleListByMessage(message);
@@ -223,7 +226,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
*/ */
private List<IotSceneRuleDO> getMatchedSceneRuleListByMessage(IotDeviceMessage message) { private List<IotSceneRuleDO> getMatchedSceneRuleListByMessage(IotDeviceMessage message) {
// 1. 匹配设备 // 1. 匹配设备
// TODO @芋艿:可能需要 getSelf(); 缓存 // TODO @芋艿:可能需要 getSelf(); 缓存 @puhui999
// 1.1 通过 deviceId 获取设备信息 // 1.1 通过 deviceId 获取设备信息
IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId());
if (device == null) { if (device == null) {
@@ -342,7 +345,6 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
private boolean isTriggerConditionMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition, private boolean isTriggerConditionMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition,
IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) { IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) {
try { try {
// 使用重构后的条件匹配管理器进行匹配
return matcherManager.isConditionMatched(message, condition); return matcherManager.isConditionMatched(message, condition);
} catch (Exception e) { } catch (Exception e) {
log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]", log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]",
@@ -351,8 +353,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
} }
} }
// TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。 // TODO @puhui999下面还需要么
/** /**
* 判断触发器的条件参数是否匹配 * 判断触发器的条件参数是否匹配
* *

View File

@@ -24,6 +24,8 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
@Slf4j @Slf4j
public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher { public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher {
// TODO @puhui999这个是不是也是【通用】条件哈
/** /**
* 评估条件是否匹配 * 评估条件是否匹配
* *
@@ -32,6 +34,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
* @param paramValue 参数值(来自条件配置) * @param paramValue 参数值(来自条件配置)
* @return 是否匹配 * @return 是否匹配
*/ */
@SuppressWarnings("DataFlowIssue")
protected boolean evaluateCondition(Object sourceValue, String operator, String paramValue) { protected boolean evaluateCondition(Object sourceValue, String operator, String paramValue) {
try { try {
// 1. 校验操作符是否合法 // 1. 校验操作符是否合法
@@ -48,6 +51,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
// 处理参数值 // 处理参数值
if (StrUtil.isNotBlank(paramValue)) { if (StrUtil.isNotBlank(paramValue)) {
// 处理多值情况(如 IN、BETWEEN 操作符) // 处理多值情况(如 IN、BETWEEN 操作符)
// TODO @puhui999使用这个会不会有问题例如说string 恰好有 分隔?
if (paramValue.contains(",")) { if (paramValue.contains(",")) {
List<String> paramValues = StrUtil.split(paramValue, ','); List<String> paramValues = StrUtil.split(paramValue, ',');
springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST,
@@ -68,7 +72,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
} }
} }
// ========== 触发器相关工具方法 ========== // ========== 触发器相关工具方法 ==========
/** /**
* 检查基础触发器参数是否有效 * 检查基础触发器参数是否有效
@@ -111,7 +115,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
log.debug("[{}][消息({}) 匹配触发器({}) 失败: {}]", getMatcherName(), message.getRequestId(), trigger.getType(), reason); log.debug("[{}][消息({}) 匹配触发器({}) 失败: {}]", getMatcherName(), message.getRequestId(), trigger.getType(), reason);
} }
// ========== 条件相关工具方法 ========== // ========== 条件相关工具方法 ==========
/** /**
* 检查基础条件参数是否有效 * 检查基础条件参数是否有效
@@ -154,7 +158,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
log.debug("[{}][消息({}) 匹配条件({}) 失败: {}]", getMatcherName(), message.getRequestId(), condition.getType(), reason); log.debug("[{}][消息({}) 匹配条件({}) 失败: {}]", getMatcherName(), message.getRequestId(), condition.getType(), reason);
} }
// ========== 通用工具方法 ========== // ========== 通用工具方法 ==========
/** /**
* 检查标识符是否匹配 * 检查标识符是否匹配

View File

@@ -56,15 +56,11 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
return false; return false;
} }
// 3. 获取当前时间 // 3. 根据操作符类型进行不同的时间匹配
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
// 4. 根据操作符类型进行不同的时间匹配
String operator = condition.getOperator(); String operator = condition.getOperator();
String param = condition.getParam(); String param = condition.getParam();
boolean matched;
boolean matched = false;
try { try {
if (operator.startsWith("date_time_")) { if (operator.startsWith("date_time_")) {
// 日期时间匹配(时间戳) // 日期时间匹配(时间戳)
@@ -82,13 +78,11 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
} else { } else {
logConditionMatchFailure(message, condition, "时间条件不匹配"); logConditionMatchFailure(message, condition, "时间条件不匹配");
} }
} catch (Exception e) { } catch (Exception e) {
log.error("[CurrentTimeConditionMatcher][时间条件匹配异常] operator: {}, param: {}", operator, param, e); log.error("[CurrentTimeConditionMatcher][时间条件匹配异常] operator: {}, param: {}", operator, param, e);
logConditionMatchFailure(message, condition, "时间条件匹配异常: " + e.getMessage()); logConditionMatchFailure(message, condition, "时间条件匹配异常: " + e.getMessage());
matched = false; matched = false;
} }
return matched; return matched;
} }
@@ -107,21 +101,20 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
try { try {
String actualOperator = operator.substring("time_".length()); String actualOperator = operator.substring("time_".length());
// TODO @puhui999if return 简化;
if ("between".equals(actualOperator)) { if ("between".equals(actualOperator)) {
// 时间区间匹配 // 时间区间匹配
String[] timeRange = param.split(","); String[] timeRange = param.split(",");
if (timeRange.length != 2) { if (timeRange.length != 2) {
return false; return false;
} }
LocalTime startTime = parseTime(timeRange[0].trim()); LocalTime startTime = parseTime(timeRange[0].trim());
LocalTime endTime = parseTime(timeRange[1].trim()); LocalTime endTime = parseTime(timeRange[1].trim());
return !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime); return !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime);
} else { } else {
// 单个时间比较 // 单个时间比较
LocalTime targetTime = parseTime(param); LocalTime targetTime = parseTime(param);
// TODO @puhui999枚举类
switch (actualOperator) { switch (actualOperator) {
case ">": case ">":
return currentTime.isAfter(targetTime); return currentTime.isAfter(targetTime);
@@ -138,6 +131,7 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
} }
} }
} catch (Exception e) { } catch (Exception e) {
// TODO @puhui9991日志格式 [][]2方法名不对哈
log.error("[CurrentTimeConditionMatcher][时间解析异常] param: {}", param, e); log.error("[CurrentTimeConditionMatcher][时间解析异常] param: {}", param, e);
return false; return false;
} }
@@ -147,10 +141,10 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
* 解析时间字符串 * 解析时间字符串
*/ */
private LocalTime parseTime(String timeStr) { private LocalTime parseTime(String timeStr) {
// TODO @puhui999可以用 hutool Assert 类简化
if (StrUtil.isBlank(timeStr)) { if (StrUtil.isBlank(timeStr)) {
throw new IllegalArgumentException("时间字符串不能为空"); throw new IllegalArgumentException("时间字符串不能为空");
} }
// 尝试不同的时间格式 // 尝试不同的时间格式
try { try {
if (timeStr.length() == 5) { // HH:mm if (timeStr.length() == 5) { // HH:mm

View File

@@ -26,6 +26,7 @@ public class DevicePropertyConditionMatcher extends AbstractIotSceneRuleMatcher
return IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY; return IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY;
} }
// TODO @puhui999参数校验的要不要 1.1 1.2 1.3 1.4 ?这样最终看到 2. 3. 就是核心逻辑列;
@Override @Override
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) {
// 1. 基础参数校验 // 1. 基础参数校验
@@ -56,13 +57,11 @@ public class DevicePropertyConditionMatcher extends AbstractIotSceneRuleMatcher
// 5. 使用条件评估器进行匹配 // 5. 使用条件评估器进行匹配
boolean matched = evaluateCondition(propertyValue, condition.getOperator(), condition.getParam()); boolean matched = evaluateCondition(propertyValue, condition.getOperator(), condition.getParam());
if (matched) { if (matched) {
logConditionMatchSuccess(message, condition); logConditionMatchSuccess(message, condition);
} else { } else {
logConditionMatchFailure(message, condition, "设备属性条件不匹配"); logConditionMatchFailure(message, condition, "设备属性条件不匹配");
} }
return matched; return matched;
} }

View File

@@ -20,6 +20,7 @@ public class DevicePropertyPostTriggerMatcher extends AbstractIotSceneRuleMatche
/** /**
* 设备属性上报消息方法 * 设备属性上报消息方法
*/ */
// TODO @puhui999是不是不用枚举哈直接使用 IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()
private static final String DEVICE_PROPERTY_POST_METHOD = IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod(); private static final String DEVICE_PROPERTY_POST_METHOD = IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod();
@Override @Override
@@ -68,13 +69,11 @@ public class DevicePropertyPostTriggerMatcher extends AbstractIotSceneRuleMatche
// 6. 使用条件评估器进行匹配 // 6. 使用条件评估器进行匹配
boolean matched = evaluateCondition(propertyValue, trigger.getOperator(), trigger.getValue()); boolean matched = evaluateCondition(propertyValue, trigger.getOperator(), trigger.getValue());
if (matched) { if (matched) {
logTriggerMatchSuccess(message, trigger); logTriggerMatchSuccess(message, trigger);
} else { } else {
logTriggerMatchFailure(message, trigger, "属性值条件不匹配"); logTriggerMatchFailure(message, trigger, "属性值条件不匹配");
} }
return matched; return matched;
} }

View File

@@ -49,13 +49,11 @@ public class DeviceStateConditionMatcher extends AbstractIotSceneRuleMatcher {
// 4. 使用条件评估器进行匹配 // 4. 使用条件评估器进行匹配
boolean matched = evaluateCondition(stateValue, condition.getOperator(), condition.getParam()); boolean matched = evaluateCondition(stateValue, condition.getOperator(), condition.getParam());
if (matched) { if (matched) {
logConditionMatchSuccess(message, condition); logConditionMatchSuccess(message, condition);
} else { } else {
logConditionMatchFailure(message, condition, "设备状态条件不匹配"); logConditionMatchFailure(message, condition, "设备状态条件不匹配");
} }
return matched; return matched;
} }

View File

@@ -16,6 +16,7 @@ import org.springframework.stereotype.Component;
@Component @Component
public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher { public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher {
// TODO @puhui999是不是不用枚举哈
/** /**
* 设备状态更新消息方法 * 设备状态更新消息方法
*/ */
@@ -60,13 +61,11 @@ public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher
// 5. 使用条件评估器进行匹配 // 5. 使用条件评估器进行匹配
boolean matched = evaluateCondition(stateValue, trigger.getOperator(), trigger.getValue()); boolean matched = evaluateCondition(stateValue, trigger.getOperator(), trigger.getValue());
if (matched) { if (matched) {
logTriggerMatchSuccess(message, trigger); logTriggerMatchSuccess(message, trigger);
} else { } else {
logTriggerMatchFailure(message, trigger, "状态值条件不匹配"); logTriggerMatchFailure(message, trigger, "状态值条件不匹配");
} }
return matched; return matched;
} }

View File

@@ -18,18 +18,23 @@ import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
*/ */
public interface IotSceneRuleMatcher { public interface IotSceneRuleMatcher {
// TODO @puhui999MatcherTypeEnum
// TODO @puhui999可以考虑根据类型新建 trigger、condition 包,然后把对应的实现类放进去哈;
/** /**
* 匹配器类型枚举 * 匹配器类型枚举
*/ */
enum MatcherType { enum MatcherType {
/** /**
* 触发器匹配器 - 用于匹配主触发条件 * 触发器匹配器 - 用于匹配主触发条件
*/ */
TRIGGER, TRIGGER,
/** /**
* 条件匹配器 - 用于匹配子条件 * 条件匹配器 - 用于匹配子条件
*/ */
CONDITION CONDITION
} }
/** /**
@@ -39,6 +44,10 @@ public interface IotSceneRuleMatcher {
*/ */
MatcherType getMatcherType(); MatcherType getMatcherType();
// TODO @puhui999【重要】有个思路IotSceneRuleMatcher 拆分成 2 种 mather 接口;然后 AbstractIotSceneRuleMatcher 是个 Helper 工具类;
// TODO @puhui999是不是和 AbstractSceneRuleMatcher 一样,分下块;
/** /**
* 获取支持的触发器类型(仅触发器匹配器需要实现) * 获取支持的触发器类型(仅触发器匹配器需要实现)
* *
@@ -90,6 +99,7 @@ public interface IotSceneRuleMatcher {
return 100; return 100;
} }
// TODO @puhui999如果目前没自定义体感可以删除哈
/** /**
* 获取匹配器名称,用于日志和调试 * 获取匹配器名称,用于日志和调试
* *

View File

@@ -30,14 +30,14 @@ public class IotSceneRuleMatcherManager {
* Key: 触发器类型枚举 * Key: 触发器类型枚举
* Value: 对应的匹配器实例 * Value: 对应的匹配器实例
*/ */
private final Map<IotSceneRuleTriggerTypeEnum, IotSceneRuleMatcher> triggerMatcherMap; private final Map<IotSceneRuleTriggerTypeEnum, IotSceneRuleMatcher> triggerMatchers;
/** /**
* 条件匹配器映射表 * 条件匹配器映射表
* Key: 条件类型枚举 * Key: 条件类型枚举
* Value: 对应的匹配器实例 * Value: 对应的匹配器实例
*/ */
private final Map<IotSceneRuleConditionTypeEnum, IotSceneRuleMatcher> conditionMatcherMap; private final Map<IotSceneRuleConditionTypeEnum, IotSceneRuleMatcher> conditionMatchers;
/** /**
* 所有匹配器列表(按优先级排序) * 所有匹配器列表(按优先级排序)
@@ -47,8 +47,8 @@ public class IotSceneRuleMatcherManager {
public IotSceneRuleMatcherManager(List<IotSceneRuleMatcher> matchers) { public IotSceneRuleMatcherManager(List<IotSceneRuleMatcher> matchers) {
if (CollUtil.isEmpty(matchers)) { if (CollUtil.isEmpty(matchers)) {
log.warn("[IotSceneRuleMatcherManager][没有找到任何匹配器]"); log.warn("[IotSceneRuleMatcherManager][没有找到任何匹配器]");
this.triggerMatcherMap = new HashMap<>(); this.triggerMatchers = new HashMap<>();
this.conditionMatcherMap = new HashMap<>(); this.conditionMatchers = new HashMap<>();
this.allMatchers = new ArrayList<>(); this.allMatchers = new ArrayList<>();
return; return;
} }
@@ -63,13 +63,13 @@ public class IotSceneRuleMatcherManager {
List<IotSceneRuleMatcher> triggerMatchers = this.allMatchers.stream() List<IotSceneRuleMatcher> triggerMatchers = this.allMatchers.stream()
.filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherType.TRIGGER) .filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherType.TRIGGER)
.toList(); .toList();
List<IotSceneRuleMatcher> conditionMatchers = this.allMatchers.stream() List<IotSceneRuleMatcher> conditionMatchers = this.allMatchers.stream()
.filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherType.CONDITION) .filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherType.CONDITION)
.toList(); .toList();
// 构建触发器匹配器映射表 // 构建触发器匹配器映射表
this.triggerMatcherMap = triggerMatchers.stream() // TODO @puhui999convertMap()
this.triggerMatchers = triggerMatchers.stream()
.collect(Collectors.toMap( .collect(Collectors.toMap(
IotSceneRuleMatcher::getSupportedTriggerType, IotSceneRuleMatcher::getSupportedTriggerType,
Function.identity(), Function.identity(),
@@ -81,9 +81,8 @@ public class IotSceneRuleMatcherManager {
}, },
LinkedHashMap::new LinkedHashMap::new
)); ));
// 构建条件匹配器映射表 // 构建条件匹配器映射表
this.conditionMatcherMap = conditionMatchers.stream() this.conditionMatchers = conditionMatchers.stream()
.collect(Collectors.toMap( .collect(Collectors.toMap(
IotSceneRuleMatcher::getSupportedConditionType, IotSceneRuleMatcher::getSupportedConditionType,
Function.identity(), Function.identity(),
@@ -96,16 +95,13 @@ public class IotSceneRuleMatcherManager {
LinkedHashMap::new LinkedHashMap::new
)); ));
// 日志输出初始化信息
log.info("[IotSceneRuleMatcherManager][初始化完成,共加载 {} 个匹配器,其中触发器匹配器 {} 个,条件匹配器 {} 个]", log.info("[IotSceneRuleMatcherManager][初始化完成,共加载 {} 个匹配器,其中触发器匹配器 {} 个,条件匹配器 {} 个]",
this.allMatchers.size(), this.triggerMatcherMap.size(), this.conditionMatcherMap.size()); this.allMatchers.size(), this.triggerMatchers.size(), this.conditionMatchers.size());
this.triggerMatchers.forEach((type, matcher) ->
// 记录触发器匹配器详情
this.triggerMatcherMap.forEach((type, matcher) ->
log.info("[IotSceneRuleMatcherManager][触发器匹配器] 类型: {}, 匹配器: {}, 优先级: {}", log.info("[IotSceneRuleMatcherManager][触发器匹配器] 类型: {}, 匹配器: {}, 优先级: {}",
type, matcher.getMatcherName(), matcher.getPriority())); type, matcher.getMatcherName(), matcher.getPriority()));
this.conditionMatchers.forEach((type, matcher) ->
// 记录条件匹配器详情
this.conditionMatcherMap.forEach((type, matcher) ->
log.info("[IotSceneRuleMatcherManager][条件匹配器] 类型: {}, 匹配器: {}, 优先级: {}", log.info("[IotSceneRuleMatcherManager][条件匹配器] 类型: {}, 匹配器: {}, 优先级: {}",
type, matcher.getMatcherName(), matcher.getPriority())); type, matcher.getMatcherName(), matcher.getPriority()));
} }
@@ -118,19 +114,17 @@ public class IotSceneRuleMatcherManager {
* @return 是否匹配 * @return 是否匹配
*/ */
public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) {
// TODO @puhui999日志优化下claude 打出来的日志风格,和项目有点不一样哈;
if (message == null || trigger == null || trigger.getType() == null) { if (message == null || trigger == null || trigger.getType() == null) {
log.debug("[isMatched][参数无效] message: {}, trigger: {}", message, trigger); log.debug("[isMatched][参数无效] message: {}, trigger: {}", message, trigger);
return false; return false;
} }
// 根据触发器类型查找对应的匹配器
IotSceneRuleTriggerTypeEnum triggerType = findTriggerTypeEnum(trigger.getType()); IotSceneRuleTriggerTypeEnum triggerType = findTriggerTypeEnum(trigger.getType());
if (triggerType == null) { if (triggerType == null) {
log.warn("[isMatched][未知的触发器类型: {}]", trigger.getType()); log.warn("[isMatched][未知的触发器类型: {}]", trigger.getType());
return false; return false;
} }
IotSceneRuleMatcher matcher = triggerMatchers.get(triggerType);
IotSceneRuleMatcher matcher = triggerMatcherMap.get(triggerType);
if (matcher == null) { if (matcher == null) {
log.warn("[isMatched][触发器类型({})没有对应的匹配器]", triggerType); log.warn("[isMatched][触发器类型({})没有对应的匹配器]", triggerType);
return false; return false;
@@ -165,7 +159,7 @@ public class IotSceneRuleMatcherManager {
return false; return false;
} }
IotSceneRuleMatcher matcher = conditionMatcherMap.get(conditionType); IotSceneRuleMatcher matcher = conditionMatchers.get(conditionType);
if (matcher == null) { if (matcher == null) {
log.warn("[isConditionMatched][条件类型({})没有对应的匹配器]", conditionType); log.warn("[isConditionMatched][条件类型({})没有对应的匹配器]", conditionType);
return false; return false;
@@ -199,7 +193,7 @@ public class IotSceneRuleMatcherManager {
* @return 支持的触发器类型列表 * @return 支持的触发器类型列表
*/ */
public Set<IotSceneRuleTriggerTypeEnum> getSupportedTriggerTypes() { public Set<IotSceneRuleTriggerTypeEnum> getSupportedTriggerTypes() {
return new HashSet<>(triggerMatcherMap.keySet()); return new HashSet<>(triggerMatchers.keySet());
} }
/** /**
@@ -208,9 +202,11 @@ public class IotSceneRuleMatcherManager {
* @return 支持的条件类型列表 * @return 支持的条件类型列表
*/ */
public Set<IotSceneRuleConditionTypeEnum> getSupportedConditionTypes() { public Set<IotSceneRuleConditionTypeEnum> getSupportedConditionTypes() {
return new HashSet<>(conditionMatcherMap.keySet()); return new HashSet<>(conditionMatchers.keySet());
} }
// TODO @puhui999用不到的方法可以去掉先哈
/** /**
* 获取指定触发器类型的匹配器 * 获取指定触发器类型的匹配器
* *
@@ -218,7 +214,7 @@ public class IotSceneRuleMatcherManager {
* @return 匹配器实例,如果不存在则返回 null * @return 匹配器实例,如果不存在则返回 null
*/ */
public IotSceneRuleMatcher getTriggerMatcher(IotSceneRuleTriggerTypeEnum triggerType) { public IotSceneRuleMatcher getTriggerMatcher(IotSceneRuleTriggerTypeEnum triggerType) {
return triggerMatcherMap.get(triggerType); return triggerMatchers.get(triggerType);
} }
/** /**
@@ -228,9 +224,10 @@ public class IotSceneRuleMatcherManager {
* @return 匹配器实例,如果不存在则返回 null * @return 匹配器实例,如果不存在则返回 null
*/ */
public IotSceneRuleMatcher getConditionMatcher(IotSceneRuleConditionTypeEnum conditionType) { public IotSceneRuleMatcher getConditionMatcher(IotSceneRuleConditionTypeEnum conditionType) {
return conditionMatcherMap.get(conditionType); return conditionMatchers.get(conditionType);
} }
// TODO @puhui999是不是不用这个哈直接 @Getter单测直接处理
/** /**
* 获取所有匹配器的统计信息 * 获取所有匹配器的统计信息
* *
@@ -239,14 +236,14 @@ public class IotSceneRuleMatcherManager {
public Map<String, Object> getMatcherStatistics() { public Map<String, Object> getMatcherStatistics() {
Map<String, Object> statistics = new HashMap<>(); Map<String, Object> statistics = new HashMap<>();
statistics.put("totalMatchers", allMatchers.size()); statistics.put("totalMatchers", allMatchers.size());
statistics.put("triggerMatchers", triggerMatcherMap.size()); statistics.put("triggerMatchers", triggerMatchers.size());
statistics.put("conditionMatchers", conditionMatcherMap.size()); statistics.put("conditionMatchers", conditionMatchers.size());
statistics.put("supportedTriggerTypes", getSupportedTriggerTypes()); statistics.put("supportedTriggerTypes", getSupportedTriggerTypes());
statistics.put("supportedConditionTypes", getSupportedConditionTypes()); statistics.put("supportedConditionTypes", getSupportedConditionTypes());
// 触发器匹配器详情 // 触发器匹配器详情
Map<String, Object> triggerMatcherDetails = new HashMap<>(); Map<String, Object> triggerMatcherDetails = new HashMap<>();
triggerMatcherMap.forEach((type, matcher) -> { triggerMatchers.forEach((type, matcher) -> {
Map<String, Object> detail = new HashMap<>(); Map<String, Object> detail = new HashMap<>();
detail.put("matcherName", matcher.getMatcherName()); detail.put("matcherName", matcher.getMatcherName());
detail.put("priority", matcher.getPriority()); detail.put("priority", matcher.getPriority());
@@ -257,7 +254,7 @@ public class IotSceneRuleMatcherManager {
// 条件匹配器详情 // 条件匹配器详情
Map<String, Object> conditionMatcherDetails = new HashMap<>(); Map<String, Object> conditionMatcherDetails = new HashMap<>();
conditionMatcherMap.forEach((type, matcher) -> { conditionMatchers.forEach((type, matcher) -> {
Map<String, Object> detail = new HashMap<>(); Map<String, Object> detail = new HashMap<>();
detail.put("matcherName", matcher.getMatcherName()); detail.put("matcherName", matcher.getMatcherName());
detail.put("priority", matcher.getPriority()); detail.put("priority", matcher.getPriority());

View File

@@ -61,6 +61,7 @@ public class TimerTriggerMatcher extends AbstractIotSceneRuleMatcher {
* @return 是否有效 * @return 是否有效
*/ */
private boolean isValidCronExpression(String cronExpression) { private boolean isValidCronExpression(String cronExpression) {
// TODO @puhui999CronExpression.isValidExpression(cronExpression);
try { try {
// 简单的 CRON 表达式格式验证 // 简单的 CRON 表达式格式验证
// 标准 CRON 表达式应该有 6 或 7 个字段(秒 分 时 日 月 周 [年] // 标准 CRON 表达式应该有 6 或 7 个字段(秒 分 时 日 月 周 [年]

View File

@@ -20,6 +20,8 @@ import static org.junit.jupiter.api.Assertions.*;
*/ */
public class IotSceneRuleTriggerMatcherTest extends BaseMockitoUnitTest { public class IotSceneRuleTriggerMatcherTest extends BaseMockitoUnitTest {
// TODO @puhui999public 都加下哈;
private IotSceneRuleMatcherManager matcherManager; private IotSceneRuleMatcherManager matcherManager;
@BeforeEach @BeforeEach
@@ -42,13 +44,13 @@ public class IotSceneRuleTriggerMatcherTest extends BaseMockitoUnitTest {
// 1. 准备测试数据 // 1. 准备测试数据
IotDeviceMessage message = IotDeviceMessage.builder() IotDeviceMessage message = IotDeviceMessage.builder()
.requestId("test-001") .requestId("test-001")
.method("thing.state.update") .method("thing.state.update") // TODO @puhui999这里的枚举
.data(1) // 在线状态 .data(1) // 在线状态 TODO @puhui999这里的枚举
.build(); .build();
IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType()); trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType());
trigger.setOperator("="); trigger.setOperator("="); // TODO @puhui999这里的枚举下面也是类似
trigger.setValue("1"); trigger.setValue("1");
// 2. 执行测试 // 2. 执行测试