Commit 9b30d5d35572dc54646b2c3f3ad2fe04368fcd5d

Authored by YunaiV
1 parent e3dcea9c

【代码评审】IoT:tdengine 封装的 review

Showing 21 changed files with 43 additions and 19 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java
... ... @@ -31,6 +31,7 @@ public class IotDeviceDataController {
31 31 @Resource
32 32 private IotDeviceDataService deviceDataService;
33 33  
  34 + // TODO @haohao:是不是叫 get-latest 就好了。因为 data 已经在 url 里了哈
34 35 @GetMapping("/latest-data")
35 36 @Operation(summary = "获取设备属性最新数据")
36 37 public CommonResult<List<IotDeviceDataRespVO>> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) {
... ... @@ -38,6 +39,7 @@ public class IotDeviceDataController {
38 39 return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class));
39 40 }
40 41  
  42 + // TODO @haohao:是不是叫 /history-data => page
41 43 @GetMapping("/history-data")
42 44 @Operation(summary = "获取设备属性历史数据")
43 45 public CommonResult<PageResult<IotTimeDataRespVO>> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO) {
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java
... ... @@ -10,6 +10,7 @@ import java.time.LocalDateTime;
10 10  
11 11 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
12 12  
  13 +// TODO @haohao:IotDeviceDataPageReqVO
13 14 @Schema(description = "管理后台 - IoT 设备数据 Request VO")
14 15 @Data
15 16 public class IotDeviceDataReqVO extends PageParam {
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java
... ... @@ -23,6 +23,7 @@ import java.time.LocalDateTime;
23 23 @AllArgsConstructor
24 24 public class IotDeviceDataDO {
25 25  
  26 + // TODO @haohao:每个字段的关联关系,可以 @ 下哈。
26 27 /**
27 28 * 设备编号
28 29 */
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java
... ... @@ -3,12 +3,15 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine;
3 3 import lombok.Data;
4 4  
5 5 import java.util.Set;
  6 +
  7 +// TODO @haohao:类似这个,其实可以参考 mybatis plus,querywrapper,搞个 TdEngineQueryWrapper。这样看起来会更好懂。
6 8 /**
7 9 * 查询DO
8 10 */
9 11 @Data
10 12 public class SelectDO {
11 13  
  14 + // TODO @haoha:database 是个单词
12 15 /**
13 16 * 数据库名称
14 17 */
... ... @@ -39,6 +42,7 @@ public class SelectDO {
39 42 */
40 43 private String type;
41 44  
  45 + // TODO @haohao:这个字段,是啥哈?
42 46 /**
43 47 * 查询条件
44 48 */
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java
... ... @@ -4,6 +4,7 @@ import lombok.Data;
4 4  
5 5 import java.util.Map;
6 6  
  7 +// TODO @haohao:类似 SelectDO 的想法,只是它是返回。ps:貌似可以在 tdengine 里面,创建一个 query 包,放这种比较特殊的查询和结果对象。dataobject 更多还是实际存储的结构化的 do
7 8 @Data
8 9 public class SelectVisualDO {
9 10  
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine;
2 2  
3 3 import java.util.List;
4 4  
  5 +// TODO @haohao:这个还有用哇?
5 6 /**
6 7 * TableManager 类用于管理 TDengine 表的创建、删除和结构信息获取
7 8 */
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java
... ... @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j;
7 7 import org.springframework.beans.factory.annotation.Value;
8 8 import org.springframework.stereotype.Service;
9 9  
  10 +// TODO @haohao:有部分非实体的部分,是不是可以搞到 iot 的 framework 包下,搞个 tdengine 包,作为框架级的封装,放在 dataobject,感觉不是很合理哈。【可以微信讨论下】
10 11 /**
11 12 * TdRestApi 类用于处理 TDengine 的 REST API 请求
12 13 */
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java
... ... @@ -21,6 +21,7 @@ public class TdTableDO {
21 21 */
22 22 private String dataBaseName;
23 23  
  24 + // TODO @haohao:superTableName 和 tableName 是不是合并。因为每个 mapper 操作的时候,有且只会使用到其中一个。
24 25 /**
25 26 * 超级表名称
26 27 */
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
... ... @@ -15,6 +15,7 @@ import org.apache.ibatis.annotations.Mapper;
15 15 @Mapper
16 16 public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
17 17  
  18 + // TODO @haohao:可能多余的查询条件,要去掉哈
18 19 default PageResult<IotDeviceDO> selectPage(IotDevicePageReqVO reqVO) {
19 20 return selectPage(reqVO, new LambdaQueryWrapperX<IotDeviceDO>()
20 21 .eqIfPresent(IotDeviceDO::getDeviceKey, reqVO.getDeviceKey())
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
... ... @@ -43,7 +43,7 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX&lt;IotThinkModelFu
43 43  
44 44 default List<IotThinkModelFunctionDO> selectListByProductIdAndIdentifiersAndTypes(Long productId,
45 45 List<String> identifiers,
46   - List<Integer> types){
  46 + List<Integer> types) {
47 47 return selectList(new LambdaQueryWrapperX<IotThinkModelFunctionDO>()
48 48 .eq(IotThinkModelFunctionDO::getProductId, productId)
49 49 .in(IotThinkModelFunctionDO::getIdentifier, identifiers)
... ... @@ -55,7 +55,8 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX&lt;IotThinkModelFu
55 55 IotThinkModelFunctionDO::getName, name);
56 56 }
57 57  
58   - default List<IotThinkModelFunctionDO> selectListByProductKey(String productKey){
  58 + default List<IotThinkModelFunctionDO> selectListByProductKey(String productKey) {
59 59 return selectList(IotThinkModelFunctionDO::getProductKey, productKey);
60 60 }
  61 +
61 62 }
62 63 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java
... ... @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
5 5 import org.apache.ibatis.annotations.Mapper;
6 6 import org.apache.ibatis.annotations.Param;
7 7  
  8 +// TODO @haohao:InterceptorIgnore 忽略租户,可以在每个方法上,添加 @TenantIgnore 哈。
8 9 /**
9 10 * TD 引擎的数据库 Mapper
10 11 */
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java
... ... @@ -25,6 +25,7 @@ public interface TdEngineQueryMapper {
25 25 */
26 26 List<Map<String, Object>> selectByTimestamp(SelectDO selectDO);
27 27  
  28 + // TODO @haohao:最好方法的命名,和数据库操作的保持一直。get => select。然后 selectList or selectOne
28 29 /**
29 30 * 根据时间戳获取数据条数
30 31 *
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
... ... @@ -31,6 +31,7 @@ public class EmqxServiceImpl implements EmqxService {
31 31 // 根据不同的主题,处理不同的业务逻辑
32 32 if (topic.contains("/property/post")) {
33 33 // 设备上报数据 topic /sys/f13f57c63e9/dianbiao1/thing/event/property/post
  34 + // TODO @hao:这块未来可能,搞个 IotTopicUrls 之类?把拼接和解析的逻辑,收敛
34 35 String productKey = topic.split("/")[2];
35 36 String deviceName = topic.split("/")[3];
36 37 String message = new String(mqttMessage.getPayload());
... ... @@ -48,4 +49,5 @@ public class EmqxServiceImpl implements EmqxService {
48 49 log.error("订阅默认主题失败", e);
49 50 }
50 51 }
  52 +
51 53 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java
... ... @@ -133,4 +133,5 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService {
133 133 private static String getDeviceTableName(String productKey, String deviceName) {
134 134 return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase());
135 135 }
  136 +
136 137 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
... ... @@ -213,31 +213,30 @@ public class IotDeviceServiceImpl implements IotDeviceService {
213 213  
214 214 @Override
215 215 public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) {
216   - // 校验存在
  216 + // 1. 校验存在
  217 + // TODO @haohao:这里的 iotDeviceDO => device。一个是去掉 iot,一个是去掉 DO 后缀。这样,简洁一点。
217 218 IotDeviceDO iotDeviceDO = validateDeviceExists(updateReqVO.getId());
218 219  
219   - // 更新状态和更新时间
  220 + // 2.1 更新状态和更新时间
220 221 IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
221   -
222   - // 以前是未激活,现在是上线,设置设备激活时间
  222 + // TODO @haohao:下面几个状态的处理,可以考虑 if else if。这样,看起来会有层次感哈
  223 + // 2.2.1 以前是未激活,现在是上线,设置设备激活时间
  224 + // TODO @haohao:这里可以使用 ObjectUtils.equalsAny 类似这种哈。
223 225 if (Objects.equals(iotDeviceDO.getStatus(), IotDeviceStatusEnum.INACTIVE.getStatus())
224 226 && Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) {
225 227 updateObj.setActiveTime(LocalDateTime.now());
226 228 }
227   -
228   - // 如果是上线,设置上线时间
  229 + // 2.2.2 如果是上线,设置上线时间
229 230 if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) {
230 231 updateObj.setLastOnlineTime(LocalDateTime.now());
231 232 }
232   -
233   - // 如果是离线,设置离线时间
  233 + // 2.2.3 如果是离线,设置离线时间
234 234 if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.OFFLINE.getStatus())) {
235 235 updateObj.setLastOfflineTime(LocalDateTime.now());
236 236 }
237   -
238   - // 设置状态更新时间
  237 + // 2.3 设置状态更新时间
239 238 updateObj.setStatusLastUpdateTime(LocalDateTime.now());
240   -
  239 + // 2.4 更新到数据库
241 240 deviceMapper.updateById(updateObj);
242 241 }
243 242  
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java
... ... @@ -47,6 +47,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
47 47 @Resource
48 48 private DeviceDataRedisDAO deviceDataRedisDAO;
49 49  
  50 + // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感
50 51 @Override
51 52 @TenantIgnore
52 53 public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) {
... ... @@ -55,12 +56,14 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
55 56 // 创建设备数据表
56 57 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
57 58 // 更新设备状态
  59 + // TODO @haohao:下面可以考虑,链式调用。iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO().setid().setstatus())
58 60 IotDeviceStatusUpdateReqVO updateReqVO = new IotDeviceStatusUpdateReqVO();
59 61 updateReqVO.setId(device.getId());
60 62 updateReqVO.setStatus(IotDeviceStatusEnum.ONLINE.getStatus());
61 63 iotDeviceService.updateDeviceStatus(updateReqVO);
62 64 }
63 65  
  66 + // TODO @haohao:这个变量,可以和 “过滤并收集有效的属性字段” 那块,因为关联度高一点。
64 67 // 获取设备属性
65 68 Map<String, Object> params = thingModelMessage.dataToMap();
66 69  
... ... @@ -70,12 +73,12 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
70 73 .stream()
71 74 .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType().equals(function.getType()))
72 75 .toList();
73   -
74 76 if (functionList.isEmpty()) {
75 77 return;
76 78 }
77 79  
78 80 // 获取属性标识符集合
  81 + // TODO @haohao:这个变量,可以和 “过滤并收集有效的属性字段” 那块,因为关联度高一点。另外,可以使用 CollectionUtils。convertSet
79 82 Set<String> propertyIdentifiers = functionList.stream()
80 83 .map(IotThinkModelFunctionDO::getIdentifier)
81 84 .collect(Collectors.toSet());
... ... @@ -90,9 +93,11 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
90 93 if (propertyIdentifiers.contains(key)) {
91 94 schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val));
92 95 // 缓存设备属性
  96 + // TODO @haohao:这个缓存的写入,可以使用的时候 cache 么?被动读
93 97 setDeviceDataCache(device, functionMap.get(key), val, thingModelMessage.getTime());
94 98 }
95 99 });
  100 + // TODO @haohao:疑问,为什么 1 不继续哈?
96 101 if (schemaFieldValues.size() == 1) {
97 102 return;
98 103 }
... ... @@ -127,6 +132,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
127 132 deviceDataRedisDAO.set(deviceData);
128 133 }
129 134  
  135 + // TODO @haohao:实现没问题哈。这个方法的空行有点多,逻辑分块上没这么明显。看看能不能改下。
130 136 /**
131 137 * 创建设备数据表
132 138 *
... ... @@ -143,6 +149,8 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
143 149 List<TdFieldDO> tagsFieldValues = new ArrayList<>();
144 150  
145 151 if (maps != null) {
  152 + // TODO @haohao:一些字符串,是不是可以枚举起来哈。
  153 + // TODO @haohao:这种过滤的,常用的,可以考虑用 CollectionUtils.filterList。一些常用的 stream 操作,适合封装哈
146 154 List<Map<String, Object>> taggedNotesList = maps.stream()
147 155 .filter(map -> "TAG".equals(map.get("note")))
148 156 .toList();
... ... @@ -176,6 +184,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
176 184 * @return 数据库名称
177 185 */
178 186 private String getDatabaseName() {
  187 + // TODO @haohao:可以使用 StrUtil.subAftetLast 这种方法
179 188 return url.substring(url.lastIndexOf("/") + 1);
180 189 }
181 190  
... ... @@ -187,6 +196,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
187 196 * @return 产品属性表名
188 197 */
189 198 private static String getProductPropertySTableName(Integer deviceType, String productKey) {
  199 + // TODO @haohao:枚举下,会好点哈。
190 200 return switch (deviceType) {
191 201 case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase();
192 202 case 2 -> String.format("gateway_%s", productKey).toLowerCase();
... ... @@ -204,4 +214,5 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
204 214 private static String getDeviceTableName(String productKey, String deviceName) {
205 215 return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase());
206 216 }
  217 +
207 218 }
208 219 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml
... ... @@ -2,7 +2,6 @@
2 2 <!DOCTYPE mapper
3 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5   -
6 5 <mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDataWriterMapper">
7 6  
8 7 <!-- 插入数据 -->
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml
... ... @@ -2,7 +2,6 @@
2 2 <!DOCTYPE mapper
3 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5   -
6 5 <mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDatabaseMapper">
7 6  
8 7 <!-- 创建数据库 -->
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml
... ... @@ -2,7 +2,6 @@
2 2 <!DOCTYPE mapper
3 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5   -
6 5 <mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineQueryMapper">
7 6  
8 7 <!-- 根据时间戳查询数据 -->
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml
... ... @@ -2,7 +2,6 @@
2 2 <!DOCTYPE mapper
3 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5   -
6 5 <mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineSuperTableMapper">
7 6  
8 7 <!-- 创建超级表 -->
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml
... ... @@ -2,7 +2,6 @@
2 2 <!DOCTYPE mapper
3 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5   -
6 5 <mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineTableMapper">
7 6  
8 7 <!-- 创建子表 -->
... ...