【功能优化】IoT:device 和 thingmodel 读取增加缓存
This commit is contained in:
parent
7745035fa4
commit
a364153d4a
|
@ -49,6 +49,10 @@ public interface IotThingModelMapper extends BaseMapperX<IotThingModelDO> {
|
|||
return selectList(IotThingModelDO::getProductId, productId);
|
||||
}
|
||||
|
||||
default List<IotThingModelDO> selectListByProductKey(String productKey) {
|
||||
return selectList(IotThingModelDO::getProductKey, productKey);
|
||||
}
|
||||
|
||||
default List<IotThingModelDO> selectListByProductIdAndType(Long productId, Integer type) {
|
||||
return selectList(IotThingModelDO::getProductId, productId,
|
||||
IotThingModelDO::getType, type);
|
||||
|
@ -68,8 +72,4 @@ public interface IotThingModelMapper extends BaseMapperX<IotThingModelDO> {
|
|||
IotThingModelDO::getName, name);
|
||||
}
|
||||
|
||||
default List<IotThingModelDO> selectListByProductKey(String productKey) {
|
||||
return selectList(IotThingModelDO::getProductKey, productKey);
|
||||
}
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
|
|||
public interface RedisKeyConstants {
|
||||
|
||||
/**
|
||||
* 设备属性数据缓存,采用 HASH 结构
|
||||
* 设备属性的数据缓存,采用 HASH 结构
|
||||
* <p>
|
||||
* KEY 格式:device_property:{deviceKey}
|
||||
* HASH KEY:identifier 属性标识
|
||||
|
@ -26,4 +26,20 @@ public interface RedisKeyConstants {
|
|||
*/
|
||||
String DEVICE_REPORT_TIME = "device_report_time";
|
||||
|
||||
/**
|
||||
* 设备信息的数据缓存,使用 Spring Cache 操作
|
||||
*
|
||||
* KEY 格式:device_${productKey}_${deviceKey}
|
||||
* VALUE 数据类型:String(JSON)
|
||||
*/
|
||||
String DEVICE = "device";
|
||||
|
||||
/**
|
||||
* 物模型的数据缓存,使用 Spring Cache 操作
|
||||
*
|
||||
* KEY 格式:thing_model_${productKey}
|
||||
* VALUE 数据类型:String 数组(JSON),即 {@link cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO} 列表
|
||||
*/
|
||||
String THING_MODEL_LIST = "thing_model_list";
|
||||
|
||||
}
|
||||
|
|
|
@ -113,15 +113,16 @@ public interface IotDeviceService {
|
|||
*/
|
||||
Long getDeviceCountByGroupId(Long groupId);
|
||||
|
||||
// TODO @芋艿:增加缓存
|
||||
/**
|
||||
* 根据产品 key 和设备名称,获得设备信息
|
||||
* 【缓存】根据产品 key 和设备名称,获得设备信息
|
||||
*
|
||||
* 注意:该方法会忽略租户信息,所以调用时,需要确认会不会有跨租户访问的风险!!!
|
||||
*
|
||||
* @param productKey 产品 key
|
||||
* @param deviceName 设备名称
|
||||
* @return 设备信息
|
||||
*/
|
||||
IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName);
|
||||
IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache(String productKey, String deviceName);
|
||||
|
||||
/**
|
||||
* 导入设备
|
||||
|
|
|
@ -4,22 +4,27 @@ import cn.hutool.core.collection.CollUtil;
|
|||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
|
||||
import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
|
||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
@ -78,6 +83,7 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds());
|
||||
|
||||
// 2.1 转换 VO 为 DO
|
||||
// TODO @芋艿:state 相关的参数。另外,到底叫 state,还是 status 好!
|
||||
IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class, o -> {
|
||||
o.setProductKey(product.getProductKey()).setDeviceType(product.getDeviceType());
|
||||
// 生成并设置必要的字段
|
||||
|
@ -109,6 +115,9 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
// 2. 更新到数据库
|
||||
IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
|
||||
deviceMapper.updateById(updateObj);
|
||||
|
||||
// 3. 清空对应缓存
|
||||
deleteDeviceCache(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -125,6 +134,9 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
// 3. 更新设备分组
|
||||
deviceMapper.updateBatch(convertList(devices, device -> new IotDeviceDO()
|
||||
.setId(device.getId()).setGroupIds(updateReqVO.getGroupIds())));
|
||||
|
||||
// 4. 清空对应缓存
|
||||
deleteDeviceCache(devices);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -138,6 +150,9 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
|
||||
// 2. 删除设备
|
||||
deviceMapper.deleteById(id);
|
||||
|
||||
// 3. 清空对应缓存
|
||||
deleteDeviceCache(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -160,6 +175,9 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
|
||||
// 2. 删除设备
|
||||
deviceMapper.deleteByIds(ids);
|
||||
|
||||
// 3. 清空对应缓存
|
||||
deleteDeviceCache(devices);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,6 +231,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
|
||||
@Override
|
||||
public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) {
|
||||
// TODO @芋艿:state 相关的参数。另外,到底叫 state,还是 status 好!
|
||||
// TODO @芋艿:各种时间,需要 check 下,优化处理下!
|
||||
// 1. 校验存在
|
||||
IotDeviceDO device = validateDeviceExists(updateReqVO.getId());
|
||||
|
||||
|
@ -233,6 +253,9 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
}
|
||||
// 2.3 更新到数据库
|
||||
deviceMapper.updateById(updateDevice);
|
||||
|
||||
// 3. 清空对应缓存
|
||||
deleteDeviceCache(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -246,7 +269,9 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName) {
|
||||
@TenantIgnore
|
||||
@Cacheable(value = RedisKeyConstants.DEVICE, key = "#productKey + '_' + #deviceName", unless = "#result == null")
|
||||
public IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) {
|
||||
return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName);
|
||||
}
|
||||
|
||||
|
@ -367,4 +392,20 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
return respVO;
|
||||
}
|
||||
|
||||
private void deleteDeviceCache(IotDeviceDO device) {
|
||||
// 保证在 @CacheEvict 之前,忽略租户
|
||||
TenantUtils.executeIgnore(() -> getSelf().deleteDeviceCache0(device));
|
||||
}
|
||||
|
||||
private void deleteDeviceCache(List<IotDeviceDO> devices) {
|
||||
devices.forEach(this::deleteDeviceCache);
|
||||
}
|
||||
|
||||
@CacheEvict(value = RedisKeyConstants.DEVICE, key = "#device.productKey + '_' + #device.deviceName")
|
||||
public void deleteDeviceCache0(IotDeviceDO device) {}
|
||||
|
||||
private IotDeviceServiceImpl getSelf() {
|
||||
return SpringUtil.getBean(getClass());
|
||||
}
|
||||
|
||||
}
|
|
@ -118,21 +118,21 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
|
|||
}
|
||||
|
||||
@Override
|
||||
@TenantIgnore // TODO @芋艿:租户的缓存问题,需要考虑下。因为会存在一会又 tenantId,一会没有!
|
||||
@TenantIgnore
|
||||
public void saveDeviceProperty(IotDeviceMessage message) {
|
||||
if (!(message.getData() instanceof Map)) {
|
||||
log.error("[saveDeviceProperty][消息内容({}) 的 data 类型不正确]", message);
|
||||
return;
|
||||
}
|
||||
// 1. 获得设备信息
|
||||
IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(message.getProductKey(), message.getDeviceName());
|
||||
IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(message.getProductKey(), message.getDeviceName());
|
||||
if (device == null) {
|
||||
log.error("[saveDeviceProperty][消息({}) 对应的设备不存在]", message);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 根据物模型,拼接合法的属性
|
||||
List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductId(device.getProductId());
|
||||
List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductKeyFromCache(device.getProductKey());
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
((Map<?, ?>) message.getData()).forEach((key, value) -> {
|
||||
if (CollUtil.findOne(thingModels, thingModel -> thingModel.getIdentifier().equals(key)) == null) {
|
||||
|
|
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.service.device.upstream;
|
|||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
|
||||
|
@ -47,7 +46,8 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
|
|||
public void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) {
|
||||
// 1.1 获得设备
|
||||
log.info("[reportDevicePropertyData][上报设备属性数据: {}]", reportReqDTO);
|
||||
IotDeviceDO device = getDevice(reportReqDTO);
|
||||
IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(
|
||||
reportReqDTO.getProductKey(), reportReqDTO.getDeviceName());
|
||||
if (device == null) {
|
||||
log.error("[reportDevicePropertyData][设备({}/{})不存在]",
|
||||
reportReqDTO.getProductKey(), reportReqDTO.getDeviceName());
|
||||
|
@ -71,11 +71,6 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
|
|||
// TODO 芋艿:待实现
|
||||
}
|
||||
|
||||
private IotDeviceDO getDevice(IotDeviceUpstreamAbstractReqDTO reqDTO) {
|
||||
return TenantUtils.executeIgnore(() -> // 需要忽略租户,因为请求时,未带租户编号
|
||||
deviceService.getDeviceByProductKeyAndDeviceName(reqDTO.getProductKey(), reqDTO.getDeviceName()));
|
||||
}
|
||||
|
||||
private void updateDeviceLastTime(IotDeviceDO deviceDO, IotDeviceUpstreamAbstractReqDTO reqDTO) {
|
||||
// TODO 芋艿:插件状态
|
||||
// TODO 芋艿:操作时间
|
||||
|
|
|
@ -46,7 +46,6 @@ public interface IotThingModelService {
|
|||
*/
|
||||
IotThingModelDO getThingModel(Long id);
|
||||
|
||||
// TODO @芋艿:增加缓存
|
||||
/**
|
||||
* 获得产品物模型列表
|
||||
*
|
||||
|
@ -55,6 +54,16 @@ public interface IotThingModelService {
|
|||
*/
|
||||
List<IotThingModelDO> getThingModelListByProductId(Long productId);
|
||||
|
||||
/**
|
||||
* 【缓存】获得产品物模型列表
|
||||
*
|
||||
* 注意:该方法会忽略租户信息,所以调用时,需要确认会不会有跨租户访问的风险!!!
|
||||
*
|
||||
* @param productKey 产品标识
|
||||
* @return 产品物模型列表
|
||||
*/
|
||||
List<IotThingModelDO> getThingModelListByProductKeyFromCache(String productKey);
|
||||
|
||||
/**
|
||||
* 获得产品物模型分页
|
||||
*
|
||||
|
@ -63,14 +72,6 @@ public interface IotThingModelService {
|
|||
*/
|
||||
PageResult<IotThingModelDO> getProductThingModelPage(IotThingModelPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得产品物模型列表
|
||||
*
|
||||
* @param productKey 产品 Key
|
||||
* @return 产品物模型列表
|
||||
*/
|
||||
List<IotThingModelDO> getProductThingModelListByProductKey(String productKey);
|
||||
|
||||
/**
|
||||
* 获得产品物模型列表
|
||||
*
|
||||
|
|
|
@ -2,8 +2,11 @@ package cn.iocoder.yudao.module.iot.service.thingmodel;
|
|||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelParam;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService;
|
||||
|
@ -14,11 +17,14 @@ import cn.iocoder.yudao.module.iot.convert.thingmodel.IotThingModelConvert;
|
|||
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotThingModelMapper;
|
||||
import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
|
||||
import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
|
||||
import cn.iocoder.yudao.module.iot.enums.thingmodel.*;
|
||||
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
|
||||
import jakarta.annotation.Resource;
|
||||
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.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
@ -69,6 +75,9 @@ public class IotThingModelServiceImpl implements IotThingModelService {
|
|||
createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
|
||||
}
|
||||
// TODO @puhui999: 服务和事件的情况 method 怎么设置?在前端设置还是后端设置?
|
||||
|
||||
// 7. 删除缓存
|
||||
deleteThingModelListCache(createReqVO.getProductKey());
|
||||
return thingModel.getId();
|
||||
}
|
||||
|
||||
|
@ -92,6 +101,9 @@ public class IotThingModelServiceImpl implements IotThingModelService {
|
|||
if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
|
||||
createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey());
|
||||
}
|
||||
|
||||
// 6. 删除缓存
|
||||
deleteThingModelListCache(updateReqVO.getProductKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -113,6 +125,9 @@ public class IotThingModelServiceImpl implements IotThingModelService {
|
|||
if (Objects.equals(thingModel.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
|
||||
createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey());
|
||||
}
|
||||
|
||||
// 4. 删除缓存
|
||||
deleteThingModelListCache(thingModel.getProductKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -126,13 +141,15 @@ public class IotThingModelServiceImpl implements IotThingModelService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PageResult<IotThingModelDO> getProductThingModelPage(IotThingModelPageReqVO pageReqVO) {
|
||||
return thingModelMapper.selectPage(pageReqVO);
|
||||
@TenantIgnore
|
||||
@Cacheable(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey")
|
||||
public List<IotThingModelDO> getThingModelListByProductKeyFromCache(String productKey) {
|
||||
return thingModelMapper.selectListByProductKey(productKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IotThingModelDO> getProductThingModelListByProductKey(String productKey) {
|
||||
return thingModelMapper.selectListByProductKey(productKey);
|
||||
public PageResult<IotThingModelDO> getProductThingModelPage(IotThingModelPageReqVO pageReqVO) {
|
||||
return thingModelMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -333,4 +350,16 @@ public class IotThingModelServiceImpl implements IotThingModelService {
|
|||
.setDirection(direction.getDirection()));
|
||||
}
|
||||
|
||||
private void deleteThingModelListCache(String productKey) {
|
||||
// 保证在 @CacheEvict 之前,忽略租户
|
||||
TenantUtils.executeIgnore(() -> getSelf().deleteThingModelListCache0(productKey));
|
||||
}
|
||||
|
||||
@CacheEvict(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey")
|
||||
public void deleteThingModelListCache0(String productKey) {}
|
||||
|
||||
private IotThingModelServiceImpl getSelf() {
|
||||
return SpringUtil.getBean(getClass());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue