Commit 067130ecde7211d2063ba0e2a83e03daf7ab9e5e

Authored by alwayssuper
1 parent de78cc92

新增:物模型日志建表

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 { @@ -35,4 +35,11 @@ public interface IotConstants {
35 */ 35 */
36 String DEVICE_STABLE_NAME_FORMAT = "device_%s"; 36 String DEVICE_STABLE_NAME_FORMAT = "device_%s";
37 37
  38 + /**
  39 + * 获取物模型消息记录设备名
  40 + * <p>
  41 + * 格式为 thing_model_message_{productKey}_{deviceName}
  42 + */
  43 + String THINK_MODEL_MESSAGE_TABLE_NAME_FORMAT = "thing_model_message_%s_%s";
  44 +
38 } 45 }
39 \ No newline at end of file 46 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java
1 package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; 1 package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType;
2 2
3 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; 3 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty;
  4 +import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 import lombok.Data; 5 import lombok.Data;
5 6
6 @Data 7 @Data
  8 +@JsonIgnoreProperties(ignoreUnknown = true)
7 public class ThinkModelArgument { 9 public class ThinkModelArgument {
8 10
9 public static final String DIRECTION_INPUT = "input"; 11 public static final String DIRECTION_INPUT = "input";
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Builder;
  5 +import lombok.Data;
  6 +import lombok.NoArgsConstructor;
  7 +import org.apache.xmlbeans.impl.xb.xsdschema.Public;
  8 +
  9 +
  10 +/**
  11 + * TD 物模型消息日志的数据库
  12 + */
  13 +@Data
  14 +@Builder
  15 +@NoArgsConstructor
  16 +@AllArgsConstructor
  17 +public class ThinkModelMessageDO {
  18 + /**
  19 + * 数据库名称
  20 + */
  21 + private String dataBaseName;
  22 +
  23 + // TODO @haohao:superTableName 和 tableName 是不是合并。因为每个 mapper 操作的时候,有且只会使用到其中一个。
  24 + /**
  25 + * 超级表名称
  26 + */
  27 + private String superTableName;
  28 +
  29 + /**
  30 + * 表名称
  31 + */
  32 + private String tableName;
  33 +
  34 + /**
  35 + * 消息ID
  36 + */
  37 + private String id;
  38 +
  39 + /**
  40 + * 扩展功能的参数
  41 + */
  42 + private Object sys;
  43 +
  44 + /**
  45 + * 请求方法 例如:thing.event.property.post
  46 + */
  47 + private String method;
  48 +
  49 + /**
  50 + * 请求参数
  51 + */
  52 + private Object params;
  53 +
  54 + /**
  55 + * 属性上报时间戳
  56 + */
  57 + private Long time;
  58 +
  59 +
  60 + /**
  61 + * 设备 key
  62 + */
  63 + private String deviceKey;
  64 +
  65 +
  66 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.tdengine;
  2 +
  3 +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
  4 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO;
  5 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessageDO;
  6 +import com.baomidou.dynamic.datasource.annotation.DS;
  7 +import org.apache.ibatis.annotations.Mapper;
  8 +
  9 +/**
  10 + * 处理 TD 中物模型消息日志的操作
  11 + */
  12 +@Mapper
  13 +@DS("tdengine")
  14 +public interface TdThinkModelMessageMapper {
  15 +
  16 + /**
  17 + * 创建物模型消息日志超级表超级表
  18 + *
  19 + */
  20 + @TenantIgnore
  21 + void createSuperTable(ThinkModelMessageDO superTable);
  22 +
  23 + /**
  24 + * 创建子表
  25 + *
  26 + */
  27 + @TenantIgnore
  28 + void createTableWithTag(ThinkModelMessageDO table);
  29 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.mq.producer.simulatesend;
  2 +
  3 +import jakarta.annotation.Resource;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.springframework.context.ApplicationContext;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +/**
  9 + * SimulateSend 模拟设备上报的 Producer
  10 + *
  11 + * @author alwayssuper
  12 + * @since 2024/12/17 16:35
  13 + */
  14 +@Slf4j
  15 +@Component
  16 +public class SimulateSendProducer {
  17 + @Resource
  18 + private ApplicationContext applicationContext;
  19 +
  20 +}
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 @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc
7 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
8 import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; 8 import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper;
9 import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; 9 import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
  10 +import cn.iocoder.yudao.module.iot.service.tdengine.IotThinkModelMessageService;
10 import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; 11 import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService;
11 import com.baomidou.dynamic.datasource.annotation.DSTransactional; 12 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
12 import jakarta.annotation.Resource; 13 import jakarta.annotation.Resource;
@@ -31,11 +32,12 @@ public class IotProductServiceImpl implements IotProductService { @@ -31,11 +32,12 @@ public class IotProductServiceImpl implements IotProductService {
31 32
32 @Resource 33 @Resource
33 private IotProductMapper productMapper; 34 private IotProductMapper productMapper;
34 -  
35 @Resource 35 @Resource
36 @Lazy 36 @Lazy
37 private IotProductThinkModelService thinkModelFunctionService; 37 private IotProductThinkModelService thinkModelFunctionService;
38 - 38 + @Resource
  39 + @Lazy
  40 + private IotThinkModelMessageService thinkModelMessageService;
39 @Override 41 @Override
40 public Long createProduct(IotProductSaveReqVO createReqVO) { 42 public Long createProduct(IotProductSaveReqVO createReqVO) {
41 // 1. 生成 ProductKey 43 // 1. 生成 ProductKey
@@ -114,8 +116,10 @@ public class IotProductServiceImpl implements IotProductService { @@ -114,8 +116,10 @@ public class IotProductServiceImpl implements IotProductService {
114 IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); 116 IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build();
115 // 3. 产品是发布状态 117 // 3. 产品是发布状态
116 if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { 118 if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) {
117 - // 3.1 创建超级表数据模型 119 + // 3.1 创建产品超级表数据模型
118 thinkModelFunctionService.createSuperTableDataModel(id); 120 thinkModelFunctionService.createSuperTableDataModel(id);
  121 + // 3.2 创建物模型日志超级表数据模型
  122 + thinkModelMessageService.createSuperTable(id);
119 } 123 }
120 productMapper.updateById(updateObj); 124 productMapper.updateById(updateObj);
121 } 125 }
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 { @@ -15,4 +15,12 @@ public interface IotThinkModelMessageService {
15 * @param thingModelMessage 物模型消息 15 * @param thingModelMessage 物模型消息
16 */ 16 */
17 void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage); 17 void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage);
  18 +
  19 + /**
  20 + * 创建物模型消息日志超级表
  21 + *
  22 + * @param productId 产品编号
  23 + */
  24 + void createSuperTable(Long productId);
  25 +
18 } 26 }
19 \ No newline at end of file 27 \ No newline at end of file
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; @@ -7,19 +7,20 @@ import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
7 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; 7 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO;
8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; 8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
9 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; 9 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO;
10 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser;  
11 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;  
12 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO;  
13 -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; 10 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  11 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*;
14 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; 12 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO;
15 import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; 13 import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO;
16 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; 14 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper;
17 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; 15 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper;
  16 +import cn.iocoder.yudao.module.iot.dal.tdengine.TdThinkModelMessageMapper;
18 import cn.iocoder.yudao.module.iot.enums.IotConstants; 17 import cn.iocoder.yudao.module.iot.enums.IotConstants;
19 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; 18 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
20 import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; 19 import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum;
21 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; 20 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.thinkmodel.IotProductThinkModelService; 22 import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService;
  23 +import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils;
23 import jakarta.annotation.Resource; 24 import jakarta.annotation.Resource;
24 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
25 import org.springframework.beans.factory.annotation.Value; 26 import org.springframework.beans.factory.annotation.Value;
@@ -54,19 +55,29 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ @@ -54,19 +55,29 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ
54 private TdEngineDDLMapper tdEngineDDLMapper; 55 private TdEngineDDLMapper tdEngineDDLMapper;
55 @Resource 56 @Resource
56 private TdEngineDMLMapper tdEngineDMLMapper; 57 private TdEngineDMLMapper tdEngineDMLMapper;
57 - 58 + @Resource
  59 + private IotProductService productService;
58 @Resource 60 @Resource
59 private DeviceDataRedisDAO deviceDataRedisDAO; 61 private DeviceDataRedisDAO deviceDataRedisDAO;
60 62
  63 + @Resource
  64 + private IotTdDatabaseUtils iotTdDatabaseUtils;
  65 +
  66 + @Resource
  67 + private TdThinkModelMessageMapper tdThinkModelMessageMapper;
  68 +
61 // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 69 // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感
62 @Override 70 @Override
63 @TenantIgnore 71 @TenantIgnore
64 public void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage) { 72 public void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage) {
65 // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态 73 // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态
66 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { 74 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) {
  75 + // 1.1 创建设备表
67 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); 76 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
68 iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() 77 iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO()
69 .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); 78 .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus()));
  79 + // 1.2 创建物模型日志设备表
  80 + createThinkModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
70 } 81 }
71 82
72 // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 83 // 2. 获取设备属性并进行物模型校验,过滤非物模型属性
@@ -90,6 +101,22 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ @@ -90,6 +101,22 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ
90 .build()); 101 .build());
91 } 102 }
92 103
  104 + @Override
  105 + @TenantIgnore
  106 + public void createSuperTable(Long productId) {
  107 + // 1. 查询产品
  108 + IotProductDO product = productService.getProduct(productId);
  109 +
  110 + // 2. 获取超级表的名称和数据库名称
  111 + String databaseName = iotTdDatabaseUtils.getDatabaseName();
  112 + String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(product.getProductKey());
  113 +
  114 + // 3. 创建超级表
  115 + tdThinkModelMessageMapper.createSuperTable(ThinkModelMessageDO.builder().build()
  116 + .setDataBaseName(databaseName)
  117 + .setSuperTableName(superTableName));
  118 + }
  119 +
93 private List<IotProductThinkModelDO> getValidFunctionList(String productKey) { 120 private List<IotProductThinkModelDO> getValidFunctionList(String productKey) {
94 return iotProductThinkModelService 121 return iotProductThinkModelService
95 .getProductThinkModelListByProductKey(productKey) 122 .getProductThinkModelListByProductKey(productKey)
@@ -189,6 +216,30 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ @@ -189,6 +216,30 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ
189 } 216 }
190 217
191 /** 218 /**
  219 + * 创建物模型日志设备数据表
  220 + *
  221 + * @param productKey 产品 Key
  222 + * @param deviceName 设备名称
  223 + * @param deviceKey 设备 Key
  224 + *
  225 + */
  226 + private void createThinkModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){
  227 +
  228 + // 1. 获取超级表的名称、数据库名称、设备日志表名称
  229 + String databaseName = iotTdDatabaseUtils.getDatabaseName();
  230 + String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(productKey);
  231 + String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThinkModelMessageDeviceTableName(productKey, deviceName);
  232 +
  233 + // 2. 创建物模型日志设备数据表
  234 + tdThinkModelMessageMapper.createTableWithTag(ThinkModelMessageDO.builder().build()
  235 + .setDataBaseName(databaseName)
  236 + .setSuperTableName(superTableName)
  237 + .setTableName(thinkModelMessageDeviceTableName)
  238 + .setDeviceKey(deviceKey));
  239 +
  240 + }
  241 +
  242 + /**
192 * 获取数据库名称 243 * 获取数据库名称
193 * 244 *
194 * @return 数据库名称 245 * @return 数据库名称
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.util;
  2 +
  3 +import cn.iocoder.yudao.module.iot.enums.IotConstants;
  4 +import org.springframework.beans.factory.annotation.Value;
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +/**
  8 + * TD数据库工具类
  9 + *
  10 + * @author AlwaysSuper
  11 + */
  12 +@Component
  13 +public class IotTdDatabaseUtils {
  14 +
  15 + @Value("${spring.datasource.dynamic.datasource.tdengine.url}")
  16 + private String url;
  17 +
  18 + /**
  19 + * 获取数据库名称
  20 + */
  21 + public String getDatabaseName() {
  22 + int index = url.lastIndexOf("/");
  23 + return index != -1 ? url.substring(index + 1) : url;
  24 + }
  25 +
  26 + /**
  27 + * 获取产品超级表表名
  28 + *
  29 + * @param deviceType 设备类型
  30 + * @param productKey 产品 Key
  31 + * @return 产品超级表表名
  32 + */
  33 + public static String getProductSuperTableName(Integer deviceType, String productKey) {
  34 + return switch (deviceType) {
  35 + case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase();
  36 + case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase();
  37 + default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase();
  38 + };
  39 + }
  40 +
  41 + /**
  42 + * 获取物模型日志超级表表名
  43 + *
  44 + * @param productKey 产品 Key
  45 + * @return 物模型日志超级表表名
  46 + *
  47 + */
  48 + public static String getThinkModelMessageSuperTableName(String productKey) {
  49 + return String.format("thing_model_message_", productKey).toLowerCase();
  50 + }
  51 +
  52 + /**
  53 + * 获取物模型日志设备表名
  54 + *
  55 + * @param productKey 产品 Key
  56 + * @param deviceName 设备名称
  57 + * @return 物模型日志设备表名
  58 + */
  59 + public static String getThinkModelMessageDeviceTableName(String productKey, String deviceName) {
  60 + return String.format(IotConstants.THINK_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase());
  61 + }
  62 +
  63 +}
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper
  3 + PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4 + "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5 +<mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.TdThinkModelMessageMapper">
  6 +
  7 +
  8 + <!-- 创建物模型消息日志超级表 -->
  9 + <update id="createSuperTable">
  10 + CREATE STABLE ${dataBaseName}.${superTableName}(
  11 + ts TIMESTAMP,
  12 + id VARCHAR(255),
  13 + sys VARCHAR(2048),
  14 + method VARCHAR(255),
  15 + params VARCHAR(2048)
  16 + )TAGS (
  17 + deviceKey VARCHAR(255)
  18 + )
  19 + </update>
  20 +
  21 + <!-- 创建物模型消息日志子表,带有deviceKey的TAG -->
  22 + <update id="createTableWithTag">
  23 + CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName}
  24 + USING ${dataBaseName}.${superTableName}(
  25 + ts,
  26 + id ,
  27 + sys ,
  28 + method ,
  29 + params
  30 + )TAGS(
  31 + #{deviceKey}
  32 + )
  33 + </update>
  34 +</mapper>
0 \ No newline at end of file 35 \ No newline at end of file