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

This commit is contained in:
puhui999
2025-09-19 14:37:25 +08:00
parent 057f924bd1
commit 997bfe8fa1
3 changed files with 24 additions and 11 deletions

View File

@ -76,4 +76,12 @@ public interface RedisKeyConstants {
*/ */
String DATA_SINK = "iot:data_sink"; String DATA_SINK = "iot:data_sink";
/**
* 场景联动规则的数据缓存,使用 Spring Cache 操作
* <p>
* KEY 格式scene_rule_list_${productId}_${deviceId}
* VALUE 数据类型String 数组(JSON),即 {@link cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO} 列表
*/
String SCENE_RULE_LIST = "iot:scene_rule_list";
} }

View File

@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper;
import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.product.IotProductService;
@ -24,6 +25,8 @@ import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatche
import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotSceneRuleTimerHandler; import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotSceneRuleTimerHandler;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -60,6 +63,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
private IotSceneRuleTimerHandler timerHandler; private IotSceneRuleTimerHandler timerHandler;
@Override @Override
@CacheEvict(value = RedisKeyConstants.SCENE_RULE_LIST, allEntries = true)
public Long createSceneRule(IotSceneRuleSaveReqVO createReqVO) { public Long createSceneRule(IotSceneRuleSaveReqVO createReqVO) {
IotSceneRuleDO sceneRule = BeanUtils.toBean(createReqVO, IotSceneRuleDO.class); IotSceneRuleDO sceneRule = BeanUtils.toBean(createReqVO, IotSceneRuleDO.class);
sceneRuleMapper.insert(sceneRule); sceneRuleMapper.insert(sceneRule);
@ -71,6 +75,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
} }
@Override @Override
@CacheEvict(value = RedisKeyConstants.SCENE_RULE_LIST, allEntries = true)
public void updateSceneRule(IotSceneRuleSaveReqVO updateReqVO) { public void updateSceneRule(IotSceneRuleSaveReqVO updateReqVO) {
// 校验存在 // 校验存在
validateSceneRuleExists(updateReqVO.getId()); validateSceneRuleExists(updateReqVO.getId());
@ -83,6 +88,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
} }
@Override @Override
@CacheEvict(value = RedisKeyConstants.SCENE_RULE_LIST, allEntries = true)
public void updateSceneRuleStatus(Long id, Integer status) { public void updateSceneRuleStatus(Long id, Integer status) {
// 1. 校验存在 // 1. 校验存在
validateSceneRuleExists(id); validateSceneRuleExists(id);
@ -105,6 +111,7 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
} }
@Override @Override
@CacheEvict(value = RedisKeyConstants.SCENE_RULE_LIST, allEntries = true)
public void deleteSceneRule(Long id) { public void deleteSceneRule(Long id) {
// 1. 校验存在 // 1. 校验存在
validateSceneRuleExists(id); validateSceneRuleExists(id);
@ -149,15 +156,12 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
return sceneRuleMapper.selectListByStatus(status); return sceneRuleMapper.selectListByStatus(status);
} }
// TODO @puhui999缓存待实现
@Override @Override
@Cacheable(value = RedisKeyConstants.SCENE_RULE_LIST, key = "#productId + '_' + #deviceId ")
@TenantIgnore // 忽略租户隔离:因为 IotSceneRuleMessageHandler 调用时,一般未传递租户,所以需要忽略 @TenantIgnore // 忽略租户隔离:因为 IotSceneRuleMessageHandler 调用时,一般未传递租户,所以需要忽略
public List<IotSceneRuleDO> getSceneRuleListByProductIdAndDeviceIdFromCache(Long productId, Long deviceId) { public List<IotSceneRuleDO> getSceneRuleListByProductIdAndDeviceIdFromCache(Long productId, Long deviceId) {
// 1. 查询启用状态的规则场景 // 1. 查询启用状态的规则场景
// TODO @puhui999这里查询 enable 的; List<IotSceneRuleDO> enabledList = sceneRuleMapper.selectList(IotSceneRuleDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
List<IotSceneRuleDO> list = sceneRuleMapper.selectList();
List<IotSceneRuleDO> enabledList = filterList(list,
sceneRule -> CommonStatusEnum.isEnable(sceneRule.getStatus()));
// 2. 根据 productKey 和 deviceName 进行匹配 // 2. 根据 productKey 和 deviceName 进行匹配
return filterList(enabledList, sceneRule -> { return filterList(enabledList, sceneRule -> {
@ -190,9 +194,10 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
@Override @Override
public void executeSceneRuleByDevice(IotDeviceMessage message) { public void executeSceneRuleByDevice(IotDeviceMessage message) {
// TODO @puhui999这里的 tenantId通过设备获取 // 1.1 这里的 tenantId通过设备获取
TenantUtils.execute(message.getTenantId(), () -> { IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId());
// 1. 获得设备匹配的规则场景 TenantUtils.execute(device.getTenantId(), () -> {
// 1.2 获得设备匹配的规则场景
List<IotSceneRuleDO> sceneRules = getMatchedSceneRuleListByMessage(message); List<IotSceneRuleDO> sceneRules = getMatchedSceneRuleListByMessage(message);
if (CollUtil.isEmpty(sceneRules)) { if (CollUtil.isEmpty(sceneRules)) {
return; return;
@ -238,14 +243,14 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService {
// 1. 匹配设备 // 1. 匹配设备
// TODO 缓存 @puhui999可能需要 getSelf() // TODO 缓存 @puhui999可能需要 getSelf()
// 1.1 通过 deviceId 获取设备信息 // 1.1 通过 deviceId 获取设备信息
IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); IotDeviceDO device = getSelf().deviceService.getDeviceFromCache(message.getDeviceId());
if (device == null) { if (device == null) {
log.warn("[getMatchedSceneRuleListByMessage][设备({}) 不存在]", message.getDeviceId()); log.warn("[getMatchedSceneRuleListByMessage][设备({}) 不存在]", message.getDeviceId());
return List.of(); return List.of();
} }
// 1.2 通过 productId 获取产品信息 // 1.2 通过 productId 获取产品信息
IotProductDO product = productService.getProductFromCache(device.getProductId()); IotProductDO product = getSelf().productService.getProductFromCache(device.getProductId());
if (product == null) { if (product == null) {
log.warn("[getMatchedSceneRuleListByMessage][产品({}) 不存在]", device.getProductId()); log.warn("[getMatchedSceneRuleListByMessage][产品({}) 不存在]", device.getProductId());
return List.of(); return List.of();

View File

@ -44,7 +44,7 @@ public class IotDeviceServiceInvokeTriggerMatcher implements IotSceneRuleTrigger
// 2. 对于服务调用触发器,通常只需要匹配服务标识符即可 // 2. 对于服务调用触发器,通常只需要匹配服务标识符即可
// 不需要检查操作符和值,因为服务调用本身就是触发条件 // 不需要检查操作符和值,因为服务调用本身就是触发条件
// TODO @puhui999: 服务调用时校验输入参数是否匹配条件 // TODO @puhui999: 服务调用时校验输入参数是否匹配条件
IotSceneRuleMatcherHelper.logTriggerMatchSuccess(message, trigger); IotSceneRuleMatcherHelper.logTriggerMatchSuccess(message, trigger);
return true; return true;
} }