|
@@ -1,12 +1,12 @@
|
|
package cn.iocoder.yudao.module.iot.service.tdengine;
|
|
package cn.iocoder.yudao.module.iot.service.tdengine;
|
|
|
|
|
|
|
|
+import cn.hutool.core.bean.BeanUtil;
|
|
import cn.hutool.core.collection.CollUtil;
|
|
import cn.hutool.core.collection.CollUtil;
|
|
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
|
|
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
|
|
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO;
|
|
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO;
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser;
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser;
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO;
|
|
-import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdRestApi;
|
|
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
|
|
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
|
|
import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
|
|
import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
|
|
import jakarta.annotation.Resource;
|
|
import jakarta.annotation.Resource;
|
|
@@ -14,10 +14,7 @@ import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
-import java.util.ArrayList;
|
|
|
|
-import java.util.List;
|
|
|
|
-import java.util.Map;
|
|
|
|
-import java.util.Objects;
|
|
|
|
|
|
+import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@Service
|
|
@Service
|
|
@@ -27,9 +24,6 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
@Resource
|
|
@Resource
|
|
private IotTdEngineService iotTdEngineService;
|
|
private IotTdEngineService iotTdEngineService;
|
|
|
|
|
|
- @Resource
|
|
|
|
- private TdRestApi tdRestApi;
|
|
|
|
-
|
|
|
|
@Value("${spring.datasource.dynamic.datasource.tdengine.url}")
|
|
@Value("${spring.datasource.dynamic.datasource.tdengine.url}")
|
|
private String url;
|
|
private String url;
|
|
|
|
|
|
@@ -37,39 +31,25 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) {
|
|
public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) {
|
|
// 1. 解析物模型,获得字段列表
|
|
// 1. 解析物模型,获得字段列表
|
|
List<TdFieldDO> schemaFields = new ArrayList<>();
|
|
List<TdFieldDO> schemaFields = new ArrayList<>();
|
|
- schemaFields.add(TdFieldDO.builder().
|
|
|
|
- fieldName("time").
|
|
|
|
- dataType("TIMESTAMP").
|
|
|
|
- build());
|
|
|
|
|
|
+ schemaFields.add(TdFieldDO.builder()
|
|
|
|
+ .fieldName("time")
|
|
|
|
+ .dataType("TIMESTAMP")
|
|
|
|
+ .build());
|
|
schemaFields.addAll(FieldParser.parse(thingModel));
|
|
schemaFields.addAll(FieldParser.parse(thingModel));
|
|
|
|
|
|
// 3. 设置超级表的标签
|
|
// 3. 设置超级表的标签
|
|
- List<TdFieldDO> tagsFields = new ArrayList<>();
|
|
|
|
- tagsFields.add(TdFieldDO.builder().
|
|
|
|
- fieldName("product_key").
|
|
|
|
- dataType("NCHAR").
|
|
|
|
- dataLength(64).
|
|
|
|
- build());
|
|
|
|
- tagsFields.add(TdFieldDO.builder().
|
|
|
|
- fieldName("device_key").
|
|
|
|
- dataType("NCHAR").
|
|
|
|
- dataLength(64).
|
|
|
|
- build());
|
|
|
|
- tagsFields.add(TdFieldDO.builder().
|
|
|
|
- fieldName("device_name").
|
|
|
|
- dataType("NCHAR").
|
|
|
|
- dataLength(64).
|
|
|
|
- build());
|
|
|
|
- tagsFields.add(TdFieldDO.builder().
|
|
|
|
- fieldName("device_type").
|
|
|
|
- dataType("INT").
|
|
|
|
- build());
|
|
|
|
|
|
+ List<TdFieldDO> tagsFields = Arrays.asList(
|
|
|
|
+ TdFieldDO.builder().fieldName("product_key").dataType("NCHAR").dataLength(64).build(),
|
|
|
|
+ TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build(),
|
|
|
|
+ TdFieldDO.builder().fieldName("device_name").dataType("NCHAR").dataLength(64).build(),
|
|
|
|
+ TdFieldDO.builder().fieldName("device_type").dataType("INT").build()
|
|
|
|
+ );
|
|
|
|
|
|
// 4. 获取超级表的名称
|
|
// 4. 获取超级表的名称
|
|
String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey());
|
|
String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey());
|
|
|
|
|
|
// 5. 创建超级表
|
|
// 5. 创建超级表
|
|
- String dataBaseName = url.substring(url.lastIndexOf("/") + 1);
|
|
|
|
|
|
+ String dataBaseName = getDatabaseName();
|
|
iotTdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName);
|
|
iotTdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -81,7 +61,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
List<TdFieldDO> newFields = FieldParser.parse(thingModel);
|
|
List<TdFieldDO> newFields = FieldParser.parse(thingModel);
|
|
|
|
|
|
updateTableFields(tbName, oldFields, newFields);
|
|
updateTableFields(tbName, oldFields, newFields);
|
|
- } catch (Throwable e) {
|
|
|
|
|
|
+ } catch (Exception e) {
|
|
log.error("更新物模型超级表失败", e);
|
|
log.error("更新物模型超级表失败", e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -90,14 +70,15 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
private List<TdFieldDO> getTableFields(String tableName) {
|
|
private List<TdFieldDO> getTableFields(String tableName) {
|
|
List<TdFieldDO> fields = new ArrayList<>();
|
|
List<TdFieldDO> fields = new ArrayList<>();
|
|
// 获取超级表的描述信息
|
|
// 获取超级表的描述信息
|
|
- List<Map<String, Object>> maps = iotTdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), tableName);
|
|
|
|
|
|
+ List<Map<String, Object>> maps = iotTdEngineService.describeSuperTable(getDatabaseName(), tableName);
|
|
if (maps != null) {
|
|
if (maps != null) {
|
|
- // 过滤掉 note 字段为 TAG 的记录
|
|
|
|
- maps = maps.stream().filter(map -> !"TAG".equals(map.get("note"))).toList();
|
|
|
|
- // 过滤掉 time 字段
|
|
|
|
- maps = maps.stream().filter(map -> !"time".equals(map.get("field"))).toList();
|
|
|
|
|
|
+ // 过滤掉 note 字段为 TAG 的记录和 time 字段
|
|
|
|
+ List<Map<String, Object>> filteredMaps = maps.stream()
|
|
|
|
+ .filter(map -> !"TAG".equals(map.get("note")))
|
|
|
|
+ .filter(map -> !"time".equals(map.get("field")))
|
|
|
|
+ .toList();
|
|
// 解析字段信息
|
|
// 解析字段信息
|
|
- fields = FieldParser.parse(maps.stream()
|
|
|
|
|
|
+ fields = FieldParser.parse(filteredMaps.stream()
|
|
.map(map -> List.of(map.get("field"), map.get("type"), map.get("length")))
|
|
.map(map -> List.of(map.get("field"), map.get("type"), map.get("length")))
|
|
.collect(Collectors.toList()));
|
|
.collect(Collectors.toList()));
|
|
}
|
|
}
|
|
@@ -113,7 +94,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
// 获取删除字段
|
|
// 获取删除字段
|
|
List<TdFieldDO> dropFields = getDropFields(oldFields, newFields);
|
|
List<TdFieldDO> dropFields = getDropFields(oldFields, newFields);
|
|
|
|
|
|
- String dataBaseName = url.substring(url.lastIndexOf("/") + 1);
|
|
|
|
|
|
+ String dataBaseName = getDatabaseName();
|
|
// 添加新增字段
|
|
// 添加新增字段
|
|
if (CollUtil.isNotEmpty(addFields)) {
|
|
if (CollUtil.isNotEmpty(addFields)) {
|
|
iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, addFields);
|
|
iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, addFields);
|
|
@@ -131,25 +112,37 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
|
|
|
|
// 获取新增字段
|
|
// 获取新增字段
|
|
private List<TdFieldDO> getAddFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
|
private List<TdFieldDO> getAddFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
|
|
|
+ Set<String> oldFieldNames = oldFields.stream()
|
|
|
|
+ .map(TdFieldDO::getFieldName)
|
|
|
|
+ .collect(Collectors.toSet());
|
|
return newFields.stream()
|
|
return newFields.stream()
|
|
- .filter(f -> oldFields.stream().noneMatch(old -> old.getFieldName().equals(f.getFieldName())))
|
|
|
|
|
|
+ .filter(f -> !oldFieldNames.contains(f.getFieldName()))
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
}
|
|
}
|
|
|
|
|
|
// 获取修改字段
|
|
// 获取修改字段
|
|
private List<TdFieldDO> getModifyFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
|
private List<TdFieldDO> getModifyFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
|
|
|
+ Map<String, TdFieldDO> oldFieldMap = oldFields.stream()
|
|
|
|
+ .collect(Collectors.toMap(TdFieldDO::getFieldName, f -> f));
|
|
|
|
+
|
|
return newFields.stream()
|
|
return newFields.stream()
|
|
- .filter(f -> oldFields.stream().anyMatch(old ->
|
|
|
|
- old.getFieldName().equals(f.getFieldName()) &&
|
|
|
|
- (!old.getDataType().equals(f.getDataType()) || !Objects.equals(old.getDataLength(), f.getDataLength()))))
|
|
|
|
|
|
+ .filter(f -> {
|
|
|
|
+ TdFieldDO oldField = oldFieldMap.get(f.getFieldName());
|
|
|
|
+ return oldField != null &&
|
|
|
|
+ (!oldField.getDataType().equals(f.getDataType()) ||
|
|
|
|
+ !Objects.equals(oldField.getDataLength(), f.getDataLength()));
|
|
|
|
+ })
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
}
|
|
}
|
|
|
|
|
|
// 获取删除字段
|
|
// 获取删除字段
|
|
private List<TdFieldDO> getDropFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
|
private List<TdFieldDO> getDropFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) {
|
|
|
|
+ Set<String> newFieldNames = newFields.stream()
|
|
|
|
+ .map(TdFieldDO::getFieldName)
|
|
|
|
+ .collect(Collectors.toSet());
|
|
return oldFields.stream()
|
|
return oldFields.stream()
|
|
- .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName()) &&
|
|
|
|
- newFields.stream().noneMatch(n -> n.getFieldName().equals(f.getFieldName())))
|
|
|
|
|
|
+ .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName()))
|
|
|
|
+ .filter(f -> !newFieldNames.contains(f.getFieldName()))
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
}
|
|
}
|
|
|
|
|
|
@@ -157,13 +150,13 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
public void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) {
|
|
public void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) {
|
|
ThingModelRespVO thingModel = buildThingModel(product, functionList);
|
|
ThingModelRespVO thingModel = buildThingModel(product, functionList);
|
|
|
|
|
|
- if (thingModel.getModel().getProperties().isEmpty()) {
|
|
|
|
|
|
+ if (thingModel.getModel() == null || CollUtil.isEmpty(thingModel.getModel().getProperties())) {
|
|
log.warn("物模型属性列表为空,不创建超级表");
|
|
log.warn("物模型属性列表为空,不创建超级表");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey());
|
|
String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey());
|
|
- String dataBaseName = url.substring(url.lastIndexOf("/") + 1);
|
|
|
|
|
|
+ String dataBaseName = getDatabaseName();
|
|
Integer tableExists = iotTdEngineService.checkSuperTableExists(dataBaseName, superTableName);
|
|
Integer tableExists = iotTdEngineService.checkSuperTableExists(dataBaseName, superTableName);
|
|
|
|
|
|
if (tableExists != null && tableExists > 0) {
|
|
if (tableExists != null && tableExists > 0) {
|
|
@@ -180,7 +173,8 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
|
|
|
|
ThingModelRespVO.Model model = new ThingModelRespVO.Model();
|
|
ThingModelRespVO.Model model = new ThingModelRespVO.Model();
|
|
List<ThingModelProperty> properties = functionList.stream()
|
|
List<ThingModelProperty> properties = functionList.stream()
|
|
- .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals(IotProductFunctionTypeEnum.valueOf(function.getType())))
|
|
|
|
|
|
+ .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals(
|
|
|
|
+ IotProductFunctionTypeEnum.valueOfType(function.getType())))
|
|
.map(this::buildThingModelProperty)
|
|
.map(this::buildThingModelProperty)
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
@@ -191,14 +185,15 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
}
|
|
}
|
|
|
|
|
|
private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) {
|
|
private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) {
|
|
- ThingModelProperty property = new ThingModelProperty();
|
|
|
|
- property.setIdentifier(function.getIdentifier());
|
|
|
|
- property.setName(function.getName());
|
|
|
|
- property.setDescription(function.getDescription());
|
|
|
|
|
|
+ ThingModelProperty property = BeanUtil.copyProperties(function, ThingModelProperty.class);
|
|
property.setDataType(function.getProperty().getDataType());
|
|
property.setDataType(function.getProperty().getDataType());
|
|
return property;
|
|
return property;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private String getDatabaseName() {
|
|
|
|
+ return url.substring(url.lastIndexOf("/") + 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
static String getProductPropertySTableName(Integer deviceType, String productKey) {
|
|
static String getProductPropertySTableName(Integer deviceType, String productKey) {
|
|
return switch (deviceType) {
|
|
return switch (deviceType) {
|
|
case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase();
|
|
case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase();
|
|
@@ -207,7 +202,4 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
- static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) {
|
|
|
|
- return String.format("%s_%s_%s", deviceType, productKey, deviceKey).toLowerCase();
|
|
|
|
- }
|
|
|
|
}
|
|
}
|