Commit 6791c628589b66b7419bf46a3e476d29d0d77470

Authored by YunaiV
1 parent f88d30f1

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

Showing 13 changed files with 65 additions and 62 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleTriggerTypeEnum.java
@@ -60,7 +60,7 @@ public enum IotSceneRuleTriggerTypeEnum implements ArrayValuable<Integer> { @@ -60,7 +60,7 @@ public enum IotSceneRuleTriggerTypeEnum implements ArrayValuable<Integer> {
60 return ARRAYS; 60 return ARRAYS;
61 } 61 }
62 62
63 - 63 + // TODO @puhui999:可以参考下别的枚举哈,方法名,和实现都可以更简洁;of(String type) { firstMatch
64 /** 64 /**
65 * 根据类型值查找触发器类型枚举 65 * 根据类型值查找触发器类型枚举
66 * 66 *
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisRuleAction.java
@@ -45,7 +45,6 @@ public class IotRedisRuleAction extends @@ -45,7 +45,6 @@ public class IotRedisRuleAction extends
45 // 2. 根据数据结构类型执行不同的操作 45 // 2. 根据数据结构类型执行不同的操作
46 String messageJson = JsonUtils.toJsonString(message); 46 String messageJson = JsonUtils.toJsonString(message);
47 IotRedisDataStructureEnum dataStructure = getDataStructureByType(config.getDataStructure()); 47 IotRedisDataStructureEnum dataStructure = getDataStructureByType(config.getDataStructure());
48 -  
49 switch (dataStructure) { 48 switch (dataStructure) {
50 case STREAM: 49 case STREAM:
51 executeStream(redisTemplate, config, messageJson); 50 executeStream(redisTemplate, config, messageJson);
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java
@@ -58,12 +58,15 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -58,12 +58,15 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
58 @Resource 58 @Resource
59 private IotSceneRuleMapper sceneRuleMapper; 59 private IotSceneRuleMapper sceneRuleMapper;
60 60
  61 + // TODO @puhui999:定时任务,基于它调度;
61 @Resource(name = "iotSchedulerManager") 62 @Resource(name = "iotSchedulerManager")
62 private IotSchedulerManager schedulerManager; 63 private IotSchedulerManager schedulerManager;
63 @Resource 64 @Resource
64 private IotProductService productService; 65 private IotProductService productService;
65 @Resource 66 @Resource
66 private IotDeviceService deviceService; 67 private IotDeviceService deviceService;
  68 +
  69 + // TODO @puhui999:sceneRuleMatcherManager 变量名
67 @Resource 70 @Resource
68 private IotSceneRuleMatcherManager matcherManager; 71 private IotSceneRuleMatcherManager matcherManager;
69 @Resource 72 @Resource
@@ -135,7 +138,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -135,7 +138,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
135 return sceneRuleMapper.selectListByStatus(status); 138 return sceneRuleMapper.selectListByStatus(status);
136 } 139 }
137 140
138 - // TODO 芋艿,缓存待实现 141 + // TODO 芋艿,缓存待实现 @puhui999
139 @Override 142 @Override
140 @TenantIgnore // 忽略租户隔离:因为 IotSceneRuleMessageHandler 调用时,一般未传递租户,所以需要忽略 143 @TenantIgnore // 忽略租户隔离:因为 IotSceneRuleMessageHandler 调用时,一般未传递租户,所以需要忽略
141 public List<IotSceneRuleDO> getSceneRuleListByProductIdAndDeviceIdFromCache(Long productId, Long deviceId) { 144 public List<IotSceneRuleDO> getSceneRuleListByProductIdAndDeviceIdFromCache(Long productId, Long deviceId) {
@@ -177,7 +180,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -177,7 +180,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
177 180
178 @Override 181 @Override
179 public void executeSceneRuleByDevice(IotDeviceMessage message) { 182 public void executeSceneRuleByDevice(IotDeviceMessage message) {
180 - // TODO @芋艿:这里的 tenantId,通过设备获取; 183 + // TODO @芋艿:这里的 tenantId,通过设备获取;@puhui999:
181 TenantUtils.execute(message.getTenantId(), () -> { 184 TenantUtils.execute(message.getTenantId(), () -> {
182 // 1. 获得设备匹配的规则场景 185 // 1. 获得设备匹配的规则场景
183 List<IotSceneRuleDO> sceneRules = getMatchedSceneRuleListByMessage(message); 186 List<IotSceneRuleDO> sceneRules = getMatchedSceneRuleListByMessage(message);
@@ -223,7 +226,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -223,7 +226,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
223 */ 226 */
224 private List<IotSceneRuleDO> getMatchedSceneRuleListByMessage(IotDeviceMessage message) { 227 private List<IotSceneRuleDO> getMatchedSceneRuleListByMessage(IotDeviceMessage message) {
225 // 1. 匹配设备 228 // 1. 匹配设备
226 - // TODO @芋艿:可能需要 getSelf(); 缓存 229 + // TODO @芋艿:可能需要 getSelf(); 缓存 @puhui999;
227 // 1.1 通过 deviceId 获取设备信息 230 // 1.1 通过 deviceId 获取设备信息
228 IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); 231 IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId());
229 if (device == null) { 232 if (device == null) {
@@ -342,7 +345,6 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -342,7 +345,6 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
342 private boolean isTriggerConditionMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition, 345 private boolean isTriggerConditionMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition,
343 IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) { 346 IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) {
344 try { 347 try {
345 - // 使用重构后的条件匹配管理器进行匹配  
346 return matcherManager.isConditionMatched(message, condition); 348 return matcherManager.isConditionMatched(message, condition);
347 } catch (Exception e) { 349 } catch (Exception e) {
348 log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]", 350 log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]",
@@ -351,8 +353,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -351,8 +353,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
351 } 353 }
352 } 354 }
353 355
354 - // TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。  
355 - 356 + // TODO @puhui999:下面还需要么?
356 /** 357 /**
357 * 判断触发器的条件参数是否匹配 358 * 判断触发器的条件参数是否匹配
358 * 359 *
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/AbstractIotSceneRuleMatcher.java
@@ -24,6 +24,8 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @@ -24,6 +24,8 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
24 @Slf4j 24 @Slf4j
25 public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher { 25 public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher {
26 26
  27 + // TODO @puhui999:这个是不是也是【通用】条件哈?
  28 +
27 /** 29 /**
28 * 评估条件是否匹配 30 * 评估条件是否匹配
29 * 31 *
@@ -32,6 +34,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher @@ -32,6 +34,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
32 * @param paramValue 参数值(来自条件配置) 34 * @param paramValue 参数值(来自条件配置)
33 * @return 是否匹配 35 * @return 是否匹配
34 */ 36 */
  37 + @SuppressWarnings("DataFlowIssue")
35 protected boolean evaluateCondition(Object sourceValue, String operator, String paramValue) { 38 protected boolean evaluateCondition(Object sourceValue, String operator, String paramValue) {
36 try { 39 try {
37 // 1. 校验操作符是否合法 40 // 1. 校验操作符是否合法
@@ -48,6 +51,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher @@ -48,6 +51,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
48 // 处理参数值 51 // 处理参数值
49 if (StrUtil.isNotBlank(paramValue)) { 52 if (StrUtil.isNotBlank(paramValue)) {
50 // 处理多值情况(如 IN、BETWEEN 操作符) 53 // 处理多值情况(如 IN、BETWEEN 操作符)
  54 + // TODO @puhui999:使用这个,会不会有问题?例如说:string 恰好有 , 分隔?
51 if (paramValue.contains(",")) { 55 if (paramValue.contains(",")) {
52 List<String> paramValues = StrUtil.split(paramValue, ','); 56 List<String> paramValues = StrUtil.split(paramValue, ',');
53 springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, 57 springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST,
@@ -68,7 +72,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher @@ -68,7 +72,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
68 } 72 }
69 } 73 }
70 74
71 - // ========== 触发器相关工具方法 ========== 75 + // ========== 【触发器】相关工具方法 ==========
72 76
73 /** 77 /**
74 * 检查基础触发器参数是否有效 78 * 检查基础触发器参数是否有效
@@ -111,7 +115,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher @@ -111,7 +115,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
111 log.debug("[{}][消息({}) 匹配触发器({}) 失败: {}]", getMatcherName(), message.getRequestId(), trigger.getType(), reason); 115 log.debug("[{}][消息({}) 匹配触发器({}) 失败: {}]", getMatcherName(), message.getRequestId(), trigger.getType(), reason);
112 } 116 }
113 117
114 - // ========== 条件相关工具方法 ========== 118 + // ========== 【条件】相关工具方法 ==========
115 119
116 /** 120 /**
117 * 检查基础条件参数是否有效 121 * 检查基础条件参数是否有效
@@ -154,7 +158,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher @@ -154,7 +158,7 @@ public abstract class AbstractIotSceneRuleMatcher implements IotSceneRuleMatcher
154 log.debug("[{}][消息({}) 匹配条件({}) 失败: {}]", getMatcherName(), message.getRequestId(), condition.getType(), reason); 158 log.debug("[{}][消息({}) 匹配条件({}) 失败: {}]", getMatcherName(), message.getRequestId(), condition.getType(), reason);
155 } 159 }
156 160
157 - // ========== 通用工具方法 ========== 161 + // ========== 【通用】工具方法 ==========
158 162
159 /** 163 /**
160 * 检查标识符是否匹配 164 * 检查标识符是否匹配
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/CurrentTimeConditionMatcher.java
@@ -56,15 +56,11 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { @@ -56,15 +56,11 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
56 return false; 56 return false;
57 } 57 }
58 58
59 - // 3. 获取当前时间 59 + // 3. 根据操作符类型进行不同的时间匹配
60 LocalDateTime now = LocalDateTime.now(); 60 LocalDateTime now = LocalDateTime.now();
61 -  
62 - // 4. 根据操作符类型进行不同的时间匹配  
63 String operator = condition.getOperator(); 61 String operator = condition.getOperator();
64 String param = condition.getParam(); 62 String param = condition.getParam();
65 -  
66 - boolean matched = false;  
67 - 63 + boolean matched;
68 try { 64 try {
69 if (operator.startsWith("date_time_")) { 65 if (operator.startsWith("date_time_")) {
70 // 日期时间匹配(时间戳) 66 // 日期时间匹配(时间戳)
@@ -82,13 +78,11 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { @@ -82,13 +78,11 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
82 } else { 78 } else {
83 logConditionMatchFailure(message, condition, "时间条件不匹配"); 79 logConditionMatchFailure(message, condition, "时间条件不匹配");
84 } 80 }
85 -  
86 } catch (Exception e) { 81 } catch (Exception e) {
87 log.error("[CurrentTimeConditionMatcher][时间条件匹配异常] operator: {}, param: {}", operator, param, e); 82 log.error("[CurrentTimeConditionMatcher][时间条件匹配异常] operator: {}, param: {}", operator, param, e);
88 logConditionMatchFailure(message, condition, "时间条件匹配异常: " + e.getMessage()); 83 logConditionMatchFailure(message, condition, "时间条件匹配异常: " + e.getMessage());
89 matched = false; 84 matched = false;
90 } 85 }
91 -  
92 return matched; 86 return matched;
93 } 87 }
94 88
@@ -107,21 +101,20 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { @@ -107,21 +101,20 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
107 try { 101 try {
108 String actualOperator = operator.substring("time_".length()); 102 String actualOperator = operator.substring("time_".length());
109 103
  104 + // TODO @puhui999:if return 简化;
110 if ("between".equals(actualOperator)) { 105 if ("between".equals(actualOperator)) {
111 // 时间区间匹配 106 // 时间区间匹配
112 String[] timeRange = param.split(","); 107 String[] timeRange = param.split(",");
113 if (timeRange.length != 2) { 108 if (timeRange.length != 2) {
114 return false; 109 return false;
115 } 110 }
116 -  
117 LocalTime startTime = parseTime(timeRange[0].trim()); 111 LocalTime startTime = parseTime(timeRange[0].trim());
118 LocalTime endTime = parseTime(timeRange[1].trim()); 112 LocalTime endTime = parseTime(timeRange[1].trim());
119 -  
120 return !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime); 113 return !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime);
121 } else { 114 } else {
122 // 单个时间比较 115 // 单个时间比较
123 LocalTime targetTime = parseTime(param); 116 LocalTime targetTime = parseTime(param);
124 - 117 + // TODO @puhui999:枚举类;
125 switch (actualOperator) { 118 switch (actualOperator) {
126 case ">": 119 case ">":
127 return currentTime.isAfter(targetTime); 120 return currentTime.isAfter(targetTime);
@@ -138,6 +131,7 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { @@ -138,6 +131,7 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
138 } 131 }
139 } 132 }
140 } catch (Exception e) { 133 } catch (Exception e) {
  134 + // TODO @puhui999:1)日志格式 [][];2)方法名不对哈;
141 log.error("[CurrentTimeConditionMatcher][时间解析异常] param: {}", param, e); 135 log.error("[CurrentTimeConditionMatcher][时间解析异常] param: {}", param, e);
142 return false; 136 return false;
143 } 137 }
@@ -147,10 +141,10 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher { @@ -147,10 +141,10 @@ public class CurrentTimeConditionMatcher extends AbstractIotSceneRuleMatcher {
147 * 解析时间字符串 141 * 解析时间字符串
148 */ 142 */
149 private LocalTime parseTime(String timeStr) { 143 private LocalTime parseTime(String timeStr) {
  144 + // TODO @puhui999:可以用 hutool Assert 类简化
150 if (StrUtil.isBlank(timeStr)) { 145 if (StrUtil.isBlank(timeStr)) {
151 throw new IllegalArgumentException("时间字符串不能为空"); 146 throw new IllegalArgumentException("时间字符串不能为空");
152 } 147 }
153 -  
154 // 尝试不同的时间格式 148 // 尝试不同的时间格式
155 try { 149 try {
156 if (timeStr.length() == 5) { // HH:mm 150 if (timeStr.length() == 5) { // HH:mm
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/DevicePropertyConditionMatcher.java
@@ -26,6 +26,7 @@ public class DevicePropertyConditionMatcher extends AbstractIotSceneRuleMatcher @@ -26,6 +26,7 @@ public class DevicePropertyConditionMatcher extends AbstractIotSceneRuleMatcher
26 return IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY; 26 return IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY;
27 } 27 }
28 28
  29 + // TODO @puhui999:参数校验的,要不要 1.1 1.2 1.3 1.4 ?这样最终看到 2. 3. 就是核心逻辑列;
29 @Override 30 @Override
30 public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { 31 public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) {
31 // 1. 基础参数校验 32 // 1. 基础参数校验
@@ -56,13 +57,11 @@ public class DevicePropertyConditionMatcher extends AbstractIotSceneRuleMatcher @@ -56,13 +57,11 @@ public class DevicePropertyConditionMatcher extends AbstractIotSceneRuleMatcher
56 57
57 // 5. 使用条件评估器进行匹配 58 // 5. 使用条件评估器进行匹配
58 boolean matched = evaluateCondition(propertyValue, condition.getOperator(), condition.getParam()); 59 boolean matched = evaluateCondition(propertyValue, condition.getOperator(), condition.getParam());
59 -  
60 if (matched) { 60 if (matched) {
61 logConditionMatchSuccess(message, condition); 61 logConditionMatchSuccess(message, condition);
62 } else { 62 } else {
63 logConditionMatchFailure(message, condition, "设备属性条件不匹配"); 63 logConditionMatchFailure(message, condition, "设备属性条件不匹配");
64 } 64 }
65 -  
66 return matched; 65 return matched;
67 } 66 }
68 67
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/DevicePropertyPostTriggerMatcher.java
@@ -20,6 +20,7 @@ public class DevicePropertyPostTriggerMatcher extends AbstractIotSceneRuleMatche @@ -20,6 +20,7 @@ public class DevicePropertyPostTriggerMatcher extends AbstractIotSceneRuleMatche
20 /** 20 /**
21 * 设备属性上报消息方法 21 * 设备属性上报消息方法
22 */ 22 */
  23 + // TODO @puhui999:是不是不用枚举哈?直接使用 IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod()
23 private static final String DEVICE_PROPERTY_POST_METHOD = IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod(); 24 private static final String DEVICE_PROPERTY_POST_METHOD = IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod();
24 25
25 @Override 26 @Override
@@ -68,13 +69,11 @@ public class DevicePropertyPostTriggerMatcher extends AbstractIotSceneRuleMatche @@ -68,13 +69,11 @@ public class DevicePropertyPostTriggerMatcher extends AbstractIotSceneRuleMatche
68 69
69 // 6. 使用条件评估器进行匹配 70 // 6. 使用条件评估器进行匹配
70 boolean matched = evaluateCondition(propertyValue, trigger.getOperator(), trigger.getValue()); 71 boolean matched = evaluateCondition(propertyValue, trigger.getOperator(), trigger.getValue());
71 -  
72 if (matched) { 72 if (matched) {
73 logTriggerMatchSuccess(message, trigger); 73 logTriggerMatchSuccess(message, trigger);
74 } else { 74 } else {
75 logTriggerMatchFailure(message, trigger, "属性值条件不匹配"); 75 logTriggerMatchFailure(message, trigger, "属性值条件不匹配");
76 } 76 }
77 -  
78 return matched; 77 return matched;
79 } 78 }
80 79
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/DeviceStateConditionMatcher.java
@@ -49,13 +49,11 @@ public class DeviceStateConditionMatcher extends AbstractIotSceneRuleMatcher { @@ -49,13 +49,11 @@ public class DeviceStateConditionMatcher extends AbstractIotSceneRuleMatcher {
49 49
50 // 4. 使用条件评估器进行匹配 50 // 4. 使用条件评估器进行匹配
51 boolean matched = evaluateCondition(stateValue, condition.getOperator(), condition.getParam()); 51 boolean matched = evaluateCondition(stateValue, condition.getOperator(), condition.getParam());
52 -  
53 if (matched) { 52 if (matched) {
54 logConditionMatchSuccess(message, condition); 53 logConditionMatchSuccess(message, condition);
55 } else { 54 } else {
56 logConditionMatchFailure(message, condition, "设备状态条件不匹配"); 55 logConditionMatchFailure(message, condition, "设备状态条件不匹配");
57 } 56 }
58 -  
59 return matched; 57 return matched;
60 } 58 }
61 59
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/DeviceStateUpdateTriggerMatcher.java
@@ -16,6 +16,7 @@ import org.springframework.stereotype.Component; @@ -16,6 +16,7 @@ import org.springframework.stereotype.Component;
16 @Component 16 @Component
17 public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher { 17 public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher {
18 18
  19 + // TODO @puhui999:是不是不用枚举哈;
19 /** 20 /**
20 * 设备状态更新消息方法 21 * 设备状态更新消息方法
21 */ 22 */
@@ -60,13 +61,11 @@ public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher @@ -60,13 +61,11 @@ public class DeviceStateUpdateTriggerMatcher extends AbstractIotSceneRuleMatcher
60 61
61 // 5. 使用条件评估器进行匹配 62 // 5. 使用条件评估器进行匹配
62 boolean matched = evaluateCondition(stateValue, trigger.getOperator(), trigger.getValue()); 63 boolean matched = evaluateCondition(stateValue, trigger.getOperator(), trigger.getValue());
63 -  
64 if (matched) { 64 if (matched) {
65 logTriggerMatchSuccess(message, trigger); 65 logTriggerMatchSuccess(message, trigger);
66 } else { 66 } else {
67 logTriggerMatchFailure(message, trigger, "状态值条件不匹配"); 67 logTriggerMatchFailure(message, trigger, "状态值条件不匹配");
68 } 68 }
69 -  
70 return matched; 69 return matched;
71 } 70 }
72 71
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcher.java
@@ -18,18 +18,23 @@ import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; @@ -18,18 +18,23 @@ import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
18 */ 18 */
19 public interface IotSceneRuleMatcher { 19 public interface IotSceneRuleMatcher {
20 20
  21 + // TODO @puhui999:MatcherTypeEnum;
  22 + // TODO @puhui999:可以考虑根据类型,新建 trigger、condition 包,然后把对应的实现类放进去哈;
21 /** 23 /**
22 * 匹配器类型枚举 24 * 匹配器类型枚举
23 */ 25 */
24 enum MatcherType { 26 enum MatcherType {
  27 +
25 /** 28 /**
26 * 触发器匹配器 - 用于匹配主触发条件 29 * 触发器匹配器 - 用于匹配主触发条件
27 */ 30 */
28 TRIGGER, 31 TRIGGER,
  32 +
29 /** 33 /**
30 * 条件匹配器 - 用于匹配子条件 34 * 条件匹配器 - 用于匹配子条件
31 */ 35 */
32 CONDITION 36 CONDITION
  37 +
33 } 38 }
34 39
35 /** 40 /**
@@ -39,6 +44,10 @@ public interface IotSceneRuleMatcher { @@ -39,6 +44,10 @@ public interface IotSceneRuleMatcher {
39 */ 44 */
40 MatcherType getMatcherType(); 45 MatcherType getMatcherType();
41 46
  47 + // TODO @puhui999:【重要】有个思路,IotSceneRuleMatcher 拆分成 2 种 mather 接口;然后 AbstractIotSceneRuleMatcher 是个 Helper 工具类;
  48 +
  49 + // TODO @puhui999:是不是和 AbstractSceneRuleMatcher 一样,分下块;
  50 +
42 /** 51 /**
43 * 获取支持的触发器类型(仅触发器匹配器需要实现) 52 * 获取支持的触发器类型(仅触发器匹配器需要实现)
44 * 53 *
@@ -90,6 +99,7 @@ public interface IotSceneRuleMatcher { @@ -90,6 +99,7 @@ public interface IotSceneRuleMatcher {
90 return 100; 99 return 100;
91 } 100 }
92 101
  102 + // TODO @puhui999:如果目前没自定义,体感可以删除哈;
93 /** 103 /**
94 * 获取匹配器名称,用于日志和调试 104 * 获取匹配器名称,用于日志和调试
95 * 105 *
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherManager.java
@@ -30,14 +30,14 @@ public class IotSceneRuleMatcherManager { @@ -30,14 +30,14 @@ public class IotSceneRuleMatcherManager {
30 * Key: 触发器类型枚举 30 * Key: 触发器类型枚举
31 * Value: 对应的匹配器实例 31 * Value: 对应的匹配器实例
32 */ 32 */
33 - private final Map<IotSceneRuleTriggerTypeEnum, IotSceneRuleMatcher> triggerMatcherMap; 33 + private final Map<IotSceneRuleTriggerTypeEnum, IotSceneRuleMatcher> triggerMatchers;
34 34
35 /** 35 /**
36 * 条件匹配器映射表 36 * 条件匹配器映射表
37 * Key: 条件类型枚举 37 * Key: 条件类型枚举
38 * Value: 对应的匹配器实例 38 * Value: 对应的匹配器实例
39 */ 39 */
40 - private final Map<IotSceneRuleConditionTypeEnum, IotSceneRuleMatcher> conditionMatcherMap; 40 + private final Map<IotSceneRuleConditionTypeEnum, IotSceneRuleMatcher> conditionMatchers;
41 41
42 /** 42 /**
43 * 所有匹配器列表(按优先级排序) 43 * 所有匹配器列表(按优先级排序)
@@ -47,8 +47,8 @@ public class IotSceneRuleMatcherManager { @@ -47,8 +47,8 @@ public class IotSceneRuleMatcherManager {
47 public IotSceneRuleMatcherManager(List<IotSceneRuleMatcher> matchers) { 47 public IotSceneRuleMatcherManager(List<IotSceneRuleMatcher> matchers) {
48 if (CollUtil.isEmpty(matchers)) { 48 if (CollUtil.isEmpty(matchers)) {
49 log.warn("[IotSceneRuleMatcherManager][没有找到任何匹配器]"); 49 log.warn("[IotSceneRuleMatcherManager][没有找到任何匹配器]");
50 - this.triggerMatcherMap = new HashMap<>();  
51 - this.conditionMatcherMap = new HashMap<>(); 50 + this.triggerMatchers = new HashMap<>();
  51 + this.conditionMatchers = new HashMap<>();
52 this.allMatchers = new ArrayList<>(); 52 this.allMatchers = new ArrayList<>();
53 return; 53 return;
54 } 54 }
@@ -63,13 +63,13 @@ public class IotSceneRuleMatcherManager { @@ -63,13 +63,13 @@ public class IotSceneRuleMatcherManager {
63 List<IotSceneRuleMatcher> triggerMatchers = this.allMatchers.stream() 63 List<IotSceneRuleMatcher> triggerMatchers = this.allMatchers.stream()
64 .filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherType.TRIGGER) 64 .filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherType.TRIGGER)
65 .toList(); 65 .toList();
66 -  
67 List<IotSceneRuleMatcher> conditionMatchers = this.allMatchers.stream() 66 List<IotSceneRuleMatcher> conditionMatchers = this.allMatchers.stream()
68 .filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherType.CONDITION) 67 .filter(matcher -> matcher.getMatcherType() == IotSceneRuleMatcher.MatcherType.CONDITION)
69 .toList(); 68 .toList();
70 69
71 // 构建触发器匹配器映射表 70 // 构建触发器匹配器映射表
72 - this.triggerMatcherMap = triggerMatchers.stream() 71 + // TODO @puhui999:convertMap()
  72 + this.triggerMatchers = triggerMatchers.stream()
73 .collect(Collectors.toMap( 73 .collect(Collectors.toMap(
74 IotSceneRuleMatcher::getSupportedTriggerType, 74 IotSceneRuleMatcher::getSupportedTriggerType,
75 Function.identity(), 75 Function.identity(),
@@ -81,9 +81,8 @@ public class IotSceneRuleMatcherManager { @@ -81,9 +81,8 @@ public class IotSceneRuleMatcherManager {
81 }, 81 },
82 LinkedHashMap::new 82 LinkedHashMap::new
83 )); 83 ));
84 -  
85 // 构建条件匹配器映射表 84 // 构建条件匹配器映射表
86 - this.conditionMatcherMap = conditionMatchers.stream() 85 + this.conditionMatchers = conditionMatchers.stream()
87 .collect(Collectors.toMap( 86 .collect(Collectors.toMap(
88 IotSceneRuleMatcher::getSupportedConditionType, 87 IotSceneRuleMatcher::getSupportedConditionType,
89 Function.identity(), 88 Function.identity(),
@@ -96,16 +95,13 @@ public class IotSceneRuleMatcherManager { @@ -96,16 +95,13 @@ public class IotSceneRuleMatcherManager {
96 LinkedHashMap::new 95 LinkedHashMap::new
97 )); 96 ));
98 97
  98 + // 日志输出初始化信息
99 log.info("[IotSceneRuleMatcherManager][初始化完成,共加载 {} 个匹配器,其中触发器匹配器 {} 个,条件匹配器 {} 个]", 99 log.info("[IotSceneRuleMatcherManager][初始化完成,共加载 {} 个匹配器,其中触发器匹配器 {} 个,条件匹配器 {} 个]",
100 - this.allMatchers.size(), this.triggerMatcherMap.size(), this.conditionMatcherMap.size());  
101 -  
102 - // 记录触发器匹配器详情  
103 - this.triggerMatcherMap.forEach((type, matcher) -> 100 + this.allMatchers.size(), this.triggerMatchers.size(), this.conditionMatchers.size());
  101 + this.triggerMatchers.forEach((type, matcher) ->
104 log.info("[IotSceneRuleMatcherManager][触发器匹配器] 类型: {}, 匹配器: {}, 优先级: {}", 102 log.info("[IotSceneRuleMatcherManager][触发器匹配器] 类型: {}, 匹配器: {}, 优先级: {}",
105 type, matcher.getMatcherName(), matcher.getPriority())); 103 type, matcher.getMatcherName(), matcher.getPriority()));
106 -  
107 - // 记录条件匹配器详情  
108 - this.conditionMatcherMap.forEach((type, matcher) -> 104 + this.conditionMatchers.forEach((type, matcher) ->
109 log.info("[IotSceneRuleMatcherManager][条件匹配器] 类型: {}, 匹配器: {}, 优先级: {}", 105 log.info("[IotSceneRuleMatcherManager][条件匹配器] 类型: {}, 匹配器: {}, 优先级: {}",
110 type, matcher.getMatcherName(), matcher.getPriority())); 106 type, matcher.getMatcherName(), matcher.getPriority()));
111 } 107 }
@@ -118,19 +114,17 @@ public class IotSceneRuleMatcherManager { @@ -118,19 +114,17 @@ public class IotSceneRuleMatcherManager {
118 * @return 是否匹配 114 * @return 是否匹配
119 */ 115 */
120 public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) { 116 public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) {
  117 + // TODO @puhui999:日志优化下;claude 打出来的日志风格,和项目有点不一样哈;
121 if (message == null || trigger == null || trigger.getType() == null) { 118 if (message == null || trigger == null || trigger.getType() == null) {
122 log.debug("[isMatched][参数无效] message: {}, trigger: {}", message, trigger); 119 log.debug("[isMatched][参数无效] message: {}, trigger: {}", message, trigger);
123 return false; 120 return false;
124 } 121 }
125 -  
126 - // 根据触发器类型查找对应的匹配器  
127 IotSceneRuleTriggerTypeEnum triggerType = findTriggerTypeEnum(trigger.getType()); 122 IotSceneRuleTriggerTypeEnum triggerType = findTriggerTypeEnum(trigger.getType());
128 if (triggerType == null) { 123 if (triggerType == null) {
129 log.warn("[isMatched][未知的触发器类型: {}]", trigger.getType()); 124 log.warn("[isMatched][未知的触发器类型: {}]", trigger.getType());
130 return false; 125 return false;
131 } 126 }
132 -  
133 - IotSceneRuleMatcher matcher = triggerMatcherMap.get(triggerType); 127 + IotSceneRuleMatcher matcher = triggerMatchers.get(triggerType);
134 if (matcher == null) { 128 if (matcher == null) {
135 log.warn("[isMatched][触发器类型({})没有对应的匹配器]", triggerType); 129 log.warn("[isMatched][触发器类型({})没有对应的匹配器]", triggerType);
136 return false; 130 return false;
@@ -165,7 +159,7 @@ public class IotSceneRuleMatcherManager { @@ -165,7 +159,7 @@ public class IotSceneRuleMatcherManager {
165 return false; 159 return false;
166 } 160 }
167 161
168 - IotSceneRuleMatcher matcher = conditionMatcherMap.get(conditionType); 162 + IotSceneRuleMatcher matcher = conditionMatchers.get(conditionType);
169 if (matcher == null) { 163 if (matcher == null) {
170 log.warn("[isConditionMatched][条件类型({})没有对应的匹配器]", conditionType); 164 log.warn("[isConditionMatched][条件类型({})没有对应的匹配器]", conditionType);
171 return false; 165 return false;
@@ -199,7 +193,7 @@ public class IotSceneRuleMatcherManager { @@ -199,7 +193,7 @@ public class IotSceneRuleMatcherManager {
199 * @return 支持的触发器类型列表 193 * @return 支持的触发器类型列表
200 */ 194 */
201 public Set<IotSceneRuleTriggerTypeEnum> getSupportedTriggerTypes() { 195 public Set<IotSceneRuleTriggerTypeEnum> getSupportedTriggerTypes() {
202 - return new HashSet<>(triggerMatcherMap.keySet()); 196 + return new HashSet<>(triggerMatchers.keySet());
203 } 197 }
204 198
205 /** 199 /**
@@ -208,9 +202,11 @@ public class IotSceneRuleMatcherManager { @@ -208,9 +202,11 @@ public class IotSceneRuleMatcherManager {
208 * @return 支持的条件类型列表 202 * @return 支持的条件类型列表
209 */ 203 */
210 public Set<IotSceneRuleConditionTypeEnum> getSupportedConditionTypes() { 204 public Set<IotSceneRuleConditionTypeEnum> getSupportedConditionTypes() {
211 - return new HashSet<>(conditionMatcherMap.keySet()); 205 + return new HashSet<>(conditionMatchers.keySet());
212 } 206 }
213 207
  208 + // TODO @puhui999:用不到的方法,可以去掉先哈;
  209 +
214 /** 210 /**
215 * 获取指定触发器类型的匹配器 211 * 获取指定触发器类型的匹配器
216 * 212 *
@@ -218,7 +214,7 @@ public class IotSceneRuleMatcherManager { @@ -218,7 +214,7 @@ public class IotSceneRuleMatcherManager {
218 * @return 匹配器实例,如果不存在则返回 null 214 * @return 匹配器实例,如果不存在则返回 null
219 */ 215 */
220 public IotSceneRuleMatcher getTriggerMatcher(IotSceneRuleTriggerTypeEnum triggerType) { 216 public IotSceneRuleMatcher getTriggerMatcher(IotSceneRuleTriggerTypeEnum triggerType) {
221 - return triggerMatcherMap.get(triggerType); 217 + return triggerMatchers.get(triggerType);
222 } 218 }
223 219
224 /** 220 /**
@@ -228,9 +224,10 @@ public class IotSceneRuleMatcherManager { @@ -228,9 +224,10 @@ public class IotSceneRuleMatcherManager {
228 * @return 匹配器实例,如果不存在则返回 null 224 * @return 匹配器实例,如果不存在则返回 null
229 */ 225 */
230 public IotSceneRuleMatcher getConditionMatcher(IotSceneRuleConditionTypeEnum conditionType) { 226 public IotSceneRuleMatcher getConditionMatcher(IotSceneRuleConditionTypeEnum conditionType) {
231 - return conditionMatcherMap.get(conditionType); 227 + return conditionMatchers.get(conditionType);
232 } 228 }
233 229
  230 + // TODO @puhui999:是不是不用这个哈;直接 @Getter,单测直接处理;
234 /** 231 /**
235 * 获取所有匹配器的统计信息 232 * 获取所有匹配器的统计信息
236 * 233 *
@@ -239,14 +236,14 @@ public class IotSceneRuleMatcherManager { @@ -239,14 +236,14 @@ public class IotSceneRuleMatcherManager {
239 public Map<String, Object> getMatcherStatistics() { 236 public Map<String, Object> getMatcherStatistics() {
240 Map<String, Object> statistics = new HashMap<>(); 237 Map<String, Object> statistics = new HashMap<>();
241 statistics.put("totalMatchers", allMatchers.size()); 238 statistics.put("totalMatchers", allMatchers.size());
242 - statistics.put("triggerMatchers", triggerMatcherMap.size());  
243 - statistics.put("conditionMatchers", conditionMatcherMap.size()); 239 + statistics.put("triggerMatchers", triggerMatchers.size());
  240 + statistics.put("conditionMatchers", conditionMatchers.size());
244 statistics.put("supportedTriggerTypes", getSupportedTriggerTypes()); 241 statistics.put("supportedTriggerTypes", getSupportedTriggerTypes());
245 statistics.put("supportedConditionTypes", getSupportedConditionTypes()); 242 statistics.put("supportedConditionTypes", getSupportedConditionTypes());
246 243
247 // 触发器匹配器详情 244 // 触发器匹配器详情
248 Map<String, Object> triggerMatcherDetails = new HashMap<>(); 245 Map<String, Object> triggerMatcherDetails = new HashMap<>();
249 - triggerMatcherMap.forEach((type, matcher) -> { 246 + triggerMatchers.forEach((type, matcher) -> {
250 Map<String, Object> detail = new HashMap<>(); 247 Map<String, Object> detail = new HashMap<>();
251 detail.put("matcherName", matcher.getMatcherName()); 248 detail.put("matcherName", matcher.getMatcherName());
252 detail.put("priority", matcher.getPriority()); 249 detail.put("priority", matcher.getPriority());
@@ -257,7 +254,7 @@ public class IotSceneRuleMatcherManager { @@ -257,7 +254,7 @@ public class IotSceneRuleMatcherManager {
257 254
258 // 条件匹配器详情 255 // 条件匹配器详情
259 Map<String, Object> conditionMatcherDetails = new HashMap<>(); 256 Map<String, Object> conditionMatcherDetails = new HashMap<>();
260 - conditionMatcherMap.forEach((type, matcher) -> { 257 + conditionMatchers.forEach((type, matcher) -> {
261 Map<String, Object> detail = new HashMap<>(); 258 Map<String, Object> detail = new HashMap<>();
262 detail.put("matcherName", matcher.getMatcherName()); 259 detail.put("matcherName", matcher.getMatcherName());
263 detail.put("priority", matcher.getPriority()); 260 detail.put("priority", matcher.getPriority());
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/TimerTriggerMatcher.java
@@ -61,6 +61,7 @@ public class TimerTriggerMatcher extends AbstractIotSceneRuleMatcher { @@ -61,6 +61,7 @@ public class TimerTriggerMatcher extends AbstractIotSceneRuleMatcher {
61 * @return 是否有效 61 * @return 是否有效
62 */ 62 */
63 private boolean isValidCronExpression(String cronExpression) { 63 private boolean isValidCronExpression(String cronExpression) {
  64 + // TODO @puhui999:CronExpression.isValidExpression(cronExpression);
64 try { 65 try {
65 // 简单的 CRON 表达式格式验证 66 // 简单的 CRON 表达式格式验证
66 // 标准 CRON 表达式应该有 6 或 7 个字段(秒 分 时 日 月 周 [年]) 67 // 标准 CRON 表达式应该有 6 或 7 个字段(秒 分 时 日 月 周 [年])
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleTriggerMatcherTest.java
@@ -20,6 +20,8 @@ import static org.junit.jupiter.api.Assertions.*; @@ -20,6 +20,8 @@ import static org.junit.jupiter.api.Assertions.*;
20 */ 20 */
21 public class IotSceneRuleTriggerMatcherTest extends BaseMockitoUnitTest { 21 public class IotSceneRuleTriggerMatcherTest extends BaseMockitoUnitTest {
22 22
  23 + // TODO @puhui999:public 都加下哈;
  24 +
23 private IotSceneRuleMatcherManager matcherManager; 25 private IotSceneRuleMatcherManager matcherManager;
24 26
25 @BeforeEach 27 @BeforeEach
@@ -42,13 +44,13 @@ public class IotSceneRuleTriggerMatcherTest extends BaseMockitoUnitTest { @@ -42,13 +44,13 @@ public class IotSceneRuleTriggerMatcherTest extends BaseMockitoUnitTest {
42 // 1. 准备测试数据 44 // 1. 准备测试数据
43 IotDeviceMessage message = IotDeviceMessage.builder() 45 IotDeviceMessage message = IotDeviceMessage.builder()
44 .requestId("test-001") 46 .requestId("test-001")
45 - .method("thing.state.update")  
46 - .data(1) // 在线状态 47 + .method("thing.state.update") // TODO @puhui999:这里的枚举;
  48 + .data(1) // 在线状态 TODO @puhui999:这里的枚举;
47 .build(); 49 .build();
48 50
49 IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger(); 51 IotSceneRuleDO.Trigger trigger = new IotSceneRuleDO.Trigger();
50 trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType()); 52 trigger.setType(IotSceneRuleTriggerTypeEnum.DEVICE_STATE_UPDATE.getType());
51 - trigger.setOperator("="); 53 + trigger.setOperator("="); // TODO @puhui999:这里的枚举;下面也是类似;
52 trigger.setValue("1"); 54 trigger.setValue("1");
53 55
54 // 2. 执行测试 56 // 2. 执行测试