Commit 92de5b1f09b7c7f11aaaecc9ac883dd24cf55232

Authored by YunaiV
2 parents caa7198e 067130ec

Merge branch 'feature/iot' of https://gitee.com/alwayssuper/ruoyi-vue-pro into feature/iot

# Conflicts:
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java
#	yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java
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/thingmodel/model/dataType/ThingModelArgument.java
1 1 package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType;
2 2  
3 3 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty;
  5 +import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 6 import lombok.Data;
5 7  
6 8 @Data
7   -public class ThingModelArgument {
  9 +@JsonIgnoreProperties(ignoreUnknown = true)
  10 +public class ThinkModelArgument {
8 11  
9 12 public static final String DIRECTION_INPUT = "input";
10 13 public static final String DIRECTION_OUTPUT = "output";
... ...
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,7 +7,8 @@ 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.thingmodel.IotProductThingModelService;
  10 +import cn.iocoder.yudao.module.iot.service.tdengine.IotThinkModelMessageService;
  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;
13 14 import org.springframework.context.annotation.Lazy;
... ... @@ -33,8 +34,11 @@ public class IotProductServiceImpl implements IotProductService {
33 34 private IotProductMapper productMapper;
34 35  
35 36 @Resource
36   - @Lazy
37   - private IotProductThingModelService thingModelService;
  37 + @Lazy // 延迟加载,解决循环依赖
  38 + private IotProductThinkModelService thinkModelFunctionService;
  39 + @Resource
  40 + @Lazy // 延迟加载,解决循环依赖
  41 + private IotThinkModelMessageService thinkModelMessageService;
38 42  
39 43 @Override
40 44 public Long createProduct(IotProductSaveReqVO createReqVO) {
... ... @@ -114,8 +118,10 @@ public class IotProductServiceImpl implements IotProductService {
114 118 IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build();
115 119 // 3. 产品是发布状态
116 120 if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) {
117   - // 3.1 创建超级表数据模型
118   - thingModelService.createSuperTableDataModel(id);
  121 + // 3.1 创建产品超级表数据模型
  122 + thinkModelFunctionService.createSuperTableDataModel(id);
  123 + // 3.2 创建物模型日志超级表数据模型
  124 + thinkModelMessageService.createSuperTable(id);
119 125 }
120 126 productMapper.updateById(updateObj);
121 127 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java
1 1 package cn.iocoder.yudao.module.iot.service.tdengine;
2 2  
3 3 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
4   -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
  4 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage;
5 5  
6 6 /**
7 7 * 物模型消息 Service
... ... @@ -14,5 +14,13 @@ public interface IotThingModelMessageService {
14 14 * @param device 设备
15 15 * @param thingModelMessage 物模型消息
16 16 */
17   - void saveThingModelMessage(IotDeviceDO device, ThingModelMessage 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 27 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java
... ... @@ -12,14 +12,21 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;
12 12 import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO;
13 13 import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage;
14 14 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO;
  15 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  16 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*;
  17 +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO;
15 18 import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO;
16 19 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper;
17 20 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper;
  21 +import cn.iocoder.yudao.module.iot.dal.tdengine.TdThinkModelMessageMapper;
18 22 import cn.iocoder.yudao.module.iot.enums.IotConstants;
19 23 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
20 24 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum;
21 25 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
22 26 import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService;
  27 +import cn.iocoder.yudao.module.iot.service.product.IotProductService;
  28 +import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService;
  29 +import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils;
23 30 import jakarta.annotation.Resource;
24 31 import lombok.extern.slf4j.Slf4j;
25 32 import org.springframework.beans.factory.annotation.Value;
... ... @@ -56,19 +63,29 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
56 63 private TdEngineDDLMapper tdEngineDDLMapper;
57 64 @Resource
58 65 private TdEngineDMLMapper tdEngineDMLMapper;
59   -
  66 + @Resource
  67 + private IotProductService productService;
60 68 @Resource
61 69 private DeviceDataRedisDAO deviceDataRedisDAO;
62 70  
  71 + @Resource
  72 + private IotTdDatabaseUtils iotTdDatabaseUtils;
  73 +
  74 + @Resource
  75 + private TdThinkModelMessageMapper tdThinkModelMessageMapper;
  76 +
63 77 // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感
64 78 @Override
65 79 @TenantIgnore
66 80 public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) {
67 81 // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态
68 82 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) {
  83 + // 1.1 创建设备表
69 84 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
70 85 iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO()
71 86 .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus()));
  87 + // 1.2 创建物模型日志设备表
  88 + createThinkModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
72 89 }
73 90  
74 91 // 2. 获取设备属性并进行物模型校验,过滤非物模型属性
... ... @@ -95,6 +112,28 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
95 112 private List<IotProductThingModelDO> getValidThingModelList(String productKey) {
96 113 return filterList(iotProductThingModelService.getProductThingModelListByProductKey(productKey),
97 114 thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType()));
  115 + @Override
  116 + @TenantIgnore
  117 + public void createSuperTable(Long productId) {
  118 + // 1. 查询产品
  119 + IotProductDO product = productService.getProduct(productId);
  120 +
  121 + // 2. 获取超级表的名称和数据库名称
  122 + String databaseName = iotTdDatabaseUtils.getDatabaseName();
  123 + String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(product.getProductKey());
  124 +
  125 + // 3. 创建超级表
  126 + tdThinkModelMessageMapper.createSuperTable(ThinkModelMessageDO.builder().build()
  127 + .setDataBaseName(databaseName)
  128 + .setSuperTableName(superTableName));
  129 + }
  130 +
  131 + private List<IotProductThinkModelDO> getValidFunctionList(String productKey) {
  132 + return iotProductThinkModelService
  133 + .getProductThinkModelListByProductKey(productKey)
  134 + .stream()
  135 + .filter(function -> IotProductThinkModelTypeEnum.PROPERTY.getType().equals(function.getType()))
  136 + .toList();
98 137 }
99 138  
100 139 private List<TdFieldDO> filterAndCollectValidFields(Map<String, Object> params, List<IotProductThingModelDO> thingModelList, IotDeviceDO device, Long time) {
... ... @@ -187,6 +226,30 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
187 226 }
188 227  
189 228 /**
  229 + * 创建物模型日志设备数据表
  230 + *
  231 + * @param productKey 产品 Key
  232 + * @param deviceName 设备名称
  233 + * @param deviceKey 设备 Key
  234 + *
  235 + */
  236 + private void createThinkModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){
  237 +
  238 + // 1. 获取超级表的名称、数据库名称、设备日志表名称
  239 + String databaseName = iotTdDatabaseUtils.getDatabaseName();
  240 + String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(productKey);
  241 + String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThinkModelMessageDeviceTableName(productKey, deviceName);
  242 +
  243 + // 2. 创建物模型日志设备数据表
  244 + tdThinkModelMessageMapper.createTableWithTag(ThinkModelMessageDO.builder().build()
  245 + .setDataBaseName(databaseName)
  246 + .setSuperTableName(superTableName)
  247 + .setTableName(thinkModelMessageDeviceTableName)
  248 + .setDeviceKey(deviceKey));
  249 +
  250 + }
  251 +
  252 + /**
190 253 * 获取数据库名称
191 254 *
192 255 * @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
... ...