Commit 03d4f60e8027b2e6125e2db4077d87c72ba72ccf

Authored by alwayssuper
1 parent 4f962bd1

[fix]:code review

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java
... ... @@ -19,6 +19,9 @@ public class SelectVisualDO {
19 19 */
20 20 private String tableName;
21 21  
  22 +
  23 + private String deviceKey;
  24 +
22 25 /**
23 26 * 属性
24 27 */
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java
... ... @@ -33,6 +33,10 @@ public class TdTableDO {
33 33 */
34 34 private String tableName;
35 35  
  36 + private String productKey;
  37 +
  38 + private String deviceKey;
  39 +
36 40 /**
37 41 * COLUMN 字段
38 42 */
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java
... ... @@ -68,6 +68,15 @@ public interface IotDeviceLogDataMapper {
68 68 /**
69 69 * 查询设备日志表是否存在
70 70 *
  71 + * @return 不存在返回null
71 72 */
72   - Object checkDeviceLogTableExists();
  73 + Object checkDeviceLogSTableExists();
  74 +
  75 + /**
  76 + * 检查设备日志子表是否存在
  77 + *
  78 + * @param deviceKey 设备标识
  79 + * @return 不存在返回null
  80 + */
  81 + Object checkDeviceLogTableExists(@Param("deviceKey") String deviceKey);
73 82 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java
... ... @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.iot.dal.tdengine;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjectUtil;
  5 +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
  6 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO;
5 8 import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField;
6 9 import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS;
7 10 import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
... ... @@ -10,6 +13,7 @@ import org.apache.ibatis.annotations.Param;
10 13  
11 14 import java.util.ArrayList;
12 15 import java.util.List;
  16 +import java.util.Map;
13 17 import java.util.stream.Collectors;
14 18  
15 19 @Mapper
... ... @@ -74,4 +78,43 @@ public interface IotDevicePropertyDataMapper {
74 78 void alterProductPropertySTableDropField(@Param("productKey") String productKey,
75 79 @Param("field") TDengineTableField field);
76 80  
  81 + //TODO:先参考一下老逻辑,后续改进
  82 + /**
  83 + * 插入数据 - 指定列插入数据
  84 + *
  85 + * @param table 数据
  86 + * productKey 产品 key
  87 + * deviceKey 设备 key
  88 + * columns 列
  89 + */
  90 + void insertDevicePropertyData(TdTableDO table);
  91 +
  92 + //TODO:先参考一下老逻辑,后续改进
  93 + /**
  94 + * 查看超级表 - 获取超级表的结构信息
  95 + * SQL:DESCRIBE [db_name.]stb_name;
  96 + *
  97 + * @param superTable 超级表信息
  98 + * productKey 产品 key
  99 + */
  100 + List<Map<String, Object>> describeSuperTable(TdTableDO superTable);
  101 +
  102 + /**
  103 + * 获取历史数据列表
  104 + *
  105 + * @param selectVisualDO 查询条件
  106 + * @return 历史数据列表
  107 + */
  108 + @TenantIgnore
  109 + List<Map<String, Object>> selectHistoryDataList(SelectVisualDO selectVisualDO);
  110 +
  111 + /**
  112 + * 获取历史数据条数
  113 + *
  114 + * @param selectVisualDO 查询条件
  115 + * @return 数据条数
  116 + */
  117 + @TenantIgnore
  118 + Long selectHistoryCount(SelectVisualDO selectVisualDO);
  119 +
77 120 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java
... ... @@ -30,8 +30,10 @@ public class DeviceConsumer {
30 30 @Async
31 31 public void onMessage(ThingModelMessage message) {
32 32 log.info("[onMessage][消息内容({})]", message);
  33 + //TODO:数据插入这块整体写的比较混乱,整体借鉴了浩浩哥之前写的逻辑,目前是通过模拟设备科插入数据了,但之前的逻辑有大量弃用的部分,后续看看怎么完善
  34 +
33 35 // 设备数据记录
34   -// deviceDataService.saveDeviceDataTest(message);
  36 + deviceDataService.saveDeviceDataTest(message);
35 37 // 设备日志记录
36 38 iotDeviceLogDataService.saveDeviceLog(message);
37 39 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java
... ... @@ -43,8 +43,8 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{
43 43 // }
44 44 // throw e;
45 45 // }
46   - if(iotDeviceLogDataMapper.checkDeviceLogTableExists()==null){
47   - log.info("[TDengine] 设备日志超级表不存在,开始创建 {}",iotDeviceLogDataMapper.checkDeviceLogTableExists());
  46 + if(iotDeviceLogDataMapper.checkDeviceLogSTableExists()==null){
  47 + log.info("[TDengine] 设备日志超级表不存在,开始创建");
48 48 iotDeviceLogDataMapper.createDeviceLogSTable();
49 49 }else{
50 50 log.info("[TDengine] 设备日志超级表已存在,跳过创建");
... ... @@ -72,6 +72,10 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{
72 72 // 讨论:艿菇 这就是iotDeviceLogDataService的Impl
73 73 @Override
74 74 public PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) {
  75 + // 当设备日志表未创建时,查询会出现报错
  76 + if(iotDeviceLogDataMapper.checkDeviceLogTableExists(pageReqVO.getDeviceKey())==null){
  77 + return null;
  78 + }
75 79 // 查询数据
76 80 List<IotDeviceLogDO> list = iotDeviceLogDataMapper.selectPage(pageReqVO);
77 81 Long total = iotDeviceLogDataMapper.selectCount(pageReqVO);
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java
... ... @@ -244,6 +244,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe
244 244 SelectVisualDO selectVisualDO = new SelectVisualDO();
245 245 selectVisualDO.setDataBaseName(getDatabaseName());
246 246 selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName()));
  247 + selectVisualDO.setDeviceKey(device.getDeviceKey());
247 248 selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier());
248 249 selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());
249 250 selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime());
... ... @@ -251,8 +252,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe
251 252 params.put("rows", deviceDataReqVO.getPageSize());
252 253 params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize());
253 254 selectVisualDO.setParams(params);
254   - pageResult.setList(tdEngineDMLMapper.selectHistoryDataList(selectVisualDO));
255   - pageResult.setTotal(tdEngineDMLMapper.selectHistoryCount(selectVisualDO));
  255 + pageResult.setList(devicePropertyDataMapper.selectHistoryDataList(selectVisualDO));
  256 + pageResult.setTotal(devicePropertyDataMapper.selectHistoryCount(selectVisualDO));
256 257 return pageResult;
257 258 }
258 259  
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java
... ... @@ -13,6 +13,7 @@ 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.IotThingModelDO;
15 15 import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO;
  16 +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper;
16 17 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper;
17 18 import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper;
18 19 import cn.iocoder.yudao.module.iot.enums.IotConstants;
... ... @@ -62,6 +63,9 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
62 63 private TdEngineDMLMapper tdEngineDMLMapper;
63 64  
64 65 @Resource
  66 + private IotDevicePropertyDataMapper iotDevicePropertyDataMapper;
  67 +
  68 + @Resource
65 69 private DeviceDataRedisDAO deviceDataRedisDAO;
66 70  
67 71 // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感
... ... @@ -71,7 +75,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
71 75 // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态
72 76 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) {
73 77 // 1.1 创建设备表
74   - createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
  78 +// createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
75 79 iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO()
76 80 .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus()));
77 81 }
... ... @@ -85,14 +89,20 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
85 89  
86 90 // 3. 过滤并收集有效的属性字段,缓存设备属性
87 91 List<TdFieldDO> schemaFieldValues = filterAndCollectValidFields(params, thingModelList, device, thingModelMessage.getTime());
88   - if (schemaFieldValues.size() == 1) { // 仅有时间字段,无需保存
  92 + if (schemaFieldValues.size() == 0) { // 没有字段,无需保存
89 93 return;
90 94 }
91 95  
92 96 // 4. 构建并保存设备属性数据
93   - tdEngineDMLMapper.insertData(TdTableDO.builder()
94   - .dataBaseName(getDatabaseName())
95   - .tableName(getDeviceTableName(device.getProductKey(), device.getDeviceName()))
  97 +// tdEngineDMLMapper.insertData(TdTableDO.builder()
  98 +// .dataBaseName(getDatabaseName())
  99 +// .tableName(getDeviceTableName(device.getProductKey(), device.getDeviceName()))
  100 +// .columns(schemaFieldValues)
  101 +// .build());
  102 + // TODO:复用了旧逻辑,先过渡一下
  103 + iotDevicePropertyDataMapper.insertDevicePropertyData(TdTableDO.builder()
  104 + .productKey(device.getProductKey())
  105 + .deviceKey(device.getDeviceKey())
96 106 .columns(schemaFieldValues)
97 107 .build());
98 108 }
... ... @@ -145,7 +155,8 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
145 155  
146 156 // 3. 过滤并收集有效的属性字段
147 157 List<TdFieldDO> schemaFieldValues = new ArrayList<>();
148   - schemaFieldValues.add(new TdFieldDO(TIME, time));
  158 + //TODO:新版本是使用ts字段
  159 +// schemaFieldValues.add(new TdFieldDO(TIME, time));
149 160 params.forEach((key, val) -> {
150 161 if (propertyIdentifiers.contains(key)) {
151 162 schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val));
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml
... ... @@ -76,8 +76,14 @@
76 76 </select>
77 77  
78 78 <!-- 检查设备日志超级表是否存在 -->
79   - <select id="checkDeviceLogTableExists" resultType="Object">
  79 + <select id="checkDeviceLogSTableExists" resultType="Object">
80 80 SHOW STABLES LIKE 'device_log'
81 81 </select>
82 82  
  83 + <!-- 检查设备日志子表是否存在 -->
  84 + <select id="checkDeviceLogTableExists" resultType="Object">
  85 + SHOW TABLES LIKE 'device_log_${deviceKey}'
  86 + </select>
  87 +
  88 +
83 89 </mapper>
84 90 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml
... ... @@ -42,4 +42,46 @@
42 42 DROP COLUMN ${field.field}
43 43 </update>
44 44  
  45 + <insert id="insertDevicePropertyData">
  46 + INSERT INTO device_property_${deviceKey}
  47 + USING product_property_${productKey}
  48 + TAGS ('${deviceKey}')
  49 + (ts
  50 + <foreach item="item" collection="columns" separator=",">
  51 + ,${item.fieldName}
  52 + </foreach>
  53 + )
  54 + VALUES
  55 + (NOW
  56 + <foreach item="item" collection="columns" separator=",">
  57 + ,#{item.fieldValue}
  58 + </foreach>
  59 + )
  60 + </insert>
  61 +
  62 + <!-- 描述超级表结构 -->
  63 + <select id="describeSuperTable" resultType="java.util.Map">
  64 + DESCRIBE product_property_${productKey}
  65 + </select>
  66 +
  67 + <!-- 获取历史数据 -->
  68 + <select id="selectHistoryDataList" resultType="java.util.Map"
  69 + parameterType="cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO">
  70 + SELECT ${fieldName} AS data, ts AS time
  71 + FROM device_property_${deviceKey}
  72 + WHERE ts BETWEEN #{startTime} AND #{endTime}
  73 + AND ${fieldName} IS NOT NULL
  74 + ORDER BY ts DESC
  75 + LIMIT #{params.rows} OFFSET #{params.page}
  76 + </select>
  77 +
  78 + <!-- 统计历史数据总数 -->
  79 + <select id="selectHistoryCount" resultType="java.lang.Long"
  80 + parameterType="cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO">
  81 + SELECT COUNT(*)
  82 + FROM device_property_${deviceKey}
  83 + WHERE ts BETWEEN #{startTime} AND #{endTime}
  84 + AND ${fieldName} IS NOT NULL
  85 + </select>
  86 +
45 87 </mapper>
46 88 \ No newline at end of file
... ...