diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java index 0de45e4a71..dc069b9559 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java @@ -20,8 +20,11 @@ public class IotDevicePropertyHistoryPageReqVO extends PageParam { @NotNull(message = "设备编号不能为空") private Long deviceId; - @Schema(description = "设备 Key", hidden = true) - private String deviceKey; // 非前端传递,后端自己查询设置 + @Schema(description = "产品 Key", hidden = true) + private String productKey; // 非前端传递,后端自己查询设置 + + @Schema(description = "设备名称", hidden = true) + private String deviceName; // 非前端传递,后端自己查询设置 @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "属性标识符不能为空") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java index 52c68c1ec0..f281c5878b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -9,15 +9,14 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; */ public interface RedisKeyConstants { - // TODO @芋艿:弱化 deviceKey;使用 product_key + device_name 替代 /** * 设备属性的数据缓存,采用 HASH 结构 *

- * KEY 格式:device_property:{deviceKey} + * KEY 格式:device_property:{productKey},${deviceName} * HASH KEY:identifier 属性标识 * VALUE 数据类型:String(JSON) {@link IotDevicePropertyDO} */ - String DEVICE_PROPERTY = "iot:device_property:%s"; + String DEVICE_PROPERTY = "iot:device_property:%s,%s"; /** * 设备的最后上报时间,采用 ZSET 结构 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java index 0f1196ab6b..f60ddc2d8b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java @@ -22,8 +22,8 @@ public class DevicePropertyRedisDAO { @Resource private StringRedisTemplate stringRedisTemplate; - public Map get(String deviceKey) { - String redisKey = formatKey(deviceKey); + public Map get(String productKey, String deviceName) { + String redisKey = formatKey(productKey, deviceName); Map entries = stringRedisTemplate.opsForHash().entries(redisKey); if (CollUtil.isEmpty(entries)) { return Collections.emptyMap(); @@ -33,18 +33,18 @@ public class DevicePropertyRedisDAO { entry -> JsonUtils.parseObject((String) entry.getValue(), IotDevicePropertyDO.class)); } - public void putAll(String deviceKey, Map properties) { + public void putAll(String productKey, String deviceName, Map properties) { if (CollUtil.isEmpty(properties)) { return; } - String redisKey = formatKey(deviceKey); + String redisKey = formatKey(productKey, deviceName); stringRedisTemplate.opsForHash().putAll(redisKey, convertMap(properties.entrySet(), Map.Entry::getKey, entry -> JsonUtils.toJsonString(entry.getValue()))); } - private static String formatKey(String deviceKey) { - return String.format(DEVICE_PROPERTY, deviceKey); + private static String formatKey(String productKey, String deviceName) { + return String.format(DEVICE_PROPERTY, productKey, deviceName); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java index 37a72e4b02..4045320289 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java @@ -33,7 +33,7 @@ public interface IotDevicePropertyMapper { List oldFields, List newFields) { oldFields.removeIf(field -> StrUtil.equalsAny(field.getField(), - TDengineTableField.FIELD_TS, "report_time", "device_key")); + TDengineTableField.FIELD_TS, "report_time", "device_name")); List addFields = newFields.stream().filter( // 新增的字段 newField -> oldFields.stream().noneMatch(oldField -> oldField.getField().equals(newField.getField()))) .collect(Collectors.toList()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java deleted file mode 100644 index 1a05233ee7..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.iot.mq.consumer.device; - -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; -import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Component; - -import jakarta.annotation.Resource; - -/** - * 针对 {@link IotDeviceMessage} 的消费者,记录设备属性 - * - * @author alwayssuper - */ -@Component -@Slf4j -public class IotDevicePropertyMessageConsumer { - - @Resource - private IotDevicePropertyService deviceDataService; - - @EventListener - @Async - public void onMessage(IotDeviceMessage message) { - if (ObjectUtil.notEqual(message.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType()) - || ObjectUtil.notEqual(message.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier())) { - return; - } - log.info("[onMessage][消息内容({})]", message); - - // 保存设备属性 - deviceDataService.saveDeviceProperty(message); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageSubscriber.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageSubscriber.java new file mode 100644 index 0000000000..527e48235e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageSubscriber.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.device; + +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; +import com.google.common.base.Objects; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 针对 {@link IotDeviceMessage} 的消费者:记录设备属性 + * + * @author alwayssuper + */ +@Component +@Slf4j +public class IotDevicePropertyMessageSubscriber implements IotMessageSubscriber { + + @Resource + private IotDevicePropertyService deviceDataService; + + @Resource + private IotMessageBus messageBus; + + @PostConstruct + public void init() { + messageBus.register(this); + } + + @Override + public String getTopic() { + return IotDeviceMessage.MESSAGE_BUS_DEVICE_MESSAGE_TOPIC; + } + + @Override + public String getGroup() { + return "iot_device_property_consumer"; + } + + @Override + public void onMessage(IotDeviceMessage message) { + if (Objects.equal(message.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType()) + && Objects.equal(message.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier())) { + // 保存设备属性 + deviceDataService.saveDeviceProperty(message); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java index e29730bcf0..d7deccef43 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java @@ -8,6 +8,7 @@ import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +// TODO @puhui999:后面重构哈 /** * 针对 {@link IotDeviceMessage} 的消费者,处理规则场景 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index e0d610f4d7..7f33e87a56 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -128,7 +128,8 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { return; } // 1. 获得设备信息 - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(message.getProductKey(), message.getDeviceName()); + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( + message.getProductKey(), message.getDeviceName()); if (device == null) { log.error("[saveDeviceProperty][消息({}) 对应的设备不存在]", message); return; @@ -155,9 +156,9 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { LocalDateTimeUtil.toEpochMilli(message.getReportTime())); // 3.2 保存设备属性【日志】 - // TODO @芋艿:这里要调整下; - deviceDataRedisDAO.putAll(device.getDeviceKey(), convertMap(properties.entrySet(), Map.Entry::getKey, - entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build())); + Map properties2 = convertMap(properties.entrySet(), Map.Entry::getKey, entry -> + IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build()); + deviceDataRedisDAO.putAll(device.getProductKey(), device.getDeviceName(), properties2); } @Override @@ -166,15 +167,16 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { IotDeviceDO device = deviceService.validateDeviceExists(deviceId); // 获得设备属性 - return deviceDataRedisDAO.get(device.getDeviceKey()); + return deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName()); } @Override public PageResult getHistoryDevicePropertyPage(IotDevicePropertyHistoryPageReqVO pageReqVO) { // 获取设备信息 IotDeviceDO device = deviceService.validateDeviceExists(pageReqVO.getDeviceId()); - pageReqVO.setDeviceKey(device.getDeviceKey()); + pageReqVO.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName()); + // 分页查询 try { IPage page = devicePropertyMapper.selectPageByHistory( new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml index bdc40e8330..6ff465162e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml @@ -20,7 +20,7 @@ ) TAGS ( - device_key NCHAR(50) + device_name NCHAR(50) ) @@ -46,9 +46,9 @@ - INSERT INTO device_property_${device.deviceKey} + INSERT INTO device_property_${device.productKey}_${device.deviceName} USING product_property_${device.productKey} - TAGS ('${device.deviceKey}') + TAGS ('${device.deviceName}') (ts, report_time, ${@cn.hutool.core.util.StrUtil@toUnderlineCase(key)} @@ -66,9 +66,10 @@ DESCRIBE product_property_${productKey} - SELECT ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} AS `value`, ts AS update_time - FROM device_property_${reqVO.deviceKey} + FROM device_property_${reqVO.productKey}_${reqVO.deviceName} WHERE ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} IS NOT NULL AND ts BETWEEN ${@cn.hutool.core.date.LocalDateTimeUtil@toEpochMilli(reqVO.times[0])} AND ${@cn.hutool.core.date.LocalDateTimeUtil@toEpochMilli(reqVO.times[1])}