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 35 */
36 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 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 1 package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType;
2 2  
3 3 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty;
  4 +import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 5 import lombok.Data;
5 6  
6 7 @Data
  8 +@JsonIgnoreProperties(ignoreUnknown = true)
7 9 public class ThinkModelArgument {
8 10  
9 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 7 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
8 8 import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper;
9 9 import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
  10 +import cn.iocoder.yudao.module.iot.service.tdengine.IotThinkModelMessageService;
10 11 import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService;
11 12 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
12 13 import jakarta.annotation.Resource;
... ... @@ -31,11 +32,12 @@ public class IotProductServiceImpl implements IotProductService {
31 32  
32 33 @Resource
33 34 private IotProductMapper productMapper;
34   -
35 35 @Resource
36 36 @Lazy
37 37 private IotProductThinkModelService thinkModelFunctionService;
38   -
  38 + @Resource
  39 + @Lazy
  40 + private IotThinkModelMessageService thinkModelMessageService;
39 41 @Override
40 42 public Long createProduct(IotProductSaveReqVO createReqVO) {
41 43 // 1. 生成 ProductKey
... ... @@ -114,8 +116,10 @@ public class IotProductServiceImpl implements IotProductService {
114 116 IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build();
115 117 // 3. 产品是发布状态
116 118 if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) {
117   - // 3.1 创建超级表数据模型
  119 + // 3.1 创建产品超级表数据模型
118 120 thinkModelFunctionService.createSuperTableDataModel(id);
  121 + // 3.2 创建物模型日志超级表数据模型
  122 + thinkModelMessageService.createSuperTable(id);
119 123 }
120 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 15 * @param thingModelMessage 物模型消息
16 16 */
17 17 void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage);
  18 +
  19 + /**
  20 + * 创建物模型消息日志超级表
  21 + *
  22 + * @param productId 产品编号
  23 + */
  24 + void createSuperTable(Long productId);
  25 +
18 26 }
19 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 7 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO;
8 8 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
9 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 12 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO;
15 13 import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO;
16 14 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper;
17 15 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper;
  16 +import cn.iocoder.yudao.module.iot.dal.tdengine.TdThinkModelMessageMapper;
18 17 import cn.iocoder.yudao.module.iot.enums.IotConstants;
19 18 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
20 19 import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum;
21 20 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  21 +import cn.iocoder.yudao.module.iot.service.product.IotProductService;
22 22 import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService;
  23 +import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils;
23 24 import jakarta.annotation.Resource;
24 25 import lombok.extern.slf4j.Slf4j;
25 26 import org.springframework.beans.factory.annotation.Value;
... ... @@ -54,19 +55,29 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ
54 55 private TdEngineDDLMapper tdEngineDDLMapper;
55 56 @Resource
56 57 private TdEngineDMLMapper tdEngineDMLMapper;
57   -
  58 + @Resource
  59 + private IotProductService productService;
58 60 @Resource
59 61 private DeviceDataRedisDAO deviceDataRedisDAO;
60 62  
  63 + @Resource
  64 + private IotTdDatabaseUtils iotTdDatabaseUtils;
  65 +
  66 + @Resource
  67 + private TdThinkModelMessageMapper tdThinkModelMessageMapper;
  68 +
61 69 // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感
62 70 @Override
63 71 @TenantIgnore
64 72 public void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage) {
65 73 // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态
66 74 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) {
  75 + // 1.1 创建设备表
67 76 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
68 77 iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO()
69 78 .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus()));
  79 + // 1.2 创建物模型日志设备表
  80 + createThinkModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
70 81 }
71 82  
72 83 // 2. 获取设备属性并进行物模型校验,过滤非物模型属性
... ... @@ -90,6 +101,22 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ
90 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 120 private List<IotProductThinkModelDO> getValidFunctionList(String productKey) {
94 121 return iotProductThinkModelService
95 122 .getProductThinkModelListByProductKey(productKey)
... ... @@ -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 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 35 \ No newline at end of file
... ...