【代码评审】IoT:tdengine 封装的 review
This commit is contained in:
parent
e3dcea9cb3
commit
9b30d5d355
|
@ -31,6 +31,7 @@ public class IotDeviceDataController {
|
|||
@Resource
|
||||
private IotDeviceDataService deviceDataService;
|
||||
|
||||
// TODO @haohao:是不是叫 get-latest 就好了。因为 data 已经在 url 里了哈
|
||||
@GetMapping("/latest-data")
|
||||
@Operation(summary = "获取设备属性最新数据")
|
||||
public CommonResult<List<IotDeviceDataRespVO>> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) {
|
||||
|
@ -38,6 +39,7 @@ public class IotDeviceDataController {
|
|||
return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class));
|
||||
}
|
||||
|
||||
// TODO @haohao:是不是叫 /history-data => page
|
||||
@GetMapping("/history-data")
|
||||
@Operation(summary = "获取设备属性历史数据")
|
||||
public CommonResult<PageResult<IotTimeDataRespVO>> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.time.LocalDateTime;
|
|||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
// TODO @haohao:IotDeviceDataPageReqVO
|
||||
@Schema(description = "管理后台 - IoT 设备数据 Request VO")
|
||||
@Data
|
||||
public class IotDeviceDataReqVO extends PageParam {
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.time.LocalDateTime;
|
|||
@AllArgsConstructor
|
||||
public class IotDeviceDataDO {
|
||||
|
||||
// TODO @haohao:每个字段的关联关系,可以 @ 下哈。
|
||||
/**
|
||||
* 设备编号
|
||||
*/
|
||||
|
|
|
@ -3,12 +3,15 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine;
|
|||
import lombok.Data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
// TODO @haohao:类似这个,其实可以参考 mybatis plus,querywrapper,搞个 TdEngineQueryWrapper。这样看起来会更好懂。
|
||||
/**
|
||||
* 查询DO
|
||||
*/
|
||||
@Data
|
||||
public class SelectDO {
|
||||
|
||||
// TODO @haoha:database 是个单词
|
||||
/**
|
||||
* 数据库名称
|
||||
*/
|
||||
|
@ -39,6 +42,7 @@ public class SelectDO {
|
|||
*/
|
||||
private String type;
|
||||
|
||||
// TODO @haohao:这个字段,是啥哈?
|
||||
/**
|
||||
* 查询条件
|
||||
*/
|
||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Data;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
// TODO @haohao:类似 SelectDO 的想法,只是它是返回。ps:貌似可以在 tdengine 里面,创建一个 query 包,放这种比较特殊的查询和结果对象。dataobject 更多还是实际存储的结构化的 do
|
||||
@Data
|
||||
public class SelectVisualDO {
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
// TODO @haohao:这个还有用哇?
|
||||
/**
|
||||
* TableManager 类用于管理 TDengine 表的创建、删除和结构信息获取
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
// TODO @haohao:有部分非实体的部分,是不是可以搞到 iot 的 framework 包下,搞个 tdengine 包,作为框架级的封装,放在 dataobject,感觉不是很合理哈。【可以微信讨论下】
|
||||
/**
|
||||
* TdRestApi 类用于处理 TDengine 的 REST API 请求
|
||||
*/
|
||||
|
|
|
@ -21,6 +21,7 @@ public class TdTableDO {
|
|||
*/
|
||||
private String dataBaseName;
|
||||
|
||||
// TODO @haohao:superTableName 和 tableName 是不是合并。因为每个 mapper 操作的时候,有且只会使用到其中一个。
|
||||
/**
|
||||
* 超级表名称
|
||||
*/
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.apache.ibatis.annotations.Mapper;
|
|||
@Mapper
|
||||
public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
|
||||
|
||||
// TODO @haohao:可能多余的查询条件,要去掉哈
|
||||
default PageResult<IotDeviceDO> selectPage(IotDevicePageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<IotDeviceDO>()
|
||||
.eqIfPresent(IotDeviceDO::getDeviceKey, reqVO.getDeviceKey())
|
||||
|
|
|
@ -43,7 +43,7 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX<IotThinkModelFu
|
|||
|
||||
default List<IotThinkModelFunctionDO> selectListByProductIdAndIdentifiersAndTypes(Long productId,
|
||||
List<String> identifiers,
|
||||
List<Integer> types){
|
||||
List<Integer> types) {
|
||||
return selectList(new LambdaQueryWrapperX<IotThinkModelFunctionDO>()
|
||||
.eq(IotThinkModelFunctionDO::getProductId, productId)
|
||||
.in(IotThinkModelFunctionDO::getIdentifier, identifiers)
|
||||
|
@ -55,7 +55,8 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX<IotThinkModelFu
|
|||
IotThinkModelFunctionDO::getName, name);
|
||||
}
|
||||
|
||||
default List<IotThinkModelFunctionDO> selectListByProductKey(String productKey){
|
||||
default List<IotThinkModelFunctionDO> selectListByProductKey(String productKey) {
|
||||
return selectList(IotThinkModelFunctionDO::getProductKey, productKey);
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
|
|||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
// TODO @haohao:InterceptorIgnore 忽略租户,可以在每个方法上,添加 @TenantIgnore 哈。
|
||||
/**
|
||||
* TD 引擎的数据库 Mapper
|
||||
*/
|
||||
|
|
|
@ -25,6 +25,7 @@ public interface TdEngineQueryMapper {
|
|||
*/
|
||||
List<Map<String, Object>> selectByTimestamp(SelectDO selectDO);
|
||||
|
||||
// TODO @haohao:最好方法的命名,和数据库操作的保持一直。get => select。然后 selectList or selectOne
|
||||
/**
|
||||
* 根据时间戳获取数据条数
|
||||
*
|
||||
|
|
|
@ -31,6 +31,7 @@ public class EmqxServiceImpl implements EmqxService {
|
|||
// 根据不同的主题,处理不同的业务逻辑
|
||||
if (topic.contains("/property/post")) {
|
||||
// 设备上报数据 topic /sys/f13f57c63e9/dianbiao1/thing/event/property/post
|
||||
// TODO @hao:这块未来可能,搞个 IotTopicUrls 之类?把拼接和解析的逻辑,收敛
|
||||
String productKey = topic.split("/")[2];
|
||||
String deviceName = topic.split("/")[3];
|
||||
String message = new String(mqttMessage.getPayload());
|
||||
|
@ -48,4 +49,5 @@ public class EmqxServiceImpl implements EmqxService {
|
|||
log.error("订阅默认主题失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -133,4 +133,5 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService {
|
|||
private static String getDeviceTableName(String productKey, String deviceName) {
|
||||
return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -213,31 +213,30 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||
|
||||
@Override
|
||||
public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
// 1. 校验存在
|
||||
// TODO @haohao:这里的 iotDeviceDO => device。一个是去掉 iot,一个是去掉 DO 后缀。这样,简洁一点。
|
||||
IotDeviceDO iotDeviceDO = validateDeviceExists(updateReqVO.getId());
|
||||
|
||||
// 更新状态和更新时间
|
||||
// 2.1 更新状态和更新时间
|
||||
IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
|
||||
|
||||
// 以前是未激活,现在是上线,设置设备激活时间
|
||||
// TODO @haohao:下面几个状态的处理,可以考虑 if else if。这样,看起来会有层次感哈
|
||||
// 2.2.1 以前是未激活,现在是上线,设置设备激活时间
|
||||
// TODO @haohao:这里可以使用 ObjectUtils.equalsAny 类似这种哈。
|
||||
if (Objects.equals(iotDeviceDO.getStatus(), IotDeviceStatusEnum.INACTIVE.getStatus())
|
||||
&& Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) {
|
||||
updateObj.setActiveTime(LocalDateTime.now());
|
||||
}
|
||||
|
||||
// 如果是上线,设置上线时间
|
||||
// 2.2.2 如果是上线,设置上线时间
|
||||
if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) {
|
||||
updateObj.setLastOnlineTime(LocalDateTime.now());
|
||||
}
|
||||
|
||||
// 如果是离线,设置离线时间
|
||||
// 2.2.3 如果是离线,设置离线时间
|
||||
if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.OFFLINE.getStatus())) {
|
||||
updateObj.setLastOfflineTime(LocalDateTime.now());
|
||||
}
|
||||
|
||||
// 设置状态更新时间
|
||||
// 2.3 设置状态更新时间
|
||||
updateObj.setStatusLastUpdateTime(LocalDateTime.now());
|
||||
|
||||
// 2.4 更新到数据库
|
||||
deviceMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
|||
@Resource
|
||||
private DeviceDataRedisDAO deviceDataRedisDAO;
|
||||
|
||||
// TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感
|
||||
@Override
|
||||
@TenantIgnore
|
||||
public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) {
|
||||
|
@ -55,12 +56,14 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
|||
// 创建设备数据表
|
||||
createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey());
|
||||
// 更新设备状态
|
||||
// TODO @haohao:下面可以考虑,链式调用。iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO().setid().setstatus())
|
||||
IotDeviceStatusUpdateReqVO updateReqVO = new IotDeviceStatusUpdateReqVO();
|
||||
updateReqVO.setId(device.getId());
|
||||
updateReqVO.setStatus(IotDeviceStatusEnum.ONLINE.getStatus());
|
||||
iotDeviceService.updateDeviceStatus(updateReqVO);
|
||||
}
|
||||
|
||||
// TODO @haohao:这个变量,可以和 “过滤并收集有效的属性字段” 那块,因为关联度高一点。
|
||||
// 获取设备属性
|
||||
Map<String, Object> params = thingModelMessage.dataToMap();
|
||||
|
||||
|
@ -70,12 +73,12 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
|||
.stream()
|
||||
.filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType().equals(function.getType()))
|
||||
.toList();
|
||||
|
||||
if (functionList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取属性标识符集合
|
||||
// TODO @haohao:这个变量,可以和 “过滤并收集有效的属性字段” 那块,因为关联度高一点。另外,可以使用 CollectionUtils。convertSet
|
||||
Set<String> propertyIdentifiers = functionList.stream()
|
||||
.map(IotThinkModelFunctionDO::getIdentifier)
|
||||
.collect(Collectors.toSet());
|
||||
|
@ -90,9 +93,11 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
|||
if (propertyIdentifiers.contains(key)) {
|
||||
schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val));
|
||||
// 缓存设备属性
|
||||
// TODO @haohao:这个缓存的写入,可以使用的时候 cache 么?被动读
|
||||
setDeviceDataCache(device, functionMap.get(key), val, thingModelMessage.getTime());
|
||||
}
|
||||
});
|
||||
// TODO @haohao:疑问,为什么 1 不继续哈?
|
||||
if (schemaFieldValues.size() == 1) {
|
||||
return;
|
||||
}
|
||||
|
@ -127,6 +132,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
|||
deviceDataRedisDAO.set(deviceData);
|
||||
}
|
||||
|
||||
// TODO @haohao:实现没问题哈。这个方法的空行有点多,逻辑分块上没这么明显。看看能不能改下。
|
||||
/**
|
||||
* 创建设备数据表
|
||||
*
|
||||
|
@ -143,6 +149,8 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
|||
List<TdFieldDO> tagsFieldValues = new ArrayList<>();
|
||||
|
||||
if (maps != null) {
|
||||
// TODO @haohao:一些字符串,是不是可以枚举起来哈。
|
||||
// TODO @haohao:这种过滤的,常用的,可以考虑用 CollectionUtils.filterList。一些常用的 stream 操作,适合封装哈
|
||||
List<Map<String, Object>> taggedNotesList = maps.stream()
|
||||
.filter(map -> "TAG".equals(map.get("note")))
|
||||
.toList();
|
||||
|
@ -176,6 +184,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
|||
* @return 数据库名称
|
||||
*/
|
||||
private String getDatabaseName() {
|
||||
// TODO @haohao:可以使用 StrUtil.subAftetLast 这种方法
|
||||
return url.substring(url.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
|
@ -187,6 +196,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
|||
* @return 产品属性表名
|
||||
*/
|
||||
private static String getProductPropertySTableName(Integer deviceType, String productKey) {
|
||||
// TODO @haohao:枚举下,会好点哈。
|
||||
return switch (deviceType) {
|
||||
case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase();
|
||||
case 2 -> String.format("gateway_%s", productKey).toLowerCase();
|
||||
|
@ -204,4 +214,5 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ
|
|||
private static String getDeviceTableName(String productKey, String deviceName) {
|
||||
return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase());
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
<!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.TdEngineDataWriterMapper">
|
||||
|
||||
<!-- 插入数据 -->
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<!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.TdEngineDatabaseMapper">
|
||||
|
||||
<!-- 创建数据库 -->
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<!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.TdEngineQueryMapper">
|
||||
|
||||
<!-- 根据时间戳查询数据 -->
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<!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.TdEngineSuperTableMapper">
|
||||
|
||||
<!-- 创建超级表 -->
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<!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.TdEngineTableMapper">
|
||||
|
||||
<!-- 创建子表 -->
|
||||
|
|
Loading…
Reference in New Issue