Commit 997bfe8fa116c0f2bb0c4149d08d95bd37e52ab6

Authored by puhui999
1 parent 057f924b

feat: 【IoT 物联网】场景联动规则的数据缓存,使用 Spring Cache 操作

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java
@@ -76,4 +76,12 @@ public interface RedisKeyConstants { @@ -76,4 +76,12 @@ public interface RedisKeyConstants {
76 */ 76 */
77 String DATA_SINK = "iot:data_sink"; 77 String DATA_SINK = "iot:data_sink";
78 78
  79 + /**
  80 + * 场景联动规则的数据缓存,使用 Spring Cache 操作
  81 + * <p>
  82 + * KEY 格式:scene_rule_list_${productId}_${deviceId}
  83 + * VALUE 数据类型:String 数组(JSON),即 {@link cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO} 列表
  84 + */
  85 + String SCENE_RULE_LIST = "iot:scene_rule_list";
  86 +
79 } 87 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java
@@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
16 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; 16 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
17 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; 17 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
18 import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper; 18 import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper;
  19 +import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
19 import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; 20 import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
20 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; 21 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
21 import cn.iocoder.yudao.module.iot.service.product.IotProductService; 22 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
@@ -24,6 +25,8 @@ import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatche @@ -24,6 +25,8 @@ import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatche
24 import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotSceneRuleTimerHandler; 25 import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotSceneRuleTimerHandler;
25 import jakarta.annotation.Resource; 26 import jakarta.annotation.Resource;
26 import lombok.extern.slf4j.Slf4j; 27 import lombok.extern.slf4j.Slf4j;
  28 +import org.springframework.cache.annotation.CacheEvict;
  29 +import org.springframework.cache.annotation.Cacheable;
27 import org.springframework.stereotype.Service; 30 import org.springframework.stereotype.Service;
28 import org.springframework.validation.annotation.Validated; 31 import org.springframework.validation.annotation.Validated;
29 32
@@ -60,6 +63,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -60,6 +63,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
60 private IotSceneRuleTimerHandler timerHandler; 63 private IotSceneRuleTimerHandler timerHandler;
61 64
62 @Override 65 @Override
  66 + @CacheEvict(value = RedisKeyConstants.SCENE_RULE_LIST, allEntries = true)
63 public Long createSceneRule(IotSceneRuleSaveReqVO createReqVO) { 67 public Long createSceneRule(IotSceneRuleSaveReqVO createReqVO) {
64 IotSceneRuleDO sceneRule = BeanUtils.toBean(createReqVO, IotSceneRuleDO.class); 68 IotSceneRuleDO sceneRule = BeanUtils.toBean(createReqVO, IotSceneRuleDO.class);
65 sceneRuleMapper.insert(sceneRule); 69 sceneRuleMapper.insert(sceneRule);
@@ -71,6 +75,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -71,6 +75,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
71 } 75 }
72 76
73 @Override 77 @Override
  78 + @CacheEvict(value = RedisKeyConstants.SCENE_RULE_LIST, allEntries = true)
74 public void updateSceneRule(IotSceneRuleSaveReqVO updateReqVO) { 79 public void updateSceneRule(IotSceneRuleSaveReqVO updateReqVO) {
75 // 校验存在 80 // 校验存在
76 validateSceneRuleExists(updateReqVO.getId()); 81 validateSceneRuleExists(updateReqVO.getId());
@@ -83,6 +88,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -83,6 +88,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
83 } 88 }
84 89
85 @Override 90 @Override
  91 + @CacheEvict(value = RedisKeyConstants.SCENE_RULE_LIST, allEntries = true)
86 public void updateSceneRuleStatus(Long id, Integer status) { 92 public void updateSceneRuleStatus(Long id, Integer status) {
87 // 1. 校验存在 93 // 1. 校验存在
88 validateSceneRuleExists(id); 94 validateSceneRuleExists(id);
@@ -105,6 +111,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -105,6 +111,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
105 } 111 }
106 112
107 @Override 113 @Override
  114 + @CacheEvict(value = RedisKeyConstants.SCENE_RULE_LIST, allEntries = true)
108 public void deleteSceneRule(Long id) { 115 public void deleteSceneRule(Long id) {
109 // 1. 校验存在 116 // 1. 校验存在
110 validateSceneRuleExists(id); 117 validateSceneRuleExists(id);
@@ -149,15 +156,12 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -149,15 +156,12 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
149 return sceneRuleMapper.selectListByStatus(status); 156 return sceneRuleMapper.selectListByStatus(status);
150 } 157 }
151 158
152 - // TODO @puhui999:缓存待实现  
153 @Override 159 @Override
  160 + @Cacheable(value = RedisKeyConstants.SCENE_RULE_LIST, key = "#productId + '_' + #deviceId ")
154 @TenantIgnore // 忽略租户隔离:因为 IotSceneRuleMessageHandler 调用时,一般未传递租户,所以需要忽略 161 @TenantIgnore // 忽略租户隔离:因为 IotSceneRuleMessageHandler 调用时,一般未传递租户,所以需要忽略
155 public List<IotSceneRuleDO> getSceneRuleListByProductIdAndDeviceIdFromCache(Long productId, Long deviceId) { 162 public List<IotSceneRuleDO> getSceneRuleListByProductIdAndDeviceIdFromCache(Long productId, Long deviceId) {
156 // 1. 查询启用状态的规则场景 163 // 1. 查询启用状态的规则场景
157 - // TODO @puhui999:这里查询 enable 的;  
158 - List<IotSceneRuleDO> list = sceneRuleMapper.selectList();  
159 - List<IotSceneRuleDO> enabledList = filterList(list,  
160 - sceneRule -> CommonStatusEnum.isEnable(sceneRule.getStatus())); 164 + List<IotSceneRuleDO> enabledList = sceneRuleMapper.selectList(IotSceneRuleDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
161 165
162 // 2. 根据 productKey 和 deviceName 进行匹配 166 // 2. 根据 productKey 和 deviceName 进行匹配
163 return filterList(enabledList, sceneRule -> { 167 return filterList(enabledList, sceneRule -> {
@@ -190,9 +194,10 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -190,9 +194,10 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
190 194
191 @Override 195 @Override
192 public void executeSceneRuleByDevice(IotDeviceMessage message) { 196 public void executeSceneRuleByDevice(IotDeviceMessage message) {
193 - // TODO @puhui999:这里的 tenantId,通过设备获取;  
194 - TenantUtils.execute(message.getTenantId(), () -> {  
195 - // 1. 获得设备匹配的规则场景 197 + // 1.1 这里的 tenantId,通过设备获取;
  198 + IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId());
  199 + TenantUtils.execute(device.getTenantId(), () -> {
  200 + // 1.2 获得设备匹配的规则场景
196 List<IotSceneRuleDO> sceneRules = getMatchedSceneRuleListByMessage(message); 201 List<IotSceneRuleDO> sceneRules = getMatchedSceneRuleListByMessage(message);
197 if (CollUtil.isEmpty(sceneRules)) { 202 if (CollUtil.isEmpty(sceneRules)) {
198 return; 203 return;
@@ -238,14 +243,14 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @@ -238,14 +243,14 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
238 // 1. 匹配设备 243 // 1. 匹配设备
239 // TODO 缓存 @puhui999:可能需要 getSelf() 244 // TODO 缓存 @puhui999:可能需要 getSelf()
240 // 1.1 通过 deviceId 获取设备信息 245 // 1.1 通过 deviceId 获取设备信息
241 - IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); 246 + IotDeviceDO device = getSelf().deviceService.getDeviceFromCache(message.getDeviceId());
242 if (device == null) { 247 if (device == null) {
243 log.warn("[getMatchedSceneRuleListByMessage][设备({}) 不存在]", message.getDeviceId()); 248 log.warn("[getMatchedSceneRuleListByMessage][设备({}) 不存在]", message.getDeviceId());
244 return List.of(); 249 return List.of();
245 } 250 }
246 251
247 // 1.2 通过 productId 获取产品信息 252 // 1.2 通过 productId 获取产品信息
248 - IotProductDO product = productService.getProductFromCache(device.getProductId()); 253 + IotProductDO product = getSelf().productService.getProductFromCache(device.getProductId());
249 if (product == null) { 254 if (product == null) {
250 log.warn("[getMatchedSceneRuleListByMessage][产品({}) 不存在]", device.getProductId()); 255 log.warn("[getMatchedSceneRuleListByMessage][产品({}) 不存在]", device.getProductId());
251 return List.of(); 256 return List.of();
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java
@@ -44,7 +44,7 @@ public class IotDeviceServiceInvokeTriggerMatcher implements IotSceneRuleTrigger @@ -44,7 +44,7 @@ public class IotDeviceServiceInvokeTriggerMatcher implements IotSceneRuleTrigger
44 44
45 // 2. 对于服务调用触发器,通常只需要匹配服务标识符即可 45 // 2. 对于服务调用触发器,通常只需要匹配服务标识符即可
46 // 不需要检查操作符和值,因为服务调用本身就是触发条件 46 // 不需要检查操作符和值,因为服务调用本身就是触发条件
47 - // TODO @puhui999: 服务调用时校验输入参数是否匹配条件 47 + // TODO @puhui999: 服务调用时校验输入参数是否匹配条件?
48 IotSceneRuleMatcherHelper.logTriggerMatchSuccess(message, trigger); 48 IotSceneRuleMatcherHelper.logTriggerMatchSuccess(message, trigger);
49 return true; 49 return true;
50 } 50 }