Commit 3524bfd3b3e1d43d48860e330bf7f098f5763ea4
Merge remote-tracking branch 'yudao/feature/iot' into iot
# Conflicts: # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java
Showing
31 changed files
with
508 additions
and
461 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.enums.thingmodel; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Getter; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * IoT 数据定义的数据类型枚举类 | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +@AllArgsConstructor | |
| 12 | +@Getter | |
| 13 | +public enum IotDataSpecsDataTypeEnum { | |
| 14 | + | |
| 15 | + INT("int"), | |
| 16 | + FLOAT("float"), | |
| 17 | + DOUBLE("double"), | |
| 18 | + ENUM("enum"), | |
| 19 | + BOOL("bool"), | |
| 20 | + TEXT("text"), | |
| 21 | + DATE("date"), | |
| 22 | + STRUCT("struct"), | |
| 23 | + ARRAY("array"); | |
| 24 | + | |
| 25 | + private final String dataType; | |
| 26 | + | |
| 27 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.api.device; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; | |
| 3 | +import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | |
| 4 | 4 | import org.springframework.stereotype.Service; |
| 5 | 5 | import org.springframework.validation.annotation.Validated; |
| 6 | 6 | |
| ... | ... | @@ -14,7 +14,7 @@ import javax.annotation.Resource; |
| 14 | 14 | public class DeviceDataApiImpl implements DeviceDataApi { |
| 15 | 15 | |
| 16 | 16 | @Resource |
| 17 | - private IotDeviceDataService deviceDataService; | |
| 17 | + private IotDevicePropertyDataService deviceDataService; | |
| 18 | 18 | |
| 19 | 19 | @Override |
| 20 | 20 | public void saveDeviceData(String productKey, String deviceName, String message) { | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java
| ... | ... | @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDevi |
| 7 | 7 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; |
| 9 | 9 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotTimeDataRespVO; |
| 10 | -import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; | |
| 10 | +import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | |
| 11 | 11 | import io.swagger.v3.oas.annotations.Operation; |
| 12 | 12 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 13 | 13 | import jakarta.annotation.Resource; |
| ... | ... | @@ -29,7 +29,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 29 | 29 | public class IotDeviceDataController { |
| 30 | 30 | |
| 31 | 31 | @Resource |
| 32 | - private IotDeviceDataService deviceDataService; | |
| 32 | + private IotDevicePropertyDataService deviceDataService; | |
| 33 | 33 | |
| 34 | 34 | // TODO @浩浩:这里的 /latest-list,包括方法名。 |
| 35 | 35 | @GetMapping("/latest") | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java
| ... | ... | @@ -31,7 +31,8 @@ public class ThingModelProperty { |
| 31 | 31 | private String description; |
| 32 | 32 | /** |
| 33 | 33 | * 云端可以对该属性进行的操作类型 |
| 34 | - * 关联枚举 {@link IotProductThingModelAccessModeEnum} | |
| 34 | + * | |
| 35 | + * 枚举 {@link IotProductThingModelAccessModeEnum} | |
| 35 | 36 | */ |
| 36 | 37 | private String accessMode; |
| 37 | 38 | /** |
| ... | ... | @@ -43,6 +44,8 @@ public class ThingModelProperty { |
| 43 | 44 | private Boolean required; |
| 44 | 45 | /** |
| 45 | 46 | * 数据类型,与 dataSpecs 的 dataType 保持一致 |
| 47 | + * | |
| 48 | + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum} | |
| 46 | 49 | */ |
| 47 | 50 | private String dataType; |
| 48 | 51 | /** | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java
| ... | ... | @@ -16,6 +16,7 @@ public class FieldParser { |
| 16 | 16 | /** |
| 17 | 17 | * 物模型到td数据类型映射 |
| 18 | 18 | */ |
| 19 | + @Deprecated | |
| 19 | 20 | private static final HashMap<String, String> TYPE_MAPPING = new HashMap<>() { |
| 20 | 21 | { |
| 21 | 22 | put("INT", "INT"); |
| ... | ... | @@ -74,6 +75,7 @@ public class FieldParser { |
| 74 | 75 | /** |
| 75 | 76 | * 获取字段字义 |
| 76 | 77 | */ |
| 78 | + @Deprecated | |
| 77 | 79 | public static String getFieldDefine(TdFieldDO field) { |
| 78 | 80 | return "`" + field.getFieldName() + "`" + " " |
| 79 | 81 | + (field.getDataLength() > 0 ? String.format("%s(%d)", field.getDataType(), field.getDataLength()) | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java
| ... | ... | @@ -2,13 +2,12 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; |
| 2 | 2 | |
| 3 | 3 | import lombok.Data; |
| 4 | 4 | |
| 5 | -import java.util.Set; | |
| 6 | - | |
| 7 | 5 | // TODO @haohao:类似这个,其实可以参考 mybatis plus,querywrapper,搞个 TdEngineQueryWrapper。这样看起来会更好懂。 |
| 8 | 6 | /** |
| 9 | 7 | * 查询DO |
| 10 | 8 | */ |
| 11 | 9 | @Data |
| 10 | +@Deprecated | |
| 12 | 11 | public class SelectDO { |
| 13 | 12 | |
| 14 | 13 | // TODO @haoha:database 是个单词 | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java
| ... | ... | @@ -5,6 +5,7 @@ import lombok.Builder; |
| 5 | 5 | import lombok.Data; |
| 6 | 6 | import lombok.NoArgsConstructor; |
| 7 | 7 | |
| 8 | +// TODO 芋艿:看看是不是后续简化掉。 | |
| 8 | 9 | /** |
| 9 | 10 | * TD 引擎的字段 |
| 10 | 11 | */ |
| ... | ... | @@ -12,6 +13,7 @@ import lombok.NoArgsConstructor; |
| 12 | 13 | @NoArgsConstructor |
| 13 | 14 | @AllArgsConstructor |
| 14 | 15 | @Builder |
| 16 | +@Deprecated | |
| 15 | 17 | public class TdFieldDO { |
| 16 | 18 | |
| 17 | 19 | /** | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 6 | 6 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 7 | 7 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 9 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |
| 9 | 10 | import org.apache.ibatis.annotations.Mapper; |
| 10 | 11 | |
| 11 | 12 | import java.util.List; |
| ... | ... | @@ -47,7 +48,8 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> { |
| 47 | 48 | } |
| 48 | 49 | |
| 49 | 50 | default IotDeviceDO selectByDeviceKey(String deviceKey) { |
| 50 | - return selectOne(IotDeviceDO::getDeviceKey, deviceKey); | |
| 51 | + return selectOne(new LambdaQueryWrapper<IotDeviceDO>() | |
| 52 | + .apply("LOWER(device_key) = {0}", deviceKey.toLowerCase())); | |
| 51 | 53 | } |
| 52 | 54 | |
| 53 | 55 | default List<IotDeviceDO> selectList(Integer deviceType) { | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java
| ... | ... | @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | 6 | import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; |
| 8 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |
| 8 | 9 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 10 | |
| 10 | 11 | /** |
| ... | ... | @@ -23,7 +24,8 @@ public interface IotProductMapper extends BaseMapperX<IotProductDO> { |
| 23 | 24 | } |
| 24 | 25 | |
| 25 | 26 | default IotProductDO selectByProductKey(String productKey) { |
| 26 | - return selectOne(IotProductDO::getProductKey, productKey); | |
| 27 | + return selectOne(new LambdaQueryWrapper<IotProductDO>() | |
| 28 | + .apply("LOWER(product_key) = {0}", productKey.toLowerCase())); | |
| 27 | 29 | } |
| 28 | 30 | |
| 29 | 31 | } |
| 30 | 32 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.tdengine; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.ObjectUtil; | |
| 5 | +import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; | |
| 6 | +import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; | |
| 7 | +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; | |
| 8 | +import org.apache.ibatis.annotations.Mapper; | |
| 9 | +import org.apache.ibatis.annotations.Param; | |
| 10 | + | |
| 11 | +import java.util.ArrayList; | |
| 12 | +import java.util.List; | |
| 13 | +import java.util.stream.Collectors; | |
| 14 | + | |
| 15 | +@Mapper | |
| 16 | +@TDengineDS | |
| 17 | +@InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 | |
| 18 | +public interface IotDevicePropertyDataMapper { | |
| 19 | + | |
| 20 | + List<TDengineTableField> getProductPropertySTableFieldList(@Param("productKey") String productKey); | |
| 21 | + | |
| 22 | + void createProductPropertySTable(@Param("productKey") String productKey, | |
| 23 | + @Param("fields") List<TDengineTableField> fields); | |
| 24 | + | |
| 25 | + @SuppressWarnings("SimplifyStreamApiCallChains") // 保持 JDK8 兼容性 | |
| 26 | + default void alterProductPropertySTable(String productKey, | |
| 27 | + List<TDengineTableField> oldFields, | |
| 28 | + List<TDengineTableField> newFields) { | |
| 29 | + oldFields.removeIf(field -> TDengineTableField.FIELD_TS.equals(field.getField()) | |
| 30 | + || TDengineTableField.FIELD_DEVICE_KEY.equals(field.getField())); | |
| 31 | + List<TDengineTableField> addFields = newFields.stream().filter( // 新增的字段 | |
| 32 | + newField -> oldFields.stream().noneMatch(oldField -> oldField.getField().equals(newField.getField()))) | |
| 33 | + .collect(Collectors.toList()); | |
| 34 | + List<TDengineTableField> dropFields = oldFields.stream().filter( // 删除的字段 | |
| 35 | + oldField -> newFields.stream().noneMatch(n -> n.getField().equals(oldField.getField()))) | |
| 36 | + .collect(Collectors.toList()); | |
| 37 | + List<TDengineTableField> modifyTypeFields = new ArrayList<>(); // 变更类型的字段 | |
| 38 | + List<TDengineTableField> modifyLengthFields = new ArrayList<>(); // 变更长度的字段 | |
| 39 | + newFields.forEach(newField -> { | |
| 40 | + TDengineTableField oldField = CollUtil.findOne(oldFields, field -> field.getField().equals(newField.getField())); | |
| 41 | + if (oldField == null) { | |
| 42 | + return; | |
| 43 | + } | |
| 44 | + if (ObjectUtil.notEqual(oldField.getType(), newField.getType())) { | |
| 45 | + modifyTypeFields.add(newField); | |
| 46 | + return; | |
| 47 | + } | |
| 48 | + if (newField.getLength()!= null) { | |
| 49 | + if (newField.getLength() > oldField.getLength()) { | |
| 50 | + modifyLengthFields.add(newField); | |
| 51 | + } else if (newField.getLength() < oldField.getLength()) { | |
| 52 | + // 特殊:TDengine 长度修改时,只允许变长,所以此时认为是修改类型 | |
| 53 | + modifyTypeFields.add(newField); | |
| 54 | + } | |
| 55 | + } | |
| 56 | + }); | |
| 57 | + | |
| 58 | + // 执行 | |
| 59 | + addFields.forEach(field -> alterProductPropertySTableAddField(productKey, field)); | |
| 60 | + dropFields.forEach(field -> alterProductPropertySTableDropField(productKey, field)); | |
| 61 | + modifyLengthFields.forEach(field -> alterProductPropertySTableModifyField(productKey, field)); | |
| 62 | + modifyTypeFields.forEach(field -> { | |
| 63 | + alterProductPropertySTableDropField(productKey, field); | |
| 64 | + alterProductPropertySTableAddField(productKey, field); | |
| 65 | + }); | |
| 66 | + } | |
| 67 | + | |
| 68 | + void alterProductPropertySTableAddField(@Param("productKey") String productKey, | |
| 69 | + @Param("field") TDengineTableField field); | |
| 70 | + | |
| 71 | + void alterProductPropertySTableModifyField(@Param("productKey") String productKey, | |
| 72 | + @Param("field") TDengineTableField field); | |
| 73 | + | |
| 74 | + void alterProductPropertySTableDropField(@Param("productKey") String productKey, | |
| 75 | + @Param("field") TDengineTableField field); | |
| 76 | + | |
| 77 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.emq.service; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 4 | -import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; | |
| 3 | +import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | |
| 5 | 4 | import jakarta.annotation.Resource; |
| 6 | 5 | import lombok.extern.slf4j.Slf4j; |
| 7 | 6 | import org.eclipse.paho.client.mqttv3.MqttClient; |
| ... | ... | @@ -21,7 +20,7 @@ import org.springframework.stereotype.Service; |
| 21 | 20 | public class EmqxServiceImpl implements EmqxService { |
| 22 | 21 | |
| 23 | 22 | @Resource |
| 24 | - private IotDeviceDataService iotDeviceDataService; | |
| 23 | + private IotDevicePropertyDataService iotDeviceDataService; | |
| 25 | 24 | |
| 26 | 25 | // TODO 多线程处理消息 |
| 27 | 26 | @Override | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.framework.tdengine.core; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.NoArgsConstructor; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * TDEngine 表字段 | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +@NoArgsConstructor | |
| 12 | +@AllArgsConstructor | |
| 13 | +public class TDengineTableField { | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * 字段名 - TDengine 默认 ts 字段,默认会被 TDengine 创建 | |
| 17 | + */ | |
| 18 | + public static final String FIELD_TS = "ts"; | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * 字段名 - 我们系统定义的 device_key 字段,非 TDengine 默认字段 | |
| 22 | + */ | |
| 23 | + public static final String FIELD_DEVICE_KEY = "device_key"; | |
| 24 | + | |
| 25 | + public static final String TYPE_TINYINT = "TINYINT"; | |
| 26 | + public static final String TYPE_INT = "INT"; | |
| 27 | + public static final String TYPE_FLOAT = "FLOAT"; | |
| 28 | + public static final String TYPE_DOUBLE = "DOUBLE"; | |
| 29 | + public static final String TYPE_BOOL = "BOOL"; | |
| 30 | + public static final String TYPE_NCHAR = "NCHAR"; | |
| 31 | + public static final String TYPE_TIMESTAMP = "TIMESTAMP"; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 注释 - TAG 字段 | |
| 35 | + */ | |
| 36 | + public static final String NOTE_TAG = "TAG"; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 字段名 | |
| 40 | + */ | |
| 41 | + private String field; | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * 字段类型 | |
| 45 | + */ | |
| 46 | + private String type; | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 字段长度 | |
| 50 | + */ | |
| 51 | + private Integer length; | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 注释 | |
| 55 | + */ | |
| 56 | + private String note; | |
| 57 | + | |
| 58 | + public TDengineTableField(String field, String type) { | |
| 59 | + this.field = field; | |
| 60 | + this.type = type; | |
| 61 | + } | |
| 62 | + | |
| 63 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/annotation/TDengineDS.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation; | |
| 2 | + | |
| 3 | +import com.baomidou.dynamic.datasource.annotation.DS; | |
| 4 | + | |
| 5 | +import java.lang.annotation.*; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * TDEngine 数据源 | |
| 9 | + * | |
| 10 | + * @author 芋道源码 | |
| 11 | + */ | |
| 12 | +@Target({ElementType.TYPE, ElementType.METHOD}) | |
| 13 | +@Retention(RetentionPolicy.RUNTIME) | |
| 14 | +@Documented | |
| 15 | +@DS("tdengine") | |
| 16 | +public @interface TDengineDS { | |
| 17 | +} | |
| 0 | 18 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/package-info.java
0 → 100644
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.service.device; | |
| 2 | - | |
| 3 | -import cn.hutool.core.date.DateUtil; | |
| 4 | -import cn.hutool.core.util.StrUtil; | |
| 5 | -import cn.hutool.json.JSONObject; | |
| 6 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 7 | -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; | |
| 8 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | |
| 9 | -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | |
| 10 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; | |
| 11 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | |
| 12 | -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; | |
| 13 | -import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; | |
| 14 | -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; | |
| 15 | -import cn.iocoder.yudao.module.iot.enums.IotConstants; | |
| 16 | -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; | |
| 17 | -import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; | |
| 18 | -import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; | |
| 19 | -import jakarta.annotation.Resource; | |
| 20 | -import jakarta.validation.Valid; | |
| 21 | -import lombok.extern.slf4j.Slf4j; | |
| 22 | -import org.springframework.beans.factory.annotation.Value; | |
| 23 | -import org.springframework.stereotype.Service; | |
| 24 | - | |
| 25 | -import java.time.ZoneId; | |
| 26 | -import java.util.ArrayList; | |
| 27 | -import java.util.HashMap; | |
| 28 | -import java.util.List; | |
| 29 | -import java.util.Map; | |
| 30 | - | |
| 31 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | |
| 32 | - | |
| 33 | -@Slf4j | |
| 34 | -@Service | |
| 35 | -public class IotDeviceDataServiceImpl implements IotDeviceDataService { | |
| 36 | - | |
| 37 | - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") | |
| 38 | - private String url; | |
| 39 | - | |
| 40 | - @Resource | |
| 41 | - private IotDeviceService deviceService; | |
| 42 | - @Resource | |
| 43 | - private IotThingModelMessageService thingModelMessageService; | |
| 44 | - @Resource | |
| 45 | - private IotProductThingModelService thingModelService; | |
| 46 | - @Resource | |
| 47 | - private TdEngineDMLMapper tdEngineDMLMapper; | |
| 48 | - | |
| 49 | - @Resource | |
| 50 | - private DeviceDataRedisDAO deviceDataRedisDAO; | |
| 51 | - | |
| 52 | - @Override | |
| 53 | - public void saveDeviceData(String productKey, String deviceName, String message) { | |
| 54 | - // 1. 根据产品 key 和设备名称,获得设备信息 | |
| 55 | - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(productKey, deviceName); | |
| 56 | - // 2. 解析消息,保存数据 | |
| 57 | - JSONObject jsonObject = new JSONObject(message); | |
| 58 | - log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", productKey, deviceName, jsonObject); | |
| 59 | - ThingModelMessage thingModelMessage = ThingModelMessage.builder() | |
| 60 | - .id(jsonObject.getStr("id")) | |
| 61 | - .sys(jsonObject.get("sys")) | |
| 62 | - .method(jsonObject.getStr("method")) | |
| 63 | - .params(jsonObject.get("params")) | |
| 64 | - .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time")) | |
| 65 | - .productKey(productKey) | |
| 66 | - .deviceName(deviceName) | |
| 67 | - .deviceKey(device.getDeviceKey()) | |
| 68 | - .build(); | |
| 69 | - thingModelMessageService.saveThingModelMessage(device, thingModelMessage); | |
| 70 | - } | |
| 71 | - | |
| 72 | - @Override | |
| 73 | - public List<IotDeviceDataDO> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { | |
| 74 | - List<IotDeviceDataDO> list = new ArrayList<>(); | |
| 75 | - // 1. 获取设备信息 | |
| 76 | - IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); | |
| 77 | - // 2. 获取设备属性最新数据 | |
| 78 | - List<IotProductThingModelDO> thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey()); | |
| 79 | - thingModelList = filterList(thingModelList, thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType() | |
| 80 | - .equals(thingModel.getType())); | |
| 81 | - | |
| 82 | - // 3. 过滤标识符和属性名称 | |
| 83 | - if (deviceDataReqVO.getIdentifier() != null) { | |
| 84 | - thingModelList = filterList(thingModelList, thingModel -> thingModel.getIdentifier() | |
| 85 | - .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())); | |
| 86 | - } | |
| 87 | - if (deviceDataReqVO.getName() != null) { | |
| 88 | - thingModelList = filterList(thingModelList, thingModel -> thingModel.getName() | |
| 89 | - .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())); | |
| 90 | - } | |
| 91 | - // 4. 获取设备属性最新数据 | |
| 92 | - thingModelList.forEach(thingModel -> { | |
| 93 | - IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thingModel.getIdentifier()); | |
| 94 | - if (deviceData == null) { | |
| 95 | - deviceData = new IotDeviceDataDO(); | |
| 96 | - deviceData.setProductKey(device.getProductKey()); | |
| 97 | - deviceData.setDeviceName(device.getDeviceName()); | |
| 98 | - deviceData.setIdentifier(thingModel.getIdentifier()); | |
| 99 | - deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); | |
| 100 | - deviceData.setThingModelId(thingModel.getId()); | |
| 101 | - deviceData.setName(thingModel.getName()); | |
| 102 | - deviceData.setDataType(thingModel.getProperty().getDataType()); | |
| 103 | - } | |
| 104 | - list.add(deviceData); | |
| 105 | - }); | |
| 106 | - return list; | |
| 107 | - } | |
| 108 | - | |
| 109 | - @Override | |
| 110 | - public PageResult<Map<String, Object>> getHistoryDeviceProperties(IotDeviceDataPageReqVO deviceDataReqVO) { | |
| 111 | - PageResult<Map<String, Object>> pageResult = new PageResult<>(); | |
| 112 | - // 1. 获取设备信息 | |
| 113 | - IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); | |
| 114 | - // 2. 获取设备属性历史数据 | |
| 115 | - SelectVisualDO selectVisualDO = new SelectVisualDO(); | |
| 116 | - selectVisualDO.setDataBaseName(getDatabaseName()); | |
| 117 | - selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); | |
| 118 | - selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier()); | |
| 119 | - selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); | |
| 120 | - selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); | |
| 121 | - Map<String, Object> params = new HashMap<>(); | |
| 122 | - params.put("rows", deviceDataReqVO.getPageSize()); | |
| 123 | - params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); | |
| 124 | - selectVisualDO.setParams(params); | |
| 125 | - pageResult.setList(tdEngineDMLMapper.selectHistoryDataList(selectVisualDO)); | |
| 126 | - pageResult.setTotal(tdEngineDMLMapper.selectHistoryCount(selectVisualDO)); | |
| 127 | - return pageResult; | |
| 128 | - } | |
| 129 | - | |
| 130 | - private String getDatabaseName() { | |
| 131 | - return StrUtil.subAfter(url, "/", true); | |
| 132 | - } | |
| 133 | - | |
| 134 | - private static String getDeviceTableName(String productKey, String deviceName) { | |
| 135 | - return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey, deviceName); | |
| 136 | - } | |
| 137 | - | |
| 138 | -} | |
| 139 | 0 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java
| ... | ... | @@ -9,11 +9,18 @@ import java.util.List; |
| 9 | 9 | import java.util.Map; |
| 10 | 10 | |
| 11 | 11 | /** |
| 12 | - * IoT 设备数据 Service 接口 | |
| 12 | + * IoT 设备【属性】数据 Service 接口 | |
| 13 | 13 | * |
| 14 | 14 | * @author 芋道源码 |
| 15 | 15 | */ |
| 16 | -public interface IotDeviceDataService { | |
| 16 | +public interface IotDevicePropertyDataService { | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 定义设备属性数据的结构 | |
| 20 | + * | |
| 21 | + * @param productId 产品编号 | |
| 22 | + */ | |
| 23 | + void defineDevicePropertyData(Long productId); | |
| 17 | 24 | |
| 18 | 25 | /** |
| 19 | 26 | * 保存设备数据 |
| ... | ... | @@ -40,4 +47,5 @@ public interface IotDeviceDataService { |
| 40 | 47 | * @return 设备属性历史数据 |
| 41 | 48 | */ |
| 42 | 49 | PageResult<Map<String, Object>> getHistoryDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO); |
| 50 | + | |
| 43 | 51 | } |
| 44 | 52 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.device; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.date.DateUtil; | |
| 5 | +import cn.hutool.core.map.MapUtil; | |
| 6 | +import cn.hutool.core.util.StrUtil; | |
| 7 | +import cn.hutool.json.JSONObject; | |
| 8 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 9 | +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; | |
| 10 | +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; | |
| 11 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | |
| 12 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | |
| 13 | +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | |
| 14 | +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; | |
| 15 | +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | |
| 16 | +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; | |
| 17 | +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; | |
| 18 | +import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; | |
| 19 | +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; | |
| 20 | +import cn.iocoder.yudao.module.iot.enums.IotConstants; | |
| 21 | +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; | |
| 22 | +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; | |
| 23 | +import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; | |
| 24 | +import cn.iocoder.yudao.module.iot.service.product.IotProductService; | |
| 25 | +import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; | |
| 26 | +import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; | |
| 27 | +import jakarta.annotation.Resource; | |
| 28 | +import jakarta.validation.Valid; | |
| 29 | +import lombok.extern.slf4j.Slf4j; | |
| 30 | +import org.springframework.beans.factory.annotation.Value; | |
| 31 | +import org.springframework.stereotype.Service; | |
| 32 | + | |
| 33 | +import java.time.ZoneId; | |
| 34 | +import java.util.ArrayList; | |
| 35 | +import java.util.HashMap; | |
| 36 | +import java.util.List; | |
| 37 | +import java.util.Map; | |
| 38 | + | |
| 39 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 40 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | |
| 41 | + | |
| 42 | +/** | |
| 43 | + * IoT 设备【属性】数据 Service 实现类 | |
| 44 | + * | |
| 45 | + * @author 芋道源码 | |
| 46 | + */ | |
| 47 | +@Service | |
| 48 | +@Slf4j | |
| 49 | +public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataService { | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * 物模型的数据类型,与 TDengine 数据类型的映射关系 | |
| 53 | + */ | |
| 54 | + private static final Map<String, String> TYPE_MAPPING = MapUtil.<String, String>builder() | |
| 55 | + .put(IotDataSpecsDataTypeEnum.INT.getDataType(), TDengineTableField.TYPE_INT) | |
| 56 | + .put(IotDataSpecsDataTypeEnum.FLOAT.getDataType(), TDengineTableField.TYPE_FLOAT) | |
| 57 | + .put(IotDataSpecsDataTypeEnum.DOUBLE.getDataType(), TDengineTableField.TYPE_DOUBLE) | |
| 58 | + .put(IotDataSpecsDataTypeEnum.ENUM.getDataType(), TDengineTableField.TYPE_TINYINT) // TODO 芋艿:为什么要映射为 TINYINT 的说明? | |
| 59 | + .put( IotDataSpecsDataTypeEnum.BOOL.getDataType(), TDengineTableField.TYPE_TINYINT) // TODO 芋艿:为什么要映射为 TINYINT 的说明? | |
| 60 | + .put(IotDataSpecsDataTypeEnum.TEXT.getDataType(), TDengineTableField.TYPE_NCHAR) | |
| 61 | + .put(IotDataSpecsDataTypeEnum.DATE.getDataType(), TDengineTableField.TYPE_TIMESTAMP) | |
| 62 | + .put(IotDataSpecsDataTypeEnum.STRUCT.getDataType(), TDengineTableField.TYPE_NCHAR) // TODO 芋艿:怎么映射!!!! | |
| 63 | + .put(IotDataSpecsDataTypeEnum.ARRAY.getDataType(), TDengineTableField.TYPE_NCHAR) // TODO 芋艿:怎么映射!!!! | |
| 64 | + .build(); | |
| 65 | + | |
| 66 | + @Value("${spring.datasource.dynamic.datasource.tdengine.url}") | |
| 67 | + private String url; | |
| 68 | + | |
| 69 | + @Resource | |
| 70 | + private IotDeviceService deviceService; | |
| 71 | + @Resource | |
| 72 | + private IotThingModelMessageService thingModelMessageService; | |
| 73 | + @Resource | |
| 74 | + private IotProductThingModelService thingModelService; | |
| 75 | + @Resource | |
| 76 | + private IotProductService productService; | |
| 77 | + | |
| 78 | + @Resource | |
| 79 | + private TdEngineDMLMapper tdEngineDMLMapper; | |
| 80 | + | |
| 81 | + @Resource | |
| 82 | + private DeviceDataRedisDAO deviceDataRedisDAO; | |
| 83 | + | |
| 84 | + @Resource | |
| 85 | + private IotDevicePropertyDataMapper devicePropertyDataMapper; | |
| 86 | + | |
| 87 | + @Override | |
| 88 | + public void defineDevicePropertyData(Long productId) { | |
| 89 | + // 1.1 查询产品和物模型 | |
| 90 | + IotProductDO product = productService.validateProductExists(productId); | |
| 91 | + List<IotProductThingModelDO> thingModels = filterList(thingModelService.getProductThingModelListByProductId(productId), | |
| 92 | + thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); | |
| 93 | + // 1.2 解析 DB 里的字段 | |
| 94 | + List<TDengineTableField> oldFields = new ArrayList<>(); | |
| 95 | + try { | |
| 96 | + oldFields.addAll(devicePropertyDataMapper.getProductPropertySTableFieldList(product.getProductKey())); | |
| 97 | + } catch (Exception e) { | |
| 98 | + if (!e.getMessage().contains("Table does not exist")) { | |
| 99 | + throw e; | |
| 100 | + } | |
| 101 | + } | |
| 102 | + | |
| 103 | + // 2.1 情况一:如果是新增的时候,需要创建表 | |
| 104 | + List<TDengineTableField> newFields = buildTableFieldList(thingModels); | |
| 105 | + if (CollUtil.isEmpty(oldFields)) { | |
| 106 | + if (CollUtil.isEmpty(newFields)) { | |
| 107 | + log.info("[defineDevicePropertyData][productId({}) 没有需要定义的属性]", productId); | |
| 108 | + return; | |
| 109 | + } | |
| 110 | + newFields.add(0, new TDengineTableField(TDengineTableField.FIELD_TS, TDengineTableField.TYPE_TIMESTAMP)); | |
| 111 | + devicePropertyDataMapper.createProductPropertySTable(product.getProductKey(), newFields); | |
| 112 | + return; | |
| 113 | + } | |
| 114 | + // 2.2 情况二:如果是修改的时候,需要更新表 | |
| 115 | + devicePropertyDataMapper.alterProductPropertySTable(product.getProductKey(), oldFields, newFields); | |
| 116 | + } | |
| 117 | + | |
| 118 | + private List<TDengineTableField> buildTableFieldList(List<IotProductThingModelDO> thingModels) { | |
| 119 | + return convertList(thingModels, thingModel -> { | |
| 120 | + TDengineTableField field = new TDengineTableField( | |
| 121 | + StrUtil.toUnderlineCase(thingModel.getIdentifier()), // TDengine 字段默认都是小写 | |
| 122 | + TYPE_MAPPING.get(thingModel.getProperty().getDataType())); | |
| 123 | + if (thingModel.getProperty().getDataType().equals(IotDataSpecsDataTypeEnum.TEXT.getDataType())) { | |
| 124 | + field.setLength(((ThingModelDateOrTextDataSpecs) thingModel.getProperty().getDataSpecs()).getLength()); | |
| 125 | + } | |
| 126 | + return field; | |
| 127 | + }); | |
| 128 | + } | |
| 129 | + | |
| 130 | + @Override | |
| 131 | + public void saveDeviceData(String productKey, String deviceName, String message) { | |
| 132 | + // 1. 根据产品 key 和设备名称,获得设备信息 | |
| 133 | + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(productKey, deviceName); | |
| 134 | + // 2. 解析消息,保存数据 | |
| 135 | + JSONObject jsonObject = new JSONObject(message); | |
| 136 | + log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", productKey, deviceName, jsonObject); | |
| 137 | + ThingModelMessage thingModelMessage = ThingModelMessage.builder() | |
| 138 | + .id(jsonObject.getStr("id")) | |
| 139 | + .sys(jsonObject.get("sys")) | |
| 140 | + .method(jsonObject.getStr("method")) | |
| 141 | + .params(jsonObject.get("params")) | |
| 142 | + .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time")) | |
| 143 | + .productKey(productKey) | |
| 144 | + .deviceName(deviceName) | |
| 145 | + .deviceKey(device.getDeviceKey()) | |
| 146 | + .build(); | |
| 147 | + thingModelMessageService.saveThingModelMessage(device, thingModelMessage); | |
| 148 | + } | |
| 149 | + | |
| 150 | + @Override | |
| 151 | + public List<IotDeviceDataDO> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { | |
| 152 | + List<IotDeviceDataDO> list = new ArrayList<>(); | |
| 153 | + // 1. 获取设备信息 | |
| 154 | + IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); | |
| 155 | + // 2. 获取设备属性最新数据 | |
| 156 | + List<IotProductThingModelDO> thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey()); | |
| 157 | + thingModelList = filterList(thingModelList, thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType() | |
| 158 | + .equals(thingModel.getType())); | |
| 159 | + | |
| 160 | + // 3. 过滤标识符和属性名称 | |
| 161 | + if (deviceDataReqVO.getIdentifier() != null) { | |
| 162 | + thingModelList = filterList(thingModelList, thingModel -> thingModel.getIdentifier() | |
| 163 | + .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())); | |
| 164 | + } | |
| 165 | + if (deviceDataReqVO.getName() != null) { | |
| 166 | + thingModelList = filterList(thingModelList, thingModel -> thingModel.getName() | |
| 167 | + .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())); | |
| 168 | + } | |
| 169 | + // 4. 获取设备属性最新数据 | |
| 170 | + thingModelList.forEach(thingModel -> { | |
| 171 | + IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thingModel.getIdentifier()); | |
| 172 | + if (deviceData == null) { | |
| 173 | + deviceData = new IotDeviceDataDO(); | |
| 174 | + deviceData.setProductKey(device.getProductKey()); | |
| 175 | + deviceData.setDeviceName(device.getDeviceName()); | |
| 176 | + deviceData.setIdentifier(thingModel.getIdentifier()); | |
| 177 | + deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); | |
| 178 | + deviceData.setThingModelId(thingModel.getId()); | |
| 179 | + deviceData.setName(thingModel.getName()); | |
| 180 | + deviceData.setDataType(thingModel.getProperty().getDataType()); | |
| 181 | + } | |
| 182 | + list.add(deviceData); | |
| 183 | + }); | |
| 184 | + return list; | |
| 185 | + } | |
| 186 | + | |
| 187 | + @Override | |
| 188 | + public PageResult<Map<String, Object>> getHistoryDeviceProperties(IotDeviceDataPageReqVO deviceDataReqVO) { | |
| 189 | + PageResult<Map<String, Object>> pageResult = new PageResult<>(); | |
| 190 | + // 1. 获取设备信息 | |
| 191 | + IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); | |
| 192 | + // 2. 获取设备属性历史数据 | |
| 193 | + SelectVisualDO selectVisualDO = new SelectVisualDO(); | |
| 194 | + selectVisualDO.setDataBaseName(getDatabaseName()); | |
| 195 | + selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); | |
| 196 | + selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier()); | |
| 197 | + selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); | |
| 198 | + selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); | |
| 199 | + Map<String, Object> params = new HashMap<>(); | |
| 200 | + params.put("rows", deviceDataReqVO.getPageSize()); | |
| 201 | + params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); | |
| 202 | + selectVisualDO.setParams(params); | |
| 203 | + pageResult.setList(tdEngineDMLMapper.selectHistoryDataList(selectVisualDO)); | |
| 204 | + pageResult.setTotal(tdEngineDMLMapper.selectHistoryCount(selectVisualDO)); | |
| 205 | + return pageResult; | |
| 206 | + } | |
| 207 | + | |
| 208 | + private String getDatabaseName() { | |
| 209 | + return StrUtil.subAfter(url, "/", true); | |
| 210 | + } | |
| 211 | + | |
| 212 | + private static String getDeviceTableName(String productKey, String deviceName) { | |
| 213 | + return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey, deviceName); | |
| 214 | + } | |
| 215 | + | |
| 216 | +} | |
| 0 | 217 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
| ... | ... | @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 9 | 9 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 10 | 10 | import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; |
| 11 | 11 | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; |
| 12 | +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 12 | 13 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; |
| 13 | 14 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 14 | 15 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; |
| ... | ... | @@ -60,9 +61,11 @@ public class IotDeviceServiceImpl implements IotDeviceService { |
| 60 | 61 | throw exception(PRODUCT_NOT_EXISTS); |
| 61 | 62 | } |
| 62 | 63 | // 1.2 校验设备标识是否唯一 |
| 63 | - if (deviceMapper.selectByDeviceKey(createReqVO.getDeviceKey()) != null) { | |
| 64 | - throw exception(DEVICE_KEY_EXISTS); | |
| 65 | - } | |
| 64 | + TenantUtils.executeIgnore(() -> { | |
| 65 | + if (deviceMapper.selectByDeviceKey(createReqVO.getDeviceKey()) != null) { | |
| 66 | + throw exception(PRODUCT_KEY_EXISTS); | |
| 67 | + } | |
| 68 | + }); | |
| 66 | 69 | // 1.3 校验设备名称在同一产品下是否唯一 |
| 67 | 70 | if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), createReqVO.getDeviceKey()) != null) { |
| 68 | 71 | throw exception(DEVICE_NAME_EXISTS); | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
| ... | ... | @@ -2,13 +2,14 @@ package cn.iocoder.yudao.module.iot.service.product; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 5 | 6 | import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; |
| 6 | 7 | import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductSaveReqVO; |
| 7 | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; |
| 8 | 9 | import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; |
| 9 | 10 | import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; |
| 11 | +import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | |
| 10 | 12 | import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; |
| 11 | -import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; | |
| 12 | 13 | import com.baomidou.dynamic.datasource.annotation.DSTransactional; |
| 13 | 14 | import jakarta.annotation.Resource; |
| 14 | 15 | import org.springframework.context.annotation.Lazy; |
| ... | ... | @@ -34,18 +35,22 @@ public class IotProductServiceImpl implements IotProductService { |
| 34 | 35 | private IotProductMapper productMapper; |
| 35 | 36 | |
| 36 | 37 | @Resource |
| 37 | - @Lazy // 延迟加载,解决循环依赖 | |
| 38 | - private IotProductThingModelService thingModelFunctionService; | |
| 39 | - @Resource | |
| 40 | 38 | @Lazy // 延迟加载,解决循环依赖 |
| 41 | 39 | private IotThingModelMessageService thingModelMessageService; |
| 40 | + @Resource | |
| 41 | + @Lazy // 延迟加载,解决循环依赖 | |
| 42 | + private IotDevicePropertyDataService devicePropertyDataService; | |
| 42 | 43 | |
| 43 | 44 | @Override |
| 44 | 45 | public Long createProduct(IotProductSaveReqVO createReqVO) { |
| 45 | - // 1. 生成 ProductKey | |
| 46 | - if (productMapper.selectByProductKey(createReqVO.getProductKey()) != null) { | |
| 47 | - throw exception(PRODUCT_KEY_EXISTS); | |
| 48 | - } | |
| 46 | + // 1. 校验 ProductKey | |
| 47 | + TenantUtils.executeIgnore(() -> { | |
| 48 | + // 为什么忽略租户?避免多个租户之间,productKey 重复,导致 TDengine 设备属性表重复 | |
| 49 | + if (productMapper.selectByProductKey(createReqVO.getProductKey()) != null) { | |
| 50 | + throw exception(PRODUCT_KEY_EXISTS); | |
| 51 | + } | |
| 52 | + }); | |
| 53 | + | |
| 49 | 54 | // 2. 插入 |
| 50 | 55 | IotProductDO product = BeanUtils.toBean(createReqVO, IotProductDO.class) |
| 51 | 56 | .setStatus(IotProductStatusEnum.UNPUBLISHED.getStatus()); |
| ... | ... | @@ -119,8 +124,8 @@ public class IotProductServiceImpl implements IotProductService { |
| 119 | 124 | // 3. 产品是发布状态 |
| 120 | 125 | if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { |
| 121 | 126 | // 3.1 创建产品超级表数据模型 |
| 122 | - thingModelFunctionService.createSuperTableDataModel(id); | |
| 123 | - // 3.2 创建物模型日志超级表数据模型 | |
| 127 | + devicePropertyDataService.defineDevicePropertyData(id); | |
| 128 | + // 3.2 创建物模型日志超级表数据模型 TODO 待定:message 要不要分; | |
| 124 | 129 | thingModelMessageService.createSuperTable(id); |
| 125 | 130 | } |
| 126 | 131 | productMapper.updateById(updateObj); | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.service.tdengine; | |
| 2 | - | |
| 3 | - | |
| 4 | -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | |
| 5 | -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; | |
| 6 | - | |
| 7 | -import java.util.List; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * IoT 超级表服务,负责根据物模型创建和更新超级表,以及创建超级表的子表等操作。 | |
| 11 | - */ | |
| 12 | -public interface IotSuperTableService { | |
| 13 | - | |
| 14 | - /** | |
| 15 | - * 创建超级表数据模型 | |
| 16 | - */ | |
| 17 | - void createSuperTableDataModel(IotProductDO product, List<IotProductThingModelDO> thingModelList); | |
| 18 | - | |
| 19 | -} | |
| 20 | 0 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.service.tdengine; | |
| 2 | - | |
| 3 | -import cn.hutool.core.bean.BeanUtil; | |
| 4 | -import cn.hutool.core.collection.CollUtil; | |
| 5 | -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; | |
| 6 | -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelRespVO; | |
| 7 | -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | |
| 8 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; | |
| 9 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; | |
| 10 | -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; | |
| 11 | -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; | |
| 12 | -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; | |
| 13 | -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; | |
| 14 | -import jakarta.annotation.Resource; | |
| 15 | -import lombok.extern.slf4j.Slf4j; | |
| 16 | -import org.springframework.beans.factory.annotation.Value; | |
| 17 | -import org.springframework.stereotype.Service; | |
| 18 | - | |
| 19 | -import java.util.*; | |
| 20 | -import java.util.stream.Collectors; | |
| 21 | - | |
| 22 | -/** | |
| 23 | - * IoT 超级表服务实现类,负责根据物模型创建和更新超级表,以及创建超级表的子表等操作。 | |
| 24 | - */ | |
| 25 | -@Service | |
| 26 | -@Slf4j | |
| 27 | -public class IotSuperTableServiceImpl implements IotSuperTableService { | |
| 28 | - | |
| 29 | - @Resource | |
| 30 | - private TdEngineDDLMapper tdEngineDDLMapper; | |
| 31 | - | |
| 32 | - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") | |
| 33 | - private String url; | |
| 34 | - | |
| 35 | - @Override | |
| 36 | - public void createSuperTableDataModel(IotProductDO product, List<IotProductThingModelDO> thingModelList) { | |
| 37 | - ThingModelRespVO thingModel = buildThingModel(product, thingModelList); | |
| 38 | - | |
| 39 | - if (thingModel.getModel() == null || CollUtil.isEmpty(thingModel.getModel().getProperties())) { | |
| 40 | - log.warn("物模型属性列表为空,不创建超级表"); | |
| 41 | - return; | |
| 42 | - } | |
| 43 | - | |
| 44 | - String superTableName = getSuperTableName(product.getDeviceType(), product.getProductKey()); | |
| 45 | - String databaseName = getDatabaseName(); | |
| 46 | - | |
| 47 | - List<Map<String, Object>> results = tdEngineDDLMapper.showSuperTables(new TdTableDO(databaseName, superTableName)); | |
| 48 | - int tableExists = results == null || results.isEmpty() ? 0 : results.size(); | |
| 49 | - if (tableExists > 0) { | |
| 50 | - updateSuperTable(thingModel, product.getDeviceType()); | |
| 51 | - } else { | |
| 52 | - createSuperTable(thingModel, product.getDeviceType()); | |
| 53 | - } | |
| 54 | - } | |
| 55 | - | |
| 56 | - /** | |
| 57 | - * 创建超级表 | |
| 58 | - */ | |
| 59 | - private void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { | |
| 60 | - // 解析物模型,获取字段列表 | |
| 61 | - List<TdFieldDO> schemaFields = new ArrayList<>(); | |
| 62 | - schemaFields.add(TdFieldDO.builder() | |
| 63 | - .fieldName("time") | |
| 64 | - .dataType("TIMESTAMP") | |
| 65 | - .build()); | |
| 66 | - schemaFields.addAll(FieldParser.parse(thingModel)); | |
| 67 | - | |
| 68 | - // 设置超级表的标签 | |
| 69 | - List<TdFieldDO> tagsFields = List.of( | |
| 70 | - TdFieldDO.builder().fieldName("product_key").dataType("NCHAR").dataLength(64).build(), | |
| 71 | - TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build(), | |
| 72 | - TdFieldDO.builder().fieldName("device_name").dataType("NCHAR").dataLength(64).build(), | |
| 73 | - TdFieldDO.builder().fieldName("device_type").dataType("INT").build() | |
| 74 | - ); | |
| 75 | - | |
| 76 | - // 获取超级表的名称和数据库名称 | |
| 77 | - String superTableName = getSuperTableName(deviceType, thingModel.getProductKey()); | |
| 78 | - String databaseName = getDatabaseName(); | |
| 79 | - | |
| 80 | - // 创建超级表 | |
| 81 | - tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); | |
| 82 | - } | |
| 83 | - | |
| 84 | - /** | |
| 85 | - * 更新超级表 | |
| 86 | - */ | |
| 87 | - private void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { | |
| 88 | - String superTableName = getSuperTableName(deviceType, thingModel.getProductKey()); | |
| 89 | - try { | |
| 90 | - List<TdFieldDO> oldFields = getTableFields(superTableName); | |
| 91 | - List<TdFieldDO> newFields = FieldParser.parse(thingModel); | |
| 92 | - | |
| 93 | - updateTableFields(superTableName, oldFields, newFields); | |
| 94 | - } catch (Exception e) { | |
| 95 | - log.error("更新物模型超级表失败: {}", e.getMessage(), e); | |
| 96 | - } | |
| 97 | - } | |
| 98 | - | |
| 99 | - /** | |
| 100 | - * 获取表的字段信息 | |
| 101 | - */ | |
| 102 | - private List<TdFieldDO> getTableFields(String tableName) { | |
| 103 | - List<Map<String, Object>> tableDescription = tdEngineDDLMapper.describeSuperTable(new TdTableDO(getDatabaseName(), tableName)); | |
| 104 | - if (CollUtil.isEmpty(tableDescription)) { | |
| 105 | - return Collections.emptyList(); | |
| 106 | - } | |
| 107 | - | |
| 108 | - return tableDescription.stream() | |
| 109 | - .filter(map -> !"TAG".equals(map.get("note"))) | |
| 110 | - .filter(map -> !"time".equals(map.get("field"))) | |
| 111 | - .map(map -> TdFieldDO.builder() | |
| 112 | - .fieldName((String) map.get("field")) | |
| 113 | - .dataType((String) map.get("type")) | |
| 114 | - .dataLength((Integer) map.get("length")) | |
| 115 | - .build()) | |
| 116 | - .collect(Collectors.toList()); | |
| 117 | - } | |
| 118 | - | |
| 119 | - /** | |
| 120 | - * 更新表的字段,包括新增、修改和删除字段 | |
| 121 | - */ | |
| 122 | - private void updateTableFields(String tableName, List<TdFieldDO> oldFields, List<TdFieldDO> newFields) { | |
| 123 | - String databaseName = getDatabaseName(); | |
| 124 | - | |
| 125 | - // 获取新增、修改、删除的字段 | |
| 126 | - List<TdFieldDO> addFields = getAddFields(oldFields, newFields); | |
| 127 | - List<TdFieldDO> modifyFields = getModifyFields(oldFields, newFields); | |
| 128 | - List<TdFieldDO> dropFields = getDropFields(oldFields, newFields); | |
| 129 | - | |
| 130 | - // 添加新增字段 | |
| 131 | - if (CollUtil.isNotEmpty(addFields)) { | |
| 132 | - for (TdFieldDO addField : addFields) { | |
| 133 | - tdEngineDDLMapper.addColumnForSuperTable(TdTableDO.builder() | |
| 134 | - .dataBaseName(databaseName) | |
| 135 | - .superTableName(tableName) | |
| 136 | - .column(addField) | |
| 137 | - .build()); | |
| 138 | - } | |
| 139 | - } | |
| 140 | - // 删除旧字段 | |
| 141 | - if (CollUtil.isNotEmpty(dropFields)) { | |
| 142 | - for (TdFieldDO dropField : dropFields) { | |
| 143 | - tdEngineDDLMapper.dropColumnForSuperTable(TdTableDO.builder() | |
| 144 | - .dataBaseName(databaseName) | |
| 145 | - .superTableName(tableName) | |
| 146 | - .column(dropField) | |
| 147 | - .build()); | |
| 148 | - } | |
| 149 | - } | |
| 150 | - // 修改字段(先删除再添加) | |
| 151 | - if (CollUtil.isNotEmpty(modifyFields)) { | |
| 152 | - for (TdFieldDO modifyField : modifyFields) { | |
| 153 | - tdEngineDDLMapper.dropColumnForSuperTable(TdTableDO.builder() | |
| 154 | - .dataBaseName(databaseName) | |
| 155 | - .superTableName(tableName) | |
| 156 | - .column(modifyField) | |
| 157 | - .build()); | |
| 158 | - tdEngineDDLMapper.addColumnForSuperTable(TdTableDO.builder() | |
| 159 | - .dataBaseName(databaseName) | |
| 160 | - .superTableName(tableName) | |
| 161 | - .column(modifyField) | |
| 162 | - .build()); | |
| 163 | - } | |
| 164 | - } | |
| 165 | - } | |
| 166 | - | |
| 167 | - /** | |
| 168 | - * 获取需要新增的字段 | |
| 169 | - */ | |
| 170 | - private List<TdFieldDO> getAddFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) { | |
| 171 | - Set<String> oldFieldNames = oldFields.stream() | |
| 172 | - .map(TdFieldDO::getFieldName) | |
| 173 | - .collect(Collectors.toSet()); | |
| 174 | - return newFields.stream() | |
| 175 | - .filter(f -> !oldFieldNames.contains(f.getFieldName())) | |
| 176 | - .collect(Collectors.toList()); | |
| 177 | - } | |
| 178 | - | |
| 179 | - /** | |
| 180 | - * 获取需要修改的字段 | |
| 181 | - */ | |
| 182 | - private List<TdFieldDO> getModifyFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) { | |
| 183 | - Map<String, TdFieldDO> oldFieldMap = oldFields.stream() | |
| 184 | - .collect(Collectors.toMap(TdFieldDO::getFieldName, f -> f)); | |
| 185 | - | |
| 186 | - return newFields.stream() | |
| 187 | - .filter(f -> { | |
| 188 | - TdFieldDO oldField = oldFieldMap.get(f.getFieldName()); | |
| 189 | - return oldField != null && ( | |
| 190 | - !oldField.getDataType().equals(f.getDataType()) || | |
| 191 | - !Objects.equals(oldField.getDataLength(), f.getDataLength()) | |
| 192 | - ); | |
| 193 | - }) | |
| 194 | - .collect(Collectors.toList()); | |
| 195 | - } | |
| 196 | - | |
| 197 | - /** | |
| 198 | - * 获取需要删除的字段 | |
| 199 | - */ | |
| 200 | - private List<TdFieldDO> getDropFields(List<TdFieldDO> oldFields, List<TdFieldDO> newFields) { | |
| 201 | - Set<String> newFieldNames = newFields.stream() | |
| 202 | - .map(TdFieldDO::getFieldName) | |
| 203 | - .collect(Collectors.toSet()); | |
| 204 | - return oldFields.stream() | |
| 205 | - .filter(f -> !"time".equals(f.getFieldName())) | |
| 206 | - .filter(f -> !newFieldNames.contains(f.getFieldName())) | |
| 207 | - .collect(Collectors.toList()); | |
| 208 | - } | |
| 209 | - | |
| 210 | - /** | |
| 211 | - * 构建物模型 | |
| 212 | - */ | |
| 213 | - private ThingModelRespVO buildThingModel(IotProductDO product, List<IotProductThingModelDO> thingModelList) { | |
| 214 | - ThingModelRespVO thingModel = new ThingModelRespVO(); | |
| 215 | - thingModel.setId(product.getId()); | |
| 216 | - thingModel.setProductKey(product.getProductKey()); | |
| 217 | - | |
| 218 | - List<ThingModelProperty> properties = thingModelList.stream() | |
| 219 | - .filter(item -> IotProductThingModelTypeEnum.PROPERTY.equals( | |
| 220 | - IotProductThingModelTypeEnum.valueOfType(item.getType()))) | |
| 221 | - .map(this::buildThingModelProperty) | |
| 222 | - .collect(Collectors.toList()); | |
| 223 | - | |
| 224 | - ThingModelRespVO.Model model = new ThingModelRespVO.Model(); | |
| 225 | - model.setProperties(properties); | |
| 226 | - thingModel.setModel(model); | |
| 227 | - | |
| 228 | - return thingModel; | |
| 229 | - } | |
| 230 | - | |
| 231 | - /** | |
| 232 | - * 构建物模型属性 | |
| 233 | - */ | |
| 234 | - private ThingModelProperty buildThingModelProperty(IotProductThingModelDO thingModel) { | |
| 235 | - ThingModelProperty property = BeanUtil.copyProperties(thingModel, ThingModelProperty.class); | |
| 236 | - property.setDataType(thingModel.getProperty().getDataType()); | |
| 237 | - return property; | |
| 238 | - } | |
| 239 | - | |
| 240 | - /** | |
| 241 | - * 获取数据库名称 | |
| 242 | - */ | |
| 243 | - private String getDatabaseName() { | |
| 244 | - int index = url.lastIndexOf("/"); | |
| 245 | - return index != -1 ? url.substring(index + 1) : url; | |
| 246 | - } | |
| 247 | - | |
| 248 | - /** | |
| 249 | - * 获取超级表名称 | |
| 250 | - */ | |
| 251 | - private String getSuperTableName(Integer deviceType, String productKey) { | |
| 252 | - String prefix = switch (deviceType) { | |
| 253 | - case 1 -> "gateway_sub_"; | |
| 254 | - case 2 -> "gateway_"; | |
| 255 | - default -> "device_"; | |
| 256 | - }; | |
| 257 | - return (prefix + productKey).toLowerCase(); | |
| 258 | - } | |
| 259 | - | |
| 260 | -} | |
| 261 | 0 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java
| ... | ... | @@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapp |
| 16 | 16 | import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; |
| 17 | 17 | import cn.iocoder.yudao.module.iot.enums.thingmodel.*; |
| 18 | 18 | import cn.iocoder.yudao.module.iot.service.product.IotProductService; |
| 19 | -import cn.iocoder.yudao.module.iot.service.tdengine.IotSuperTableService; | |
| 20 | 19 | import jakarta.annotation.Resource; |
| 21 | 20 | import lombok.extern.slf4j.Slf4j; |
| 22 | 21 | import org.springframework.stereotype.Service; |
| ... | ... | @@ -44,8 +43,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ |
| 44 | 43 | |
| 45 | 44 | @Resource |
| 46 | 45 | private IotProductService productService; |
| 47 | - @Resource | |
| 48 | - private IotSuperTableService superTableService; | |
| 49 | 46 | |
| 50 | 47 | @Override |
| 51 | 48 | @Transactional(rollbackFor = Exception.class) |
| ... | ... | @@ -75,18 +72,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ |
| 75 | 72 | } |
| 76 | 73 | |
| 77 | 74 | @Override |
| 78 | - public void createSuperTableDataModel(Long productId) { | |
| 79 | - // 1. 查询产品 | |
| 80 | - IotProductDO product = productService.getProduct(productId); | |
| 81 | - | |
| 82 | - // 2. 查询产品的物模型功能列表 | |
| 83 | - List<IotProductThingModelDO> thingModelList = productThingModelMapper.selectListByProductId(productId); | |
| 84 | - | |
| 85 | - // 3. 生成 TDengine 的数据模型 | |
| 86 | - superTableService.createSuperTableDataModel(product, thingModelList); | |
| 87 | - } | |
| 88 | - | |
| 89 | - @Override | |
| 90 | 75 | @Transactional(rollbackFor = Exception.class) |
| 91 | 76 | public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { |
| 92 | 77 | // 1. 校验功能是否存在 | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<!DOCTYPE mapper | |
| 3 | + PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |
| 4 | + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |
| 5 | +<mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper"> | |
| 6 | + | |
| 7 | + <select id="getProductPropertySTableFieldList" resultType="cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField"> | |
| 8 | + DESCRIBE product_property_${productKey} | |
| 9 | + </select> | |
| 10 | + | |
| 11 | + <update id="createProductPropertySTable"> | |
| 12 | + CREATE STABLE product_property_${productKey} | |
| 13 | + <foreach item="field" collection="fields" separator="," open="(" close=")"> | |
| 14 | + ${field.field} ${field.type} | |
| 15 | + <if test="field.length != null and field.length > 0"> | |
| 16 | + (${field.length}) | |
| 17 | + </if> | |
| 18 | + </foreach> | |
| 19 | + TAGS ( | |
| 20 | + device_key NCHAR(50) | |
| 21 | + ) | |
| 22 | + </update> | |
| 23 | + | |
| 24 | + <update id="alterProductPropertySTableAddField"> | |
| 25 | + ALTER STABLE product_property_${productKey} | |
| 26 | + ADD COLUMN ${field.field} ${field.type} | |
| 27 | + <if test="field.length != null and field.length > 0"> | |
| 28 | + (${field.length}) | |
| 29 | + </if> | |
| 30 | + </update> | |
| 31 | + | |
| 32 | + <update id="alterProductPropertySTableModifyField"> | |
| 33 | + ALTER STABLE product_property_${productKey} | |
| 34 | + MODIFY COLUMN ${field.field} ${field.type} | |
| 35 | + <if test="field.length != null and field.length > 0"> | |
| 36 | + (${field.length}) | |
| 37 | + </if> | |
| 38 | + </update> | |
| 39 | + | |
| 40 | + <update id="alterProductPropertySTableDropField"> | |
| 41 | + ALTER STABLE product_property_${productKey} | |
| 42 | + DROP COLUMN ${field.field} | |
| 43 | + </update> | |
| 44 | + | |
| 45 | +</mapper> | |
| 0 | 46 | \ No newline at end of file | ... | ... |