Commit a4be3bb84d0a24169f085a643edbd24eedb35aa5
1 parent
06749a18
【代码新增】IoT:增加 IotRuleSceneMessageHandler 处理规则场景,尝试基于 Spring El 表达式实现初步计算(部分场景) trigger 条件匹配
Showing
7 changed files
with
372 additions
and
4 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.enums.rule; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.ArrayUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.core.ArrayValuable; | ||
| 5 | +import lombok.Getter; | ||
| 6 | +import lombok.RequiredArgsConstructor; | ||
| 7 | + | ||
| 8 | +import java.util.Arrays; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Iot 场景触发条件参数的操作符枚举 | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@RequiredArgsConstructor | ||
| 16 | +@Getter | ||
| 17 | +public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayValuable<String> { | ||
| 18 | + | ||
| 19 | + EQUALS("=", "%s == %s"), | ||
| 20 | + NOT_EQUALS("!=", "%s != %s"), | ||
| 21 | + | ||
| 22 | + GREATER_THAN(">", "%s > %s"), | ||
| 23 | + GREATER_THAN_OR_EQUALS(">=", "%s >= %s"), | ||
| 24 | + | ||
| 25 | + LESS_THAN("<", "%s < %s"), | ||
| 26 | + LESS_THAN_OR_EQUALS("<=", "%s <= %s"), | ||
| 27 | + | ||
| 28 | + IN("in", "%s in { %s }"), | ||
| 29 | + NOT_IN("not in", "%s not in { %s }"), | ||
| 30 | + | ||
| 31 | + BETWEEN("between", "(%s >= %s) && (%s <= %s)"), | ||
| 32 | + NOT_BETWEEN("not between", "!(%s between %s and %s)"), | ||
| 33 | + | ||
| 34 | + LIKE("like", "%s like %s"), // 字符串匹配 | ||
| 35 | + NOT_NULL("not null", ""); // 非空 | ||
| 36 | + | ||
| 37 | + private final String operator; | ||
| 38 | + private final String springExpression; | ||
| 39 | + | ||
| 40 | + public static final String[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerConditionParameterOperatorEnum::getOperator).toArray(String[]::new); | ||
| 41 | + | ||
| 42 | + public static IotRuleSceneTriggerConditionParameterOperatorEnum operatorOf(String operator) { | ||
| 43 | + return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values()); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + @Override | ||
| 47 | + public String[] array() { | ||
| 48 | + return ARRAYS; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.enums.rule; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.core.ArrayValuable; | ||
| 4 | +import lombok.Getter; | ||
| 5 | +import lombok.RequiredArgsConstructor; | ||
| 6 | + | ||
| 7 | +import java.util.Arrays; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * Iot 场景流转的触发类型枚举 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@RequiredArgsConstructor | ||
| 15 | +@Getter | ||
| 16 | +public enum IotRuleSceneTriggerTypeEnum implements ArrayValuable<Integer> { | ||
| 17 | + | ||
| 18 | + DEVICE(1), // 设备触发 | ||
| 19 | + TIMER(2); // 定时触发 | ||
| 20 | + | ||
| 21 | + private final Integer type; | ||
| 22 | + | ||
| 23 | + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerTypeEnum::getType).toArray(Integer[]::new); | ||
| 24 | + | ||
| 25 | + @Override | ||
| 26 | + public Integer[] array() { | ||
| 27 | + return ARRAYS; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java
| @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | ||
| 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; |
| 7 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | 7 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; |
| 8 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | 8 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; |
| 9 | +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; | ||
| 9 | import com.baomidou.mybatisplus.annotation.KeySequence; | 10 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 10 | import com.baomidou.mybatisplus.annotation.TableField; | 11 | import com.baomidou.mybatisplus.annotation.TableField; |
| 11 | import com.baomidou.mybatisplus.annotation.TableId; | 12 | import com.baomidou.mybatisplus.annotation.TableId; |
| @@ -17,7 +18,7 @@ import java.util.List; | @@ -17,7 +18,7 @@ import java.util.List; | ||
| 17 | import java.util.Map; | 18 | import java.util.Map; |
| 18 | 19 | ||
| 19 | /** | 20 | /** |
| 20 | - * IoT 场景联动 DO | 21 | + * IoT 规则场景(场景联动) DO |
| 21 | * | 22 | * |
| 22 | * @author 芋道源码 | 23 | * @author 芋道源码 |
| 23 | */ | 24 | */ |
| @@ -72,7 +73,7 @@ public class IotRuleSceneDO extends BaseDO { | @@ -72,7 +73,7 @@ public class IotRuleSceneDO extends BaseDO { | ||
| 72 | /** | 73 | /** |
| 73 | * 触发类型 | 74 | * 触发类型 |
| 74 | * | 75 | * |
| 75 | - * TODO @芋艿:device、job | 76 | + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum} |
| 76 | */ | 77 | */ |
| 77 | private Integer type; | 78 | private Integer type; |
| 78 | 79 | ||
| @@ -147,12 +148,15 @@ public class IotRuleSceneDO extends BaseDO { | @@ -147,12 +148,15 @@ public class IotRuleSceneDO extends BaseDO { | ||
| 147 | /** | 148 | /** |
| 148 | * 操作符 | 149 | * 操作符 |
| 149 | * | 150 | * |
| 150 | - * TODO 芋艿:枚举 | 151 | + * 枚举 {@link IotRuleSceneTriggerConditionParameterOperatorEnum} |
| 151 | */ | 152 | */ |
| 152 | private String operator; | 153 | private String operator; |
| 153 | 154 | ||
| 154 | /** | 155 | /** |
| 155 | - * 值 | 156 | + * 比较值 |
| 157 | + * | ||
| 158 | + * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 | ||
| 159 | + * 例如说,{@link IotRuleSceneTriggerConditionParameterOperatorEnum#IN}、{@link IotRuleSceneTriggerConditionParameterOperatorEnum#BETWEEN} | ||
| 156 | */ | 160 | */ |
| 157 | private String value; | 161 | private String value; |
| 158 | 162 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.mysql.rule; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 4 | +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; | ||
| 5 | +import org.apache.ibatis.annotations.Mapper; | ||
| 6 | + | ||
| 7 | +@Mapper | ||
| 8 | +public interface IotRuleSceneMapper extends BaseMapperX<IotRuleSceneDO> { | ||
| 9 | + | ||
| 10 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mq.consumer.rule; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | ||
| 4 | +import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService; | ||
| 5 | +import jakarta.annotation.Resource; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.springframework.context.event.EventListener; | ||
| 8 | +import org.springframework.scheduling.annotation.Async; | ||
| 9 | +import org.springframework.stereotype.Component; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 针对 {@link IotDeviceMessage} 的消费者,处理规则场景 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +@Component | ||
| 17 | +@Slf4j | ||
| 18 | +public class IotRuleSceneMessageHandler { | ||
| 19 | + | ||
| 20 | + @Resource | ||
| 21 | + private IotRuleSceneService ruleSceneService; | ||
| 22 | + | ||
| 23 | + @EventListener | ||
| 24 | + @Async | ||
| 25 | + public void onMessage(IotDeviceMessage message) { | ||
| 26 | + log.info("[onMessage][消息内容({})]", message); | ||
| 27 | + ruleSceneService.executeRuleScene(message); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.rule; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; | ||
| 4 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | ||
| 5 | + | ||
| 6 | +import java.util.List; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * IoT 规则场景 Service 接口 | ||
| 10 | + * | ||
| 11 | + * @author 芋道源码 | ||
| 12 | + */ | ||
| 13 | +public interface IotRuleSceneService { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 【缓存】获得指定设备的场景列表 | ||
| 17 | + * | ||
| 18 | + * @param productKey 产品 Key | ||
| 19 | + * @param deviceName 设备名称 | ||
| 20 | + * @return 场景列表 | ||
| 21 | + */ | ||
| 22 | + List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName); | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 执行规则场景 | ||
| 26 | + * | ||
| 27 | + * @param message 消息 | ||
| 28 | + */ | ||
| 29 | + void executeRuleScene(IotDeviceMessage message); | ||
| 30 | + | ||
| 31 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.rule; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.collection.ListUtil; | ||
| 5 | +import cn.hutool.core.text.CharPool; | ||
| 6 | +import cn.hutool.core.util.ObjUtil; | ||
| 7 | +import cn.hutool.core.util.StrUtil; | ||
| 8 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | ||
| 9 | +import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; | ||
| 10 | +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | ||
| 11 | +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; | ||
| 12 | +import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper; | ||
| 13 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | ||
| 14 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 15 | +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; | ||
| 16 | +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; | ||
| 17 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | ||
| 18 | +import jakarta.annotation.Resource; | ||
| 19 | +import lombok.extern.slf4j.Slf4j; | ||
| 20 | +import org.springframework.stereotype.Service; | ||
| 21 | +import org.springframework.validation.annotation.Validated; | ||
| 22 | + | ||
| 23 | +import java.util.List; | ||
| 24 | +import java.util.Map; | ||
| 25 | + | ||
| 26 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | ||
| 27 | + | ||
| 28 | +/** | ||
| 29 | + * IoT 规则场景 Service 实现类 | ||
| 30 | + * | ||
| 31 | + * @author 芋道源码 | ||
| 32 | + */ | ||
| 33 | +@Service | ||
| 34 | +@Validated | ||
| 35 | +@Slf4j | ||
| 36 | +public class IotRuleSceneServiceImpl implements IotRuleSceneService { | ||
| 37 | + | ||
| 38 | + @Resource | ||
| 39 | + private IotRuleSceneMapper ruleSceneMapper; | ||
| 40 | + | ||
| 41 | + // TODO 芋艿,缓存待实现 | ||
| 42 | + @Override | ||
| 43 | + @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 | ||
| 44 | + public List<IotRuleSceneDO> getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { | ||
| 45 | + if (true) { | ||
| 46 | + IotRuleSceneDO ruleScene01 = new IotRuleSceneDO(); | ||
| 47 | + ruleScene01.setTriggers(CollUtil.newArrayList()); | ||
| 48 | + IotRuleSceneDO.Trigger trigger01 = new IotRuleSceneDO.Trigger(); | ||
| 49 | + trigger01.setType(IotRuleSceneTriggerTypeEnum.DEVICE.getType()); | ||
| 50 | + trigger01.setConditions(CollUtil.newArrayList()); | ||
| 51 | + IotRuleSceneDO.TriggerCondition condition01 = new IotRuleSceneDO.TriggerCondition(); | ||
| 52 | + condition01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); | ||
| 53 | + condition01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier()); | ||
| 54 | + condition01.setParameters(CollUtil.newArrayList()); | ||
| 55 | + IotRuleSceneDO.TriggerConditionParameter parameter011 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 56 | + parameter011.setIdentifier("width"); | ||
| 57 | + parameter011.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator()); | ||
| 58 | + parameter011.setValue("1"); | ||
| 59 | + condition01.getParameters().add(parameter011); | ||
| 60 | + IotRuleSceneDO.TriggerConditionParameter parameter012 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 61 | + parameter012.setIdentifier("width"); | ||
| 62 | + parameter012.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS.getOperator()); | ||
| 63 | + parameter012.setValue("2"); | ||
| 64 | + condition01.getParameters().add(parameter012); | ||
| 65 | + IotRuleSceneDO.TriggerConditionParameter parameter013 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 66 | + parameter013.setIdentifier("width"); | ||
| 67 | + parameter013.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN.getOperator()); | ||
| 68 | + parameter013.setValue("0"); | ||
| 69 | + condition01.getParameters().add(parameter013); | ||
| 70 | + IotRuleSceneDO.TriggerConditionParameter parameter014 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 71 | + parameter014.setIdentifier("width"); | ||
| 72 | + parameter014.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator()); | ||
| 73 | + parameter014.setValue("0"); | ||
| 74 | + condition01.getParameters().add(parameter014); | ||
| 75 | + IotRuleSceneDO.TriggerConditionParameter parameter015 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 76 | + parameter015.setIdentifier("width"); | ||
| 77 | + parameter015.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN.getOperator()); | ||
| 78 | + parameter015.setValue("2"); | ||
| 79 | + condition01.getParameters().add(parameter015); | ||
| 80 | + IotRuleSceneDO.TriggerConditionParameter parameter016 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 81 | + parameter016.setIdentifier("width"); | ||
| 82 | + parameter016.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS.getOperator()); | ||
| 83 | + parameter016.setValue("2"); | ||
| 84 | + condition01.getParameters().add(parameter016); | ||
| 85 | + IotRuleSceneDO.TriggerConditionParameter parameter017 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 86 | + parameter017.setIdentifier("width"); | ||
| 87 | + parameter017.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.IN.getOperator()); | ||
| 88 | + parameter017.setValue("1,2,3"); | ||
| 89 | + condition01.getParameters().add(parameter017); | ||
| 90 | + IotRuleSceneDO.TriggerConditionParameter parameter018 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 91 | + parameter018.setIdentifier("width"); | ||
| 92 | + parameter018.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_IN.getOperator()); | ||
| 93 | + parameter018.setValue("0,2,3"); | ||
| 94 | + condition01.getParameters().add(parameter018); | ||
| 95 | + IotRuleSceneDO.TriggerConditionParameter parameter019 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 96 | + parameter019.setIdentifier("width"); | ||
| 97 | + parameter019.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN.getOperator()); | ||
| 98 | + parameter019.setValue("1,3"); | ||
| 99 | + condition01.getParameters().add(parameter019); | ||
| 100 | + IotRuleSceneDO.TriggerConditionParameter parameter020 = new IotRuleSceneDO.TriggerConditionParameter(); | ||
| 101 | + parameter020.setIdentifier("width"); | ||
| 102 | + parameter020.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN.getOperator()); | ||
| 103 | + parameter020.setValue("2,3"); | ||
| 104 | + condition01.getParameters().add(parameter020); | ||
| 105 | + trigger01.getConditions().add(condition01); | ||
| 106 | + ruleScene01.getTriggers().add(trigger01); | ||
| 107 | + | ||
| 108 | + return ListUtil.toList(ruleScene01); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + List<IotRuleSceneDO> list = ruleSceneMapper.selectList(); | ||
| 112 | + // TODO @芋艿:需要考虑开启状态 | ||
| 113 | + return filterList(list, ruleScene -> { | ||
| 114 | + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { | ||
| 115 | + if (ObjUtil.notEqual(trigger.getProductKey(), productKey)) { | ||
| 116 | + continue; | ||
| 117 | + } | ||
| 118 | + if (CollUtil.isEmpty(trigger.getDeviceNames()) // 无设备名称限制 | ||
| 119 | + || trigger.getDeviceNames().contains(deviceName)) { // 包含设备名称 | ||
| 120 | + return true; | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + return false; | ||
| 124 | + }); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + @Override | ||
| 128 | + public void executeRuleScene(IotDeviceMessage message) { | ||
| 129 | + // 1. 获得设备匹配的规则场景 | ||
| 130 | + List<IotRuleSceneDO> ruleScenes = getMatchedRuleSceneList(message); | ||
| 131 | + if (CollUtil.isEmpty(ruleScenes)) { | ||
| 132 | + return; | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + /** | ||
| 137 | + * 获得匹配的规则场景列表 | ||
| 138 | + * | ||
| 139 | + * @param message 设备消息 | ||
| 140 | + * @return 规则场景列表 | ||
| 141 | + */ | ||
| 142 | + @SuppressWarnings("unchecked") | ||
| 143 | + private List<IotRuleSceneDO> getMatchedRuleSceneList(IotDeviceMessage message) { | ||
| 144 | + // 1. 匹配设备 | ||
| 145 | + // TODO @芋艿:可能需要 getSelf(); 缓存 | ||
| 146 | + List<IotRuleSceneDO> ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache( | ||
| 147 | + message.getProductKey(), message.getDeviceName()); | ||
| 148 | + if (CollUtil.isEmpty(ruleScenes)) { | ||
| 149 | + return ruleScenes; | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + // 2. 匹配 trigger 触发器的条件 | ||
| 153 | + return filterList(ruleScenes, ruleScene -> { | ||
| 154 | + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { | ||
| 155 | + // 非设备触发,不匹配 | ||
| 156 | + if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) { | ||
| 157 | + return false; | ||
| 158 | + } | ||
| 159 | + // TODO 芋艿:产品、设备的匹配,要不要这里在做一次???貌似和 1. 部分重复了 | ||
| 160 | + // 条件为空,说明没有匹配的条件,因此不匹配 | ||
| 161 | + if (CollUtil.isEmpty(trigger.getConditions())) { | ||
| 162 | + return false; | ||
| 163 | + } | ||
| 164 | + IotRuleSceneDO.TriggerCondition found = CollUtil.findOne(trigger.getConditions(), condition -> { | ||
| 165 | + if (ObjUtil.notEqual(message.getType(), condition.getType()) | ||
| 166 | + || ObjUtil.notEqual(message.getIdentifier(), condition.getIdentifier())) { | ||
| 167 | + return false; | ||
| 168 | + } | ||
| 169 | + // TODO @芋艿:设备上线,需要测试下。 | ||
| 170 | + for (IotRuleSceneDO.TriggerConditionParameter parameter : condition.getParameters()) { | ||
| 171 | + // 计算是否匹配 | ||
| 172 | + IotRuleSceneTriggerConditionParameterOperatorEnum operator = | ||
| 173 | + IotRuleSceneTriggerConditionParameterOperatorEnum.operatorOf(parameter.getOperator()); | ||
| 174 | + if (operator == null) { | ||
| 175 | + log.error("[getMatchedRuleSceneList][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", | ||
| 176 | + ruleScene.getId(), trigger, parameter.getOperator()); | ||
| 177 | + return false; | ||
| 178 | + } | ||
| 179 | + Object messageValue = ((Map<String, Object>) message.getData()).get(parameter.getIdentifier()); | ||
| 180 | + if (messageValue == null) { | ||
| 181 | + return false; | ||
| 182 | + } | ||
| 183 | + String springExpression; | ||
| 184 | + if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN, | ||
| 185 | + IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN)) { | ||
| 186 | + String[] parameterValues = StrUtil.splitToArray(parameter.getValue(), CharPool.COMMA); | ||
| 187 | + springExpression = String.format(operator.getSpringExpression(), messageValue, parameterValues[0], | ||
| 188 | + messageValue, parameterValues[1]); | ||
| 189 | + } else { | ||
| 190 | + springExpression = String.format(operator.getSpringExpression(), messageValue, parameter.getValue()); | ||
| 191 | + } | ||
| 192 | + // TODO @芋艿:【需优化】需要考虑 struct、时间等参数的比较 | ||
| 193 | + try { | ||
| 194 | + System.out.println(SpringExpressionUtils.parseExpression(springExpression)); | ||
| 195 | + } catch (Exception e) { | ||
| 196 | + log.error("[getMatchedRuleSceneList][消息({}) 规则场景编号({}) 的触发器({}) 的匹配表达式({}) 计算异常]", | ||
| 197 | + message, ruleScene.getId(), trigger, springExpression, e); | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + return true; | ||
| 201 | + }); | ||
| 202 | + if (found == null) { | ||
| 203 | + return false; | ||
| 204 | + } | ||
| 205 | + log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger); | ||
| 206 | + return true; | ||
| 207 | + } | ||
| 208 | + return false; | ||
| 209 | + }); | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | +} |