mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 18:49:06 +08:00 
			
		
		
		
	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
This commit is contained in:
		| @ -35,4 +35,11 @@ public interface IotConstants { | ||||
|      */ | ||||
|     String DEVICE_STABLE_NAME_FORMAT = "device_%s"; | ||||
|  | ||||
|     /** | ||||
|      * 获取物模型消息记录设备名 | ||||
|      * <p> | ||||
|      * 格式为 thing_model_message_{productKey}_{deviceName} | ||||
|      */ | ||||
|     String THINK_MODEL_MESSAGE_TABLE_NAME_FORMAT = "thing_model_message_%s_%s"; | ||||
|  | ||||
| } | ||||
| @ -1,10 +1,13 @@ | ||||
| package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; | ||||
|  | ||||
| import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; | ||||
| import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; | ||||
| import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||||
| import lombok.Data; | ||||
|  | ||||
| @Data | ||||
| public class ThingModelArgument { | ||||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||||
| public class ThinkModelArgument { | ||||
|  | ||||
|     public static final String DIRECTION_INPUT = "input"; | ||||
|     public static final String DIRECTION_OUTPUT = "output"; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
|  | ||||
| } | ||||
| @ -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); | ||||
| } | ||||
| @ -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; | ||||
|  | ||||
| } | ||||
| @ -7,7 +7,8 @@ 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.thingmodel.IotProductThingModelService; | ||||
| 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; | ||||
| import org.springframework.context.annotation.Lazy; | ||||
| @ -33,8 +34,11 @@ public class IotProductServiceImpl implements IotProductService { | ||||
|     private IotProductMapper productMapper; | ||||
|  | ||||
|     @Resource | ||||
|     @Lazy | ||||
|     private IotProductThingModelService thingModelService; | ||||
|     @Lazy // 延迟加载,解决循环依赖 | ||||
|     private IotProductThinkModelService thinkModelFunctionService; | ||||
|     @Resource | ||||
|     @Lazy  // 延迟加载,解决循环依赖 | ||||
|     private IotThinkModelMessageService thinkModelMessageService; | ||||
|  | ||||
|     @Override | ||||
|     public Long createProduct(IotProductSaveReqVO createReqVO) { | ||||
| @ -114,8 +118,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 创建超级表数据模型 | ||||
|             thingModelService.createSuperTableDataModel(id); | ||||
|             // 3.1 创建产品超级表数据模型 | ||||
|             thinkModelFunctionService.createSuperTableDataModel(id); | ||||
|             // 3.2 创建物模型日志超级表数据模型 | ||||
|             thinkModelMessageService.createSuperTable(id); | ||||
|         } | ||||
|         productMapper.updateById(updateObj); | ||||
|     } | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| package cn.iocoder.yudao.module.iot.service.tdengine; | ||||
|  | ||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | ||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; | ||||
|  | ||||
| /** | ||||
|  * 物模型消息 Service | ||||
| @ -14,5 +14,13 @@ public interface IotThingModelMessageService { | ||||
|      * @param device            设备 | ||||
|      * @param thingModelMessage 物模型消息 | ||||
|      */ | ||||
|     void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); | ||||
|     void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage); | ||||
|  | ||||
|     /** | ||||
|      * 创建物模型消息日志超级表 | ||||
|      * | ||||
|      * @param productId 产品编号 | ||||
|      */ | ||||
|     void createSuperTable(Long productId); | ||||
|  | ||||
| } | ||||
| @ -12,14 +12,21 @@ 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.ThingModelMessage; | ||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; | ||||
| 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.thingmodel.IotProductThingModelTypeEnum; | ||||
| import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | ||||
| import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; | ||||
| 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; | ||||
| @ -56,19 +63,29 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ | ||||
|     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 saveThingModelMessage(IotDeviceDO device, ThingModelMessage 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. 获取设备属性并进行物模型校验,过滤非物模型属性 | ||||
| @ -95,6 +112,28 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ | ||||
|     private List<IotProductThingModelDO> getValidThingModelList(String productKey) { | ||||
|         return filterList(iotProductThingModelService.getProductThingModelListByProductKey(productKey), | ||||
|                 thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); | ||||
|     @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<IotProductThinkModelDO> getValidFunctionList(String productKey) { | ||||
|         return iotProductThinkModelService | ||||
|                 .getProductThinkModelListByProductKey(productKey) | ||||
|                 .stream() | ||||
|                 .filter(function -> IotProductThinkModelTypeEnum.PROPERTY.getType().equals(function.getType())) | ||||
|                 .toList(); | ||||
|     } | ||||
|  | ||||
|     private List<TdFieldDO> filterAndCollectValidFields(Map<String, Object> params, List<IotProductThingModelDO> thingModelList, IotDeviceDO device, Long time) { | ||||
| @ -186,6 +225,30 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ | ||||
|                 .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)); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取数据库名称 | ||||
|      * | ||||
|  | ||||
| @ -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()); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,34 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE mapper | ||||
|         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||||
|         "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||||
| <mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.TdThinkModelMessageMapper"> | ||||
|  | ||||
|  | ||||
|     <!-- 创建物模型消息日志超级表 --> | ||||
|     <update id="createSuperTable"> | ||||
|         CREATE STABLE ${dataBaseName}.${superTableName}( | ||||
|         ts TIMESTAMP, | ||||
|         id VARCHAR(255), | ||||
|         sys VARCHAR(2048), | ||||
|         method VARCHAR(255), | ||||
|         params VARCHAR(2048) | ||||
|         )TAGS ( | ||||
|         deviceKey VARCHAR(255) | ||||
|         ) | ||||
|     </update> | ||||
|  | ||||
|     <!-- 创建物模型消息日志子表,带有deviceKey的TAG --> | ||||
|     <update id="createTableWithTag"> | ||||
|         CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} | ||||
|         USING ${dataBaseName}.${superTableName}( | ||||
|             ts, | ||||
|             id , | ||||
|             sys , | ||||
|             method , | ||||
|             params | ||||
|         )TAGS( | ||||
|             #{deviceKey} | ||||
|         ) | ||||
|     </update> | ||||
| </mapper> | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV