From 067130ecde7211d2063ba0e2a83e03daf7ab9e5e Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Thu, 19 Dec 2024 16:43:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E7=89=A9=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=97=A5=E5=BF=97=E5=BB=BA=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/enums/IotConstants.java | 7 ++ .../model/dataType/ThinkModelArgument.java | 2 + .../tdengine/ThinkModelMessageDO.java | 66 +++++++++++++++++++ .../tdengine/TdThinkModelMessageMapper.java | 29 ++++++++ .../simulatesend/SimulateSendProducer.java | 20 ++++++ .../product/IotProductServiceImpl.java | 10 ++- .../tdengine/IotThinkModelMessageService.java | 8 +++ .../IotThinkModelMessageServiceImpl.java | 61 +++++++++++++++-- .../module/iot/util/IotTdDatabaseUtils.java | 63 ++++++++++++++++++ .../tdengine/TdThinkModelMessageMapper.xml | 34 ++++++++++ 10 files changed, 292 insertions(+), 8 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java index 5927f44b96..0762ade9de 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java @@ -35,4 +35,11 @@ public interface IotConstants { */ String DEVICE_STABLE_NAME_FORMAT = "device_%s"; + /** + * 获取物模型消息记录设备名 + *

+ * 格式为 thing_model_message_{productKey}_{deviceName} + */ + String THINK_MODEL_MESSAGE_TABLE_NAME_FORMAT = "thing_model_message_%s_%s"; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java index 7b293ca79e..2ed260fdec 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @Data +@JsonIgnoreProperties(ignoreUnknown = true) public class ThinkModelArgument { public static final String DIRECTION_INPUT = "input"; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java new file mode 100644 index 0000000000..13309c81ed --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.xmlbeans.impl.xb.xsdschema.Public; + + +/** + * TD 物模型消息日志的数据库 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ThinkModelMessageDO { + /** + * 数据库名称 + */ + private String dataBaseName; + + // TODO @haohao:superTableName 和 tableName 是不是合并。因为每个 mapper 操作的时候,有且只会使用到其中一个。 + /** + * 超级表名称 + */ + private String superTableName; + + /** + * 表名称 + */ + private String tableName; + + /** + * 消息ID + */ + private String id; + + /** + * 扩展功能的参数 + */ + private Object sys; + + /** + * 请求方法 例如:thing.event.property.post + */ + private String method; + + /** + * 请求参数 + */ + private Object params; + + /** + * 属性上报时间戳 + */ + private Long time; + + + /** + * 设备 key + */ + private String deviceKey; + + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java new file mode 100644 index 0000000000..4eb59975d8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessageDO; +import com.baomidou.dynamic.datasource.annotation.DS; +import org.apache.ibatis.annotations.Mapper; + +/** + * 处理 TD 中物模型消息日志的操作 + */ +@Mapper +@DS("tdengine") +public interface TdThinkModelMessageMapper { + + /** + * 创建物模型消息日志超级表超级表 + * + */ + @TenantIgnore + void createSuperTable(ThinkModelMessageDO superTable); + + /** + * 创建子表 + * + */ + @TenantIgnore + void createTableWithTag(ThinkModelMessageDO table); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java new file mode 100644 index 0000000000..76cde71be7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.mq.producer.simulatesend; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * SimulateSend 模拟设备上报的 Producer + * + * @author alwayssuper + * @since 2024/12/17 16:35 + */ +@Slf4j +@Component +public class SimulateSendProducer { + @Resource + private ApplicationContext applicationContext; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index b26c2c123b..f26c964522 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; +import cn.iocoder.yudao.module.iot.service.tdengine.IotThinkModelMessageService; import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; @@ -31,11 +32,12 @@ public class IotProductServiceImpl implements IotProductService { @Resource private IotProductMapper productMapper; - @Resource @Lazy private IotProductThinkModelService thinkModelFunctionService; - + @Resource + @Lazy + private IotThinkModelMessageService thinkModelMessageService; @Override public Long createProduct(IotProductSaveReqVO createReqVO) { // 1. 生成 ProductKey @@ -114,8 +116,10 @@ public class IotProductServiceImpl implements IotProductService { IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); // 3. 产品是发布状态 if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { - // 3.1 创建超级表数据模型 + // 3.1 创建产品超级表数据模型 thinkModelFunctionService.createSuperTableDataModel(id); + // 3.2 创建物模型日志超级表数据模型 + thinkModelMessageService.createSuperTable(id); } productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java index 67ee2b99ae..67df7045fb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java @@ -15,4 +15,12 @@ public interface IotThinkModelMessageService { * @param thingModelMessage 物模型消息 */ void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage); + + /** + * 创建物模型消息日志超级表 + * + * @param productId 产品编号 + */ + void createSuperTable(Long productId); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java index 3c2debfa49..3c6059f992 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java @@ -7,19 +7,20 @@ import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdThinkModelMessageMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; 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.thinkmodel.IotProductThinkModelService; +import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -54,19 +55,29 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ private TdEngineDDLMapper tdEngineDDLMapper; @Resource private TdEngineDMLMapper tdEngineDMLMapper; - + @Resource + private IotProductService productService; @Resource private DeviceDataRedisDAO deviceDataRedisDAO; + @Resource + private IotTdDatabaseUtils iotTdDatabaseUtils; + + @Resource + private TdThinkModelMessageMapper tdThinkModelMessageMapper; + // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 @Override @TenantIgnore public void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage) { // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { + // 1.1 创建设备表 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); + // 1.2 创建物模型日志设备表 + createThinkModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); } // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 @@ -90,6 +101,22 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ .build()); } + @Override + @TenantIgnore + public void createSuperTable(Long productId) { + // 1. 查询产品 + IotProductDO product = productService.getProduct(productId); + + // 2. 获取超级表的名称和数据库名称 + String databaseName = iotTdDatabaseUtils.getDatabaseName(); + String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(product.getProductKey()); + + // 3. 创建超级表 + tdThinkModelMessageMapper.createSuperTable(ThinkModelMessageDO.builder().build() + .setDataBaseName(databaseName) + .setSuperTableName(superTableName)); + } + private List getValidFunctionList(String productKey) { return iotProductThinkModelService .getProductThinkModelListByProductKey(productKey) @@ -188,6 +215,30 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ .setTags(tagsFieldValues)); } + /** + * 创建物模型日志设备数据表 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @param deviceKey 设备 Key + * + */ + private void createThinkModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){ + + // 1. 获取超级表的名称、数据库名称、设备日志表名称 + String databaseName = iotTdDatabaseUtils.getDatabaseName(); + String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(productKey); + String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThinkModelMessageDeviceTableName(productKey, deviceName); + + // 2. 创建物模型日志设备数据表 + tdThinkModelMessageMapper.createTableWithTag(ThinkModelMessageDO.builder().build() + .setDataBaseName(databaseName) + .setSuperTableName(superTableName) + .setTableName(thinkModelMessageDeviceTableName) + .setDeviceKey(deviceKey)); + + } + /** * 获取数据库名称 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java new file mode 100644 index 0000000000..b928ec7169 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.iot.util; + +import cn.iocoder.yudao.module.iot.enums.IotConstants; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * TD数据库工具类 + * + * @author AlwaysSuper + */ +@Component +public class IotTdDatabaseUtils { + + @Value("${spring.datasource.dynamic.datasource.tdengine.url}") + private String url; + + /** + * 获取数据库名称 + */ + public String getDatabaseName() { + int index = url.lastIndexOf("/"); + return index != -1 ? url.substring(index + 1) : url; + } + + /** + * 获取产品超级表表名 + * + * @param deviceType 设备类型 + * @param productKey 产品 Key + * @return 产品超级表表名 + */ + public static String getProductSuperTableName(Integer deviceType, String productKey) { + return switch (deviceType) { + case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); + case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); + default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); + }; + } + + /** + * 获取物模型日志超级表表名 + * + * @param productKey 产品 Key + * @return 物模型日志超级表表名 + * + */ + public static String getThinkModelMessageSuperTableName(String productKey) { + return String.format("thing_model_message_", productKey).toLowerCase(); + } + + /** + * 获取物模型日志设备表名 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 物模型日志设备表名 + */ + public static String getThinkModelMessageDeviceTableName(String productKey, String deviceName) { + return String.format(IotConstants.THINK_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml new file mode 100644 index 0000000000..476ca97abc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + CREATE STABLE ${dataBaseName}.${superTableName}( + ts TIMESTAMP, + id VARCHAR(255), + sys VARCHAR(2048), + method VARCHAR(255), + params VARCHAR(2048) + )TAGS ( + deviceKey VARCHAR(255) + ) + + + + + CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} + USING ${dataBaseName}.${superTableName}( + ts, + id , + sys , + method , + params + )TAGS( + #{deviceKey} + ) + + \ No newline at end of file