Commit 05c54827152157983661a391c73d04b2615638c7
1 parent
6a35ca72
【新增功能】 集成 tdengine
Showing
37 changed files
with
2016 additions
and
3 deletions
yudao-dependencies/pom.xml
| @@ -33,6 +33,7 @@ | @@ -33,6 +33,7 @@ | ||
| 33 | <dm8.jdbc.version>8.1.3.62</dm8.jdbc.version> | 33 | <dm8.jdbc.version>8.1.3.62</dm8.jdbc.version> |
| 34 | <kingbase.jdbc.version>8.6.0</kingbase.jdbc.version> | 34 | <kingbase.jdbc.version>8.6.0</kingbase.jdbc.version> |
| 35 | <opengauss.jdbc.version>5.0.2</opengauss.jdbc.version> | 35 | <opengauss.jdbc.version>5.0.2</opengauss.jdbc.version> |
| 36 | + <taos.version>3.3.3</taos.version> | ||
| 36 | <!-- 消息队列 --> | 37 | <!-- 消息队列 --> |
| 37 | <rocketmq-spring.version>2.3.0</rocketmq-spring.version> | 38 | <rocketmq-spring.version>2.3.0</rocketmq-spring.version> |
| 38 | <!-- 服务保障相关 --> | 39 | <!-- 服务保障相关 --> |
| @@ -253,6 +254,12 @@ | @@ -253,6 +254,12 @@ | ||
| 253 | <version>${kingbase.jdbc.version}</version> | 254 | <version>${kingbase.jdbc.version}</version> |
| 254 | </dependency> | 255 | </dependency> |
| 255 | 256 | ||
| 257 | + <dependency> | ||
| 258 | + <groupId>com.taosdata.jdbc</groupId> | ||
| 259 | + <artifactId>taos-jdbcdriver</artifactId> | ||
| 260 | + <version>${taos.version}</version> | ||
| 261 | + </dependency> | ||
| 262 | + | ||
| 256 | <!-- Job 定时任务相关 --> | 263 | <!-- Job 定时任务相关 --> |
| 257 | <dependency> | 264 | <dependency> |
| 258 | <groupId>cn.iocoder.boot</groupId> | 265 | <groupId>cn.iocoder.boot</groupId> |
yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
| @@ -63,6 +63,10 @@ | @@ -63,6 +63,10 @@ | ||
| 63 | <artifactId>opengauss-jdbc</artifactId> | 63 | <artifactId>opengauss-jdbc</artifactId> |
| 64 | <optional>true</optional> | 64 | <optional>true</optional> |
| 65 | </dependency> | 65 | </dependency> |
| 66 | + <dependency> | ||
| 67 | + <groupId>com.taosdata.jdbc</groupId> | ||
| 68 | + <artifactId>taos-jdbcdriver</artifactId> | ||
| 69 | + </dependency> | ||
| 66 | 70 | ||
| 67 | <dependency> | 71 | <dependency> |
| 68 | <groupId>com.alibaba</groupId> | 72 | <groupId>com.alibaba</groupId> |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @ClassDescription: tdEngine的基础实体类 | ||
| 7 | + * @ClassName: BaseEntity | ||
| 8 | + * @Author: fxlinks | ||
| 9 | + * @Date: 2021-12-30 14:39:25 | ||
| 10 | + * @Version 1.0 | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +public class BaseEntity { | ||
| 14 | + private static final long serialVersionUID = 1L; | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 数据库名称 | ||
| 18 | + */ | ||
| 19 | + private String dataBaseName; | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 超级表名称 | ||
| 23 | + */ | ||
| 24 | + private String superTableName; | ||
| 25 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataExportExcelDto.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 设备数据导出 excel DTO | ||
| 7 | + */ | ||
| 8 | +@Data | ||
| 9 | +public class DeviceDataExportExcelDto { | ||
| 10 | + | ||
| 11 | + /** | ||
| 12 | + * 设备标识 | ||
| 13 | + */ | ||
| 14 | + private String deviceKey; | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 导出形式 1 单个参数导出 2 全部参数导出 | ||
| 18 | + */ | ||
| 19 | + private String exportType; | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 导出开始时间 | ||
| 23 | + */ | ||
| 24 | + private String exportBeginTime; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 导出结束时间 | ||
| 28 | + */ | ||
| 29 | + private String exportEndTime; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 导出参数,空则导出全部 | ||
| 33 | + */ | ||
| 34 | + private String exportParameter; | ||
| 35 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataVo.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @ClassDescription: 查询可视化所需入参对象 | ||
| 7 | + * @ClassName: SelectDto | ||
| 8 | + * @Author: andyz | ||
| 9 | + * @Date: 2022-07-29 14:12:26 | ||
| 10 | + * @Version 1.0 | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +public class DeviceDataVo { | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + private String deviceId; | ||
| 17 | + | ||
| 18 | + private Long lastTime; | ||
| 19 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @ClassDescription: 建表的字段实体类 | ||
| 7 | + * @ClassName: Fields | ||
| 8 | + * @Author: fxlinks | ||
| 9 | + * @Date: 2021-12-28 09:09:04 | ||
| 10 | + * @Version 1.0 | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +public class Fields { | ||
| 14 | + private static final long serialVersionUID = 1L; | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 字段名称 | ||
| 18 | + */ | ||
| 19 | + private String fieldName; | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 字段值 | ||
| 23 | + */ | ||
| 24 | + private Object fieldValue; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 字段数据类型 | ||
| 28 | + */ | ||
| 29 | +// private DataTypeEnum dataType; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 字段字节大小 | ||
| 33 | + */ | ||
| 34 | + private Integer size; | ||
| 35 | + | ||
| 36 | + public Fields() { | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public Fields(String fieldName, String dataType, Integer size) { | ||
| 40 | +// this.fieldName = fieldName; | ||
| 41 | +// //根据规则匹配字段数据类型 | ||
| 42 | +// switch (dataType.toLowerCase()) { | ||
| 43 | +// case ("json"): | ||
| 44 | +// this.dataType = DataTypeEnum.JSON; | ||
| 45 | +// this.size = size; | ||
| 46 | +// break; | ||
| 47 | +// case ("string"): | ||
| 48 | +// this.dataType = DataTypeEnum.NCHAR; | ||
| 49 | +// this.size = size; | ||
| 50 | +// break; | ||
| 51 | +// case ("binary"): | ||
| 52 | +// this.dataType = DataTypeEnum.BINARY; | ||
| 53 | +// this.size = size; | ||
| 54 | +// break; | ||
| 55 | +// case ("int"): | ||
| 56 | +// this.dataType = DataTypeEnum.INT; | ||
| 57 | +// break; | ||
| 58 | +// case ("bool"): | ||
| 59 | +// this.dataType = DataTypeEnum.BOOL; | ||
| 60 | +// break; | ||
| 61 | +// case ("decimal"): | ||
| 62 | +// this.dataType = DataTypeEnum.DOUBLE; | ||
| 63 | +// break; | ||
| 64 | +// case ("timestamp"): | ||
| 65 | +// if ("eventTime".equals(fieldName)) { | ||
| 66 | +// this.fieldName = "eventTime"; | ||
| 67 | +// } | ||
| 68 | +// this.dataType = DataTypeEnum.TIMESTAMP; | ||
| 69 | +// break; | ||
| 70 | +// } | ||
| 71 | + } | ||
| 72 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +import java.sql.SQLException; | ||
| 6 | +import java.util.ArrayList; | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * @ClassDescription: 建表的字段实体类的vo类 | ||
| 11 | + * @ClassName: FieldsVo | ||
| 12 | + * @Author: fxlinks | ||
| 13 | + * @Date: 2021-12-28 11:30:06 | ||
| 14 | + * @Version 1.0 | ||
| 15 | + */ | ||
| 16 | +@Data | ||
| 17 | +public class FieldsVo { | ||
| 18 | + private static final long serialVersionUID = 1L; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 字段名称 | ||
| 22 | + */ | ||
| 23 | + private String fieldName; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 字段数据类型 | ||
| 27 | + */ | ||
| 28 | + private String dataType; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 字段字节大小 | ||
| 32 | + */ | ||
| 33 | + private Integer size; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * @param fields 字段实体类 | ||
| 37 | + * @return FieldsVo 字段实体vo类 | ||
| 38 | + * @MethodDescription 字段实体类转为vo类 | ||
| 39 | + * @author fx | ||
| 40 | + * @Date 2021/12/28 13:48 | ||
| 41 | + */ | ||
| 42 | + public static FieldsVo fieldsTranscoding(Fields fields) throws SQLException { | ||
| 43 | +// if (StringUtils.isBlank(fields.getFieldName()) || fields.getDataType() == null) { | ||
| 44 | +// throw new SQLException("invalid operation: fieldName or dataType can not be null"); | ||
| 45 | +// } | ||
| 46 | +// FieldsVo fieldsVo = new FieldsVo(); | ||
| 47 | +// fieldsVo.setFieldName(fields.getFieldName()); | ||
| 48 | +// fieldsVo.setDataType(fields.getDataType().getDataType()); | ||
| 49 | +// fieldsVo.setSize(fields.getSize()); | ||
| 50 | +// return fieldsVo; | ||
| 51 | + return null; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * @param fieldsList 字段实体类集合 | ||
| 56 | + * @return List<FieldsVo> 字段实体vo类集合 | ||
| 57 | + * @MethodDescription 字段实体类集合转为vo类集合 | ||
| 58 | + * @author fx | ||
| 59 | + * @Date 2021/12/28 14:00 | ||
| 60 | + */ | ||
| 61 | + public static List<FieldsVo> fieldsTranscoding(List<Fields> fieldsList) throws SQLException { | ||
| 62 | + List<FieldsVo> fieldsVoList = new ArrayList<>(); | ||
| 63 | + for (Fields fields : fieldsList) { | ||
| 64 | + fieldsVoList.add(fieldsTranscoding(fields)); | ||
| 65 | + } | ||
| 66 | + return fieldsVoList; | ||
| 67 | + } | ||
| 68 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/IotSequential.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 4 | + | ||
| 5 | +import java.sql.Timestamp; | ||
| 6 | + | ||
| 7 | +public class IotSequential extends BaseEntity { | ||
| 8 | + private static final long serialVersionUID = 1L; | ||
| 9 | + | ||
| 10 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") | ||
| 11 | + private Timestamp statetime; | ||
| 12 | + | ||
| 13 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") | ||
| 14 | + private Timestamp endtime; | ||
| 15 | + | ||
| 16 | + private String deviceid; | ||
| 17 | + | ||
| 18 | + private String eventtime; | ||
| 19 | + | ||
| 20 | + private String serviceid; | ||
| 21 | + | ||
| 22 | + private String devices; | ||
| 23 | + | ||
| 24 | + public String getDeviceid() { | ||
| 25 | + return deviceid; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + public void setDeviceid(String deviceid) { | ||
| 29 | + this.deviceid = deviceid; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public String getEventtime() { | ||
| 33 | + return eventtime; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public void setEventtime(String eventtime) { | ||
| 37 | + this.eventtime = eventtime; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public String getServiceid() { | ||
| 41 | + return serviceid; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + public void setServiceid(String serviceid) { | ||
| 45 | + this.serviceid = serviceid; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + public String getDevices() { | ||
| 49 | + return devices; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + public void setDevices(String devices) { | ||
| 53 | + this.devices = devices; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + public Timestamp getStatetime() { | ||
| 57 | + return statetime; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + public void setStatetime(Timestamp statetime) { | ||
| 61 | + this.statetime = statetime; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + public Timestamp getEndtime() { | ||
| 65 | + return endtime; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + public void setEndtime(Timestamp endtime) { | ||
| 69 | + this.endtime = endtime; | ||
| 70 | + } | ||
| 71 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/MessageCountVo.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 统计的时间数据 | ||
| 9 | + */ | ||
| 10 | +@Data | ||
| 11 | +@NoArgsConstructor | ||
| 12 | +@AllArgsConstructor | ||
| 13 | +public class MessageCountVo { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 时间 | ||
| 17 | + */ | ||
| 18 | + private String time; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 数据值 | ||
| 22 | + */ | ||
| 23 | + private Object data; | ||
| 24 | + | ||
| 25 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.sql.Timestamp; | ||
| 7 | +import java.util.HashMap; | ||
| 8 | +import java.util.Optional; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * @Description: 产品超级表模型 | ||
| 12 | + * @Author: fx | ||
| 13 | + * @Website: http://www.sxfxck.com | ||
| 14 | + * @CreateDate: 2022/1/1$ 19:37$ | ||
| 15 | + * @UpdateUser: fx | ||
| 16 | + * @UpdateDate: 2022/1/1$ 19:37$ | ||
| 17 | + * @UpdateRemark: 修改内容 | ||
| 18 | + * @Version: V1.0 | ||
| 19 | + */ | ||
| 20 | +@Data | ||
| 21 | +public class ProductSuperTableModel { | ||
| 22 | + private static final long serialVersionUID = 1L; | ||
| 23 | + | ||
| 24 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") | ||
| 25 | + private Timestamp ts; | ||
| 26 | + | ||
| 27 | + private String superTableName; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * columnsName,columnsProperty | ||
| 31 | + */ | ||
| 32 | + private HashMap<Optional, Optional> columns; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * tagsName,tagsProperty | ||
| 36 | + */ | ||
| 37 | + private HashMap<Optional, Optional> tags; | ||
| 38 | + | ||
| 39 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +import java.util.Set; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @ClassDescription: 查询所需入参对象 | ||
| 9 | + * @ClassName: SelectDto | ||
| 10 | + * @Author: fxlinks | ||
| 11 | + * @Date: 2022-01-07 14:12:26 | ||
| 12 | + * @Version 1.0 | ||
| 13 | + */ | ||
| 14 | +@Data | ||
| 15 | +public class SelectDto { | ||
| 16 | + | ||
| 17 | + // @NotBlank(message = "invalid operation: dataBaseName can not be empty") | ||
| 18 | + private String dataBaseName; | ||
| 19 | + | ||
| 20 | +// @NotBlank(message = "invalid operation: tableName can not be empty") | ||
| 21 | + private String tableName; | ||
| 22 | + | ||
| 23 | + // @NotBlank(message = "invalid operation: fieldName can not be empty") | ||
| 24 | + private String fieldName; | ||
| 25 | + | ||
| 26 | + // @NotNull(message = "invalid operation: startTime can not be null") | ||
| 27 | + private Long startTime; | ||
| 28 | + | ||
| 29 | + // @NotNull(message = "invalid operation: endTime can not be null") | ||
| 30 | + private Long endTime; | ||
| 31 | + | ||
| 32 | + private String type; | ||
| 33 | + | ||
| 34 | + private Set<Integer> orgIds; | ||
| 35 | + | ||
| 36 | + private String deviceId; | ||
| 37 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +import java.util.List; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @ClassDescription: 创建超级表需要的入参的实体类 | ||
| 9 | + * @ClassName: SuperTableDto | ||
| 10 | + * @Author: fxlinks | ||
| 11 | + * @Date: 2021-12-28 15:03:45 | ||
| 12 | + * @Version 1.0 | ||
| 13 | + */ | ||
| 14 | +@Data | ||
| 15 | +public class SuperTableDto extends BaseEntity { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 超级表的表结构(业务相关) | ||
| 19 | + * 第一个字段的数据类型必须为timestamp | ||
| 20 | + * 字符相关数据类型必须指定大小 | ||
| 21 | + * 字段名称和字段数据类型不能为空 | ||
| 22 | + */ | ||
| 23 | +// @NotEmpty(message = "invalid operation: schemaFields can not be empty") | ||
| 24 | + private List<Fields> schemaFields; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 超级表的标签字段,可以作为子表在超级表里的标识 | ||
| 28 | + * 字符相关数据类型必须指定大小 | ||
| 29 | + * 字段名称和字段数据类型不能为空 | ||
| 30 | + */ | ||
| 31 | +// @NotEmpty(message = "invalid operation: tagsFields can not be empty") | ||
| 32 | + private List<Fields> tagsFields; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 字段信息对象,超级表添加列时使用该属性 | ||
| 36 | + */ | ||
| 37 | + private Fields fields; | ||
| 38 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +import java.util.List; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @ClassDescription: 创建超级表的子表需要的入参的实体类 | ||
| 9 | + * @ClassName: TableDto | ||
| 10 | + * @Author: fxlinks | ||
| 11 | + * @Date: 2021-12-30 14:42:47 | ||
| 12 | + * @Version 1.0 | ||
| 13 | + */ | ||
| 14 | +@Data | ||
| 15 | +public class TableDto extends BaseEntity { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 超级表普通列字段的值 | ||
| 19 | + * 值需要与创建超级表时普通列字段的数据类型对应上 | ||
| 20 | + */ | ||
| 21 | + private List<Fields> schemaFieldValues; | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * 超级表标签字段的值 | ||
| 25 | + * 值需要与创建超级表时标签字段的数据类型对应上 | ||
| 26 | + */ | ||
| 27 | + private List<Fields> tagsFieldValues; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 表名称 | ||
| 31 | + */ | ||
| 32 | + private String tableName; | ||
| 33 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * @program: fxlinks | ||
| 8 | + * @description: 标签查询模型 | ||
| 9 | + * @packagename: com.fx.tdengine.api.domain.rule | ||
| 10 | + * @author: fx | ||
| 11 | + * @e-mainl: 13733918655@163.com | ||
| 12 | + * @date: 2022-07-27 18:40 | ||
| 13 | + **/ | ||
| 14 | +@Data | ||
| 15 | +public class TagsSelectDao { | ||
| 16 | + | ||
| 17 | +// @NotBlank(message = "invalid operation: dataBaseName can not be empty") | ||
| 18 | + private String dataBaseName; | ||
| 19 | + | ||
| 20 | +// @NotBlank(message = "invalid operation: stableName can not be empty") | ||
| 21 | + private String stableName; | ||
| 22 | + | ||
| 23 | +// @NotBlank(message = "invalid operation: tagsName can not be empty") | ||
| 24 | + private String tagsName; | ||
| 25 | + | ||
| 26 | + // @NotNull(message = "invalid operation: startTime can not be null") | ||
| 27 | + private Long startTime; | ||
| 28 | + | ||
| 29 | + // @NotNull(message = "invalid operation: endTime can not be null") | ||
| 30 | + private Long endTime; | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Weather.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 4 | + | ||
| 5 | +import java.sql.Timestamp; | ||
| 6 | + | ||
| 7 | +public class Weather { | ||
| 8 | + | ||
| 9 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") | ||
| 10 | + private Timestamp ts; | ||
| 11 | + private Float temperature; | ||
| 12 | + private Float humidity; | ||
| 13 | + private String location; | ||
| 14 | + private String note; | ||
| 15 | + private int groupId; | ||
| 16 | + | ||
| 17 | + public Weather() { | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + public Weather(Timestamp ts, float temperature, float humidity) { | ||
| 21 | + this.ts = ts; | ||
| 22 | + this.temperature = temperature; | ||
| 23 | + this.humidity = humidity; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public Timestamp getTs() { | ||
| 27 | + return ts; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + public void setTs(Timestamp ts) { | ||
| 31 | + this.ts = ts; | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + public Float getTemperature() { | ||
| 35 | + return temperature; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + public void setTemperature(Float temperature) { | ||
| 39 | + this.temperature = temperature; | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + public Float getHumidity() { | ||
| 43 | + return humidity; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + public void setHumidity(Float humidity) { | ||
| 47 | + this.humidity = humidity; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + public String getLocation() { | ||
| 51 | + return location; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + public void setLocation(String location) { | ||
| 55 | + this.location = location; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + public int getGroupId() { | ||
| 59 | + return groupId; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + public void setGroupId(int groupId) { | ||
| 63 | + this.groupId = groupId; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + public String getNote() { | ||
| 67 | + return note; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + public void setNote(String note) { | ||
| 71 | + this.note = note; | ||
| 72 | + } | ||
| 73 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.domain.visual; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +import java.util.Map; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @ClassDescription: 查询可视化所需入参对象 | ||
| 9 | + * @ClassName: SelectDto | ||
| 10 | + * @Author: andyz | ||
| 11 | + * @Date: 2022-07-29 14:12:26 | ||
| 12 | + * @Version 1.0 | ||
| 13 | + */ | ||
| 14 | +@Data | ||
| 15 | +public class SelectVisualDto { | ||
| 16 | + | ||
| 17 | +// @NotBlank(message = "invalid operation: tableName can not be empty") | ||
| 18 | + private String dataBaseName; | ||
| 19 | + | ||
| 20 | +// @NotBlank(message = "invalid operation: tableName can not be empty") | ||
| 21 | + private String tableName; | ||
| 22 | + | ||
| 23 | +// @NotBlank(message = "invalid operation: fieldName can not be empty") //属性 | ||
| 24 | + private String fieldName; | ||
| 25 | + /** | ||
| 26 | + * 查询类型,0历史数据,1实时数据,2聚合数据 | ||
| 27 | + */ | ||
| 28 | + private int type; | ||
| 29 | + /** | ||
| 30 | + * 查询的数据量 | ||
| 31 | + */ | ||
| 32 | + private int num; | ||
| 33 | + /** | ||
| 34 | + * 聚合函数 | ||
| 35 | + */ | ||
| 36 | + private String aggregate; | ||
| 37 | + /** | ||
| 38 | + * 统计间隔数字+s/m/h/d | ||
| 39 | + * 比如1s,1m,1h,1d代表1秒,1分钟,1小时,1天 | ||
| 40 | + */ | ||
| 41 | + private String interval; | ||
| 42 | + // @NotNull(message = "invalid operation: startTime can not be null") | ||
| 43 | + private Long startTime; | ||
| 44 | + | ||
| 45 | + // @NotNull(message = "invalid operation: endTime can not be null") | ||
| 46 | + private Long endTime; | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * 请求参数 | ||
| 50 | + */ | ||
| 51 | + private Map<String, Object> params; | ||
| 52 | + | ||
| 53 | + private String sql; | ||
| 54 | + | ||
| 55 | + private String deviceId; | ||
| 56 | + | ||
| 57 | + private Long lastTime; | ||
| 58 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java
| @@ -30,6 +30,15 @@ public enum IotProductFunctionTypeEnum implements IntArrayValuable { | @@ -30,6 +30,15 @@ public enum IotProductFunctionTypeEnum implements IntArrayValuable { | ||
| 30 | */ | 30 | */ |
| 31 | private final String description; | 31 | private final String description; |
| 32 | 32 | ||
| 33 | + public static IotProductFunctionTypeEnum valueOf(Integer type) { | ||
| 34 | + for (IotProductFunctionTypeEnum value : values()) { | ||
| 35 | + if (value.getType().equals(type)) { | ||
| 36 | + return value; | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + return null; | ||
| 40 | + } | ||
| 41 | + | ||
| 33 | @Override | 42 | @Override |
| 34 | public int[] array() { | 43 | public int[] array() { |
| 35 | return ARRAYS; | 44 | return ARRAYS; |
yudao-module-iot/yudao-module-iot-biz/pom.xml
| @@ -42,6 +42,11 @@ | @@ -42,6 +42,11 @@ | ||
| 42 | <artifactId>yudao-spring-boot-starter-mybatis</artifactId> | 42 | <artifactId>yudao-spring-boot-starter-mybatis</artifactId> |
| 43 | </dependency> | 43 | </dependency> |
| 44 | 44 | ||
| 45 | + <dependency> | ||
| 46 | + <groupId>cn.iocoder.boot</groupId> | ||
| 47 | + <artifactId>yudao-spring-boot-starter-redis</artifactId> | ||
| 48 | + </dependency> | ||
| 49 | + | ||
| 45 | <!-- Test 测试相关 --> | 50 | <!-- Test 测试相关 --> |
| 46 | <dependency> | 51 | <dependency> |
| 47 | <groupId>cn.iocoder.boot</groupId> | 52 | <groupId>cn.iocoder.boot</groupId> |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java
| @@ -83,11 +83,10 @@ public class IotProductController { | @@ -83,11 +83,10 @@ public class IotProductController { | ||
| 83 | return success(BeanUtils.toBean(pageResult, IotProductRespVO.class)); | 83 | return success(BeanUtils.toBean(pageResult, IotProductRespVO.class)); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | - // TODO @haohao:改成 simple-list 哈 | ||
| 87 | - @GetMapping("/list-all-simple") | 86 | + @GetMapping("/simple-list") |
| 88 | @Operation(summary = "获得所有产品列表") | 87 | @Operation(summary = "获得所有产品列表") |
| 89 | @PreAuthorize("@ss.hasPermission('iot:product:query')") | 88 | @PreAuthorize("@ss.hasPermission('iot:product:query')") |
| 90 | - public CommonResult<List<IotProductSimpleRespVO>> listAllSimpleProducts() { | 89 | + public CommonResult<List<IotProductSimpleRespVO>> getSimpleProductList() { |
| 91 | List<IotProductDO> list = productService.getProductList(); | 90 | List<IotProductDO> list = productService.getProductList(); |
| 92 | return success(BeanUtils.toBean(list, IotProductSimpleRespVO.class)); | 91 | return success(BeanUtils.toBean(list, IotProductSimpleRespVO.class)); |
| 93 | } | 92 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.*; | ||
| 4 | + | ||
| 5 | +import java.util.List; | ||
| 6 | +import java.util.Map; | ||
| 7 | + | ||
| 8 | +@Data | ||
| 9 | +@Builder | ||
| 10 | +@NoArgsConstructor | ||
| 11 | +@AllArgsConstructor | ||
| 12 | +@ToString | ||
| 13 | +public class ThingModelRespVO { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 产品编号 | ||
| 17 | + */ | ||
| 18 | + private Long id; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 产品标识 | ||
| 22 | + */ | ||
| 23 | + private String productKey; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 物模型 | ||
| 27 | + */ | ||
| 28 | + private Model model; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 物模型 | ||
| 32 | + */ | ||
| 33 | + @Data | ||
| 34 | + public static class Model { | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * 属性列表 | ||
| 38 | + */ | ||
| 39 | + private List<ThingModelProperty> properties; | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 服务列表 | ||
| 43 | + */ | ||
| 44 | + private List<ThingModelService> services; | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 事件列表 | ||
| 48 | + */ | ||
| 49 | + private List<ThingModelEvent> events; | ||
| 50 | + } | ||
| 51 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; | ||
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; | ||
| 6 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelDataType; | ||
| 7 | + | ||
| 8 | +import java.util.HashMap; | ||
| 9 | +import java.util.List; | ||
| 10 | +import java.util.stream.Collectors; | ||
| 11 | + | ||
| 12 | +public class FieldParser { | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * 物模型到td数据类型映射 | ||
| 16 | + */ | ||
| 17 | + private static final HashMap<String, String> TYPE_MAPPING = new HashMap<>() {{ | ||
| 18 | + put("INT", "INT"); | ||
| 19 | + put("FLOAT", "FLOAT"); | ||
| 20 | + put("DOUBLE", "DOUBLE"); | ||
| 21 | + put("BOOL", "BOOL"); | ||
| 22 | + put("ENUM", "NCHAR"); | ||
| 23 | + put("TEXT", "NCHAR"); | ||
| 24 | + put("DATE", "NCHAR"); | ||
| 25 | + }}; | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 将物模型字段转换为td字段 | ||
| 30 | + * | ||
| 31 | + * @param property 物模型属性 | ||
| 32 | + * @return TdField对象 | ||
| 33 | + */ | ||
| 34 | + public static TdField parse(ThingModelProperty property) { | ||
| 35 | + String fieldName = property.getIdentifier().toLowerCase(); | ||
| 36 | + ThingModelDataType type = property.getDataType(); | ||
| 37 | + | ||
| 38 | + // 将物模型字段类型映射为td字段类型 | ||
| 39 | + String fType = TYPE_MAPPING.get(type.getType().toUpperCase()); | ||
| 40 | + | ||
| 41 | + int len = -1; | ||
| 42 | + // 如果字段类型为NCHAR,默认长度为64 | ||
| 43 | + if ("NCHAR".equals(fType)) { | ||
| 44 | + len = 64; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + return new TdField(fieldName, fType, len); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 获取物模型中的字段列表 | ||
| 52 | + */ | ||
| 53 | + public static List<TdField> parse(ThingModelRespVO thingModel) { | ||
| 54 | + return thingModel.getModel().getProperties().stream().map(FieldParser::parse).collect(Collectors.toList()); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * 将从库中查出来的字段信息转换为td字段对象 | ||
| 59 | + */ | ||
| 60 | + public static List<TdField> parse(List rows) { | ||
| 61 | + return (List<TdField>) rows.stream().map((r) -> { | ||
| 62 | + List row = (List) r; | ||
| 63 | + String type = row.get(1).toString().toUpperCase(); | ||
| 64 | + return new TdField( | ||
| 65 | + row.get(0).toString(), | ||
| 66 | + type, | ||
| 67 | + type.equals("NCHAR") ? Integer.parseInt(row.get(2).toString()) : -1); | ||
| 68 | + }).collect(Collectors.toList()); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 获取字段字义 | ||
| 73 | + */ | ||
| 74 | + public static String getFieldDefine(TdField field) { | ||
| 75 | + return "`" + field.getName() + "`" + " " + (field.getLength() > 0 ? | ||
| 76 | + String.format("%s(%d)", field.getType(), field.getLength()) | ||
| 77 | + : field.getType()); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +import java.util.List; | ||
| 6 | + | ||
| 7 | +@Data | ||
| 8 | +public class TableData { | ||
| 9 | + | ||
| 10 | + /** | ||
| 11 | + * 超级表普通列字段的名称 | ||
| 12 | + */ | ||
| 13 | + private List<String> schemaFieldList; | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 超级表标签字段的值 | ||
| 17 | + * 值需要与创建超级表时标签字段的数据类型对应上 | ||
| 18 | + */ | ||
| 19 | + private List<Object> tagsValueList; | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 超级表普通列字段的值 | ||
| 23 | + * 值需要与创建超级表时普通列字段的数据类型对应上 | ||
| 24 | + */ | ||
| 25 | + private List<Object> schemaValueList; | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 表名称 | ||
| 29 | + */ | ||
| 30 | + private String tableName; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 超级表名称 | ||
| 34 | + */ | ||
| 35 | + private String superTableName; | ||
| 36 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | ||
| 2 | + | ||
| 3 | +import java.util.List; | ||
| 4 | + | ||
| 5 | +public class TableManager { | ||
| 6 | + | ||
| 7 | + /** | ||
| 8 | + * 创建超级表模板(含存在判断) | ||
| 9 | + */ | ||
| 10 | + private static final String CREATE_STABLE_INE_TPL = "CREATE STABLE IF NOT EXISTS %s (%s) TAGS (%s);"; | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + * 删除超级表 | ||
| 14 | + */ | ||
| 15 | + private static final String DROP_STABLE_TPL = "DROP STABLE IF EXISTS %s;"; | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 获取表的结构信息 | ||
| 19 | + */ | ||
| 20 | + private static final String DESC_TB_TPL = "DESCRIBE %s;"; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 超级表增加列 | ||
| 24 | + */ | ||
| 25 | + private static final String ALTER_STABLE_ADD_COL_TPL = "ALTER STABLE %s ADD COLUMN %s;"; | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 超级表修改列 | ||
| 29 | + */ | ||
| 30 | + private static final String ALTER_STABLE_MODIFY_COL_TPL = "ALTER STABLE %s MODIFY COLUMN %s;"; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 超级表删除列 | ||
| 34 | + */ | ||
| 35 | + private static final String ALTER_STABLE_DROP_COL_TPL = "ALTER STABLE %s DROP COLUMN %s;"; | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * 创建普通表模板(含存在判断) | ||
| 39 | + */ | ||
| 40 | + private static final String CREATE_CTABLE_INE_TPL = "CREATE TABLE IF NOT EXISTS %s (%s)"; | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * 获取创建表sql | ||
| 44 | + */ | ||
| 45 | + public static String getCreateSTableSql(String tbName, List<TdField> fields, TdField... tags) { | ||
| 46 | + if (fields.isEmpty()) { | ||
| 47 | + return null; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + // 生成字段片段 | ||
| 51 | + StringBuilder sbField = new StringBuilder("time TIMESTAMP,"); | ||
| 52 | + | ||
| 53 | + for (TdField field : fields) { | ||
| 54 | + sbField.append(FieldParser.getFieldDefine(field)); | ||
| 55 | + sbField.append(","); | ||
| 56 | + } | ||
| 57 | + sbField.deleteCharAt(sbField.length() - 1); | ||
| 58 | + | ||
| 59 | + String fieldFrag = sbField.toString(); | ||
| 60 | + | ||
| 61 | + // 生成tag | ||
| 62 | + StringBuilder sbTag = new StringBuilder(); | ||
| 63 | + for (TdField tag : tags) { | ||
| 64 | + sbTag.append(FieldParser.getFieldDefine(tag)) | ||
| 65 | + .append(","); | ||
| 66 | + } | ||
| 67 | + sbTag.deleteCharAt(sbTag.length() - 1); | ||
| 68 | + | ||
| 69 | + return String.format(CREATE_STABLE_INE_TPL, tbName, fieldFrag, sbTag); | ||
| 70 | + | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + /** | ||
| 74 | + * 获取创建普通表sql | ||
| 75 | + */ | ||
| 76 | + public static String getCreateCTableSql(String tbName, List<TdField> fields) { | ||
| 77 | + if (fields.size() == 0) { | ||
| 78 | + return null; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + //生成字段片段 | ||
| 82 | + StringBuilder sbField = new StringBuilder("time timestamp,"); | ||
| 83 | + | ||
| 84 | + for (TdField field : fields) { | ||
| 85 | + sbField.append(FieldParser.getFieldDefine(field)); | ||
| 86 | + sbField.append(","); | ||
| 87 | + } | ||
| 88 | + sbField.deleteCharAt(sbField.length() - 1); | ||
| 89 | + | ||
| 90 | + String fieldFrag = sbField.toString(); | ||
| 91 | + | ||
| 92 | + return String.format(CREATE_CTABLE_INE_TPL, tbName, fieldFrag); | ||
| 93 | + | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + | ||
| 97 | + /** | ||
| 98 | + * 取正确的表名 | ||
| 99 | + * | ||
| 100 | + * @param name 表象 | ||
| 101 | + */ | ||
| 102 | + public static String rightTbName(String name) { | ||
| 103 | + return name.toLowerCase().replace("-" , "_"); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + /** | ||
| 107 | + * 获取表详情的sql | ||
| 108 | + */ | ||
| 109 | + public static String getDescTableSql(String tbName) { | ||
| 110 | + return String.format(DESC_TB_TPL, tbName); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + /** | ||
| 114 | + * 获取添加字段sql | ||
| 115 | + */ | ||
| 116 | + public static String getAddSTableColumnSql(String tbName, List<TdField> fields) { | ||
| 117 | + StringBuilder sbAdd = new StringBuilder(); | ||
| 118 | + for (TdField field : fields) { | ||
| 119 | + sbAdd.append(String.format(ALTER_STABLE_ADD_COL_TPL, | ||
| 120 | + tbName, | ||
| 121 | + FieldParser.getFieldDefine(field) | ||
| 122 | + )); | ||
| 123 | + } | ||
| 124 | + return sbAdd.toString(); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + /** | ||
| 128 | + * 获取修改字段sql | ||
| 129 | + */ | ||
| 130 | + public static String getModifySTableColumnSql(String tbName, List<TdField> fields) { | ||
| 131 | + StringBuilder sbModify = new StringBuilder(); | ||
| 132 | + for (TdField field : fields) { | ||
| 133 | + sbModify.append(String.format(ALTER_STABLE_MODIFY_COL_TPL, | ||
| 134 | + tbName, | ||
| 135 | + FieldParser.getFieldDefine(field) | ||
| 136 | + )); | ||
| 137 | + } | ||
| 138 | + return sbModify.toString(); | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + /** | ||
| 142 | + * 获取删除字段sql | ||
| 143 | + */ | ||
| 144 | + public static String getDropSTableColumnSql(String tbName, List<TdField> fields) { | ||
| 145 | + StringBuilder sbDrop = new StringBuilder(); | ||
| 146 | + for (TdField field : fields) { | ||
| 147 | + sbDrop.append(String.format(ALTER_STABLE_DROP_COL_TPL, | ||
| 148 | + tbName, | ||
| 149 | + field.getName() | ||
| 150 | + )); | ||
| 151 | + } | ||
| 152 | + return sbDrop.toString(); | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdField.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * TD 引擎的字段 | ||
| 9 | + */ | ||
| 10 | +@Data | ||
| 11 | +@NoArgsConstructor | ||
| 12 | +@AllArgsConstructor | ||
| 13 | +public class TdField { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 字段名称 | ||
| 17 | + */ | ||
| 18 | + private String name; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 字段类型 | ||
| 22 | + */ | ||
| 23 | + private String type; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 字段长度 | ||
| 27 | + */ | ||
| 28 | + private int length; | ||
| 29 | +} | ||
| 0 | \ No newline at end of file | 30 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | + | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +@Data | ||
| 10 | +@NoArgsConstructor | ||
| 11 | +@AllArgsConstructor | ||
| 12 | +public class TdResponse { | ||
| 13 | + | ||
| 14 | + public static final int CODE_SUCCESS = 0; | ||
| 15 | + public static final int CODE_TB_NOT_EXIST = 866; | ||
| 16 | + | ||
| 17 | + private String status; | ||
| 18 | + | ||
| 19 | + private int code; | ||
| 20 | + | ||
| 21 | + private String desc; | ||
| 22 | + | ||
| 23 | + //[["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]] | ||
| 24 | + private List data; | ||
| 25 | + | ||
| 26 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | ||
| 2 | + | ||
| 3 | +import cn.hutool.http.HttpRequest; | ||
| 4 | +import cn.hutool.http.HttpResponse; | ||
| 5 | +import cn.hutool.json.JSONUtil; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.springframework.beans.factory.annotation.Value; | ||
| 8 | +import org.springframework.stereotype.Service; | ||
| 9 | + | ||
| 10 | +@Slf4j | ||
| 11 | +@Service | ||
| 12 | +public class TdRestApi { | ||
| 13 | + | ||
| 14 | + @Value("${spring.datasource.dynamic.datasource.master.url}") | ||
| 15 | + private String url; | ||
| 16 | + | ||
| 17 | + @Value("${spring.datasource.dynamic.datasource.master.username}") | ||
| 18 | + private String username; | ||
| 19 | + | ||
| 20 | + @Value("${spring.datasource.dynamic.datasource.master.password}") | ||
| 21 | + private String password; | ||
| 22 | + | ||
| 23 | + private String getRestApiUrl() { | ||
| 24 | + //jdbc:TAOS-RS://127.0.0.1:6041/iotkit?xxxx | ||
| 25 | + String restUrl = url.replace("jdbc:TAOS-RS://" , "") | ||
| 26 | + .replaceAll("\\?.*" , ""); | ||
| 27 | + // /rest/sql/iotkit | ||
| 28 | + int idx = restUrl.lastIndexOf("/"); | ||
| 29 | + //127.0.0.1:6041/rest/sql/iotkit | ||
| 30 | + return String.format("%s/rest/sql/%s" , restUrl.substring(0, idx), restUrl.substring(idx + 1)); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 新建td api请求对象 | ||
| 36 | + */ | ||
| 37 | + public HttpRequest newApiRequest(String sql) { | ||
| 38 | + return HttpRequest | ||
| 39 | + .post(getRestApiUrl()) | ||
| 40 | + .body(sql) | ||
| 41 | + .basicAuth(username, password); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * 执行sql | ||
| 46 | + */ | ||
| 47 | + public TdResponse execSql(String sql) { | ||
| 48 | + log.info("exec td sql:{}" , sql); | ||
| 49 | + HttpRequest request = newApiRequest(sql); | ||
| 50 | + HttpResponse response = request.execute(); | ||
| 51 | + return JSONUtil.toBean(response.body(), TdResponse.class); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + | ||
| 55 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 统计的时间数据 | ||
| 9 | + */ | ||
| 10 | +@Data | ||
| 11 | +@NoArgsConstructor | ||
| 12 | +@AllArgsConstructor | ||
| 13 | +public class TimeData { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 时间 | ||
| 17 | + */ | ||
| 18 | + private long time; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 数据值 | ||
| 22 | + */ | ||
| 23 | + private Object data; | ||
| 24 | + | ||
| 25 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.tdengine; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.iot.domain.FieldsVo; | ||
| 4 | +import cn.iocoder.yudao.module.iot.domain.SelectDto; | ||
| 5 | +import cn.iocoder.yudao.module.iot.domain.TableDto; | ||
| 6 | +import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; | ||
| 7 | +import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; | ||
| 8 | +import com.baomidou.dynamic.datasource.annotation.DS; | ||
| 9 | +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; | ||
| 10 | +import org.apache.ibatis.annotations.Mapper; | ||
| 11 | +import org.apache.ibatis.annotations.Param; | ||
| 12 | + | ||
| 13 | +import java.util.List; | ||
| 14 | +import java.util.Map; | ||
| 15 | + | ||
| 16 | +@Mapper | ||
| 17 | +@DS("tdengine") | ||
| 18 | +public interface TdEngineMapper { | ||
| 19 | + | ||
| 20 | + void createDatabase(@Param("dataBaseName") String dataBaseName); | ||
| 21 | + | ||
| 22 | + void createSuperTable(@Param("schemaFields") List<FieldsVo> schemaFields, | ||
| 23 | + @Param("tagsFields") List<FieldsVo> tagsFields, | ||
| 24 | + @Param("dataBaseName") String dataBaseName, | ||
| 25 | + @Param("superTableName") String superTableName); | ||
| 26 | + | ||
| 27 | + void createTable(TableDto tableDto); | ||
| 28 | + | ||
| 29 | + void insertData(TableDto tableDto); | ||
| 30 | + | ||
| 31 | + List<Map<String, Object>> selectByTimestamp(SelectDto selectDto); | ||
| 32 | + | ||
| 33 | + void addColumnForSuperTable(@Param("superTableName") String superTableName, | ||
| 34 | + @Param("fieldsVo") FieldsVo fieldsVo); | ||
| 35 | + | ||
| 36 | + void dropColumnForSuperTable(@Param("superTableName") String superTableName, | ||
| 37 | + @Param("fieldsVo") FieldsVo fieldsVo); | ||
| 38 | + | ||
| 39 | + void addTagForSuperTable(@Param("superTableName") String superTableName, | ||
| 40 | + @Param("fieldsVo") FieldsVo fieldsVo); | ||
| 41 | + | ||
| 42 | + void dropTagForSuperTable(@Param("superTableName") String superTableName, | ||
| 43 | + @Param("fieldsVo") FieldsVo fieldsVo); | ||
| 44 | + | ||
| 45 | + Map<String, Long> getCountByTimestamp(SelectDto selectDto); | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * 检查表是否存在 | ||
| 49 | + * | ||
| 50 | + * @param dataBaseName 数据库名称 | ||
| 51 | + * @param tableName 表名称 | ||
| 52 | + */ | ||
| 53 | + Integer checkTableExists(@Param("dataBaseName") String dataBaseName, @Param("tableName") String tableName); | ||
| 54 | + | ||
| 55 | + Map<String, Object> getLastData(SelectDto selectDto); | ||
| 56 | + | ||
| 57 | + List<Map<String, Object>> getHistoryData(SelectVisualDto selectVisualDto); | ||
| 58 | + | ||
| 59 | + List<Map<String, Object>> getRealtimeData(SelectVisualDto selectVisualDto); | ||
| 60 | + | ||
| 61 | + List<Map<String, Object>> getAggregateData(SelectVisualDto selectVisualDto); | ||
| 62 | + | ||
| 63 | + List<Map<String, Object>> getLastDataByTags(TagsSelectDao tagsSelectDao); | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * 创建超级表 | ||
| 67 | + * | ||
| 68 | + * @param sql sql | ||
| 69 | + * @return 返回值 | ||
| 70 | + */ | ||
| 71 | + @InterceptorIgnore(tenantLine = "true") | ||
| 72 | + Integer createSuperTableDevice(String sql); | ||
| 73 | + | ||
| 74 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.framework.aspect; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.aspectj.lang.ProceedingJoinPoint; | ||
| 5 | +import org.aspectj.lang.annotation.Around; | ||
| 6 | +import org.aspectj.lang.annotation.Aspect; | ||
| 7 | +import org.springframework.stereotype.Component; | ||
| 8 | + | ||
| 9 | +import java.sql.Timestamp; | ||
| 10 | +import java.util.Map; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * TaosAspect 是一个处理 Taos 数据库返回值的切面。 | ||
| 14 | + */ | ||
| 15 | +@Aspect | ||
| 16 | +@Component | ||
| 17 | +@Slf4j | ||
| 18 | +public class TaosAspect { | ||
| 19 | + | ||
| 20 | + @Around("execution(java.util.Map<String,Object> cn.iocoder.yudao.module.iot.dal.tdengine.*.*(..))") | ||
| 21 | + public Object handleType(ProceedingJoinPoint joinPoint) { | ||
| 22 | + Map<String, Object> result = null; | ||
| 23 | + try { | ||
| 24 | + result = (Map<String, Object>) joinPoint.proceed(); | ||
| 25 | + result.replaceAll((key, value) -> { | ||
| 26 | + if (value instanceof byte[]) { | ||
| 27 | + return new String((byte[]) value); | ||
| 28 | + } else if (value instanceof Timestamp) { | ||
| 29 | + return ((Timestamp) value).getTime(); | ||
| 30 | + } | ||
| 31 | + return value; | ||
| 32 | + }); | ||
| 33 | + } catch (Throwable e) { | ||
| 34 | + log.error("TaosAspect handleType error", e); | ||
| 35 | + } | ||
| 36 | + return result; | ||
| 37 | + } | ||
| 38 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
| @@ -8,8 +8,13 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReq | @@ -8,8 +8,13 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReq | ||
| 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | 8 | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; |
| 9 | import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; | 9 | import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; |
| 10 | import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; | 10 | import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; |
| 11 | +import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; | ||
| 12 | +import com.baomidou.dynamic.datasource.annotation.DSTransactional; | ||
| 11 | import jakarta.annotation.Resource; | 13 | import jakarta.annotation.Resource; |
| 14 | + | ||
| 15 | +import org.springframework.context.annotation.Lazy; | ||
| 12 | import org.springframework.stereotype.Service; | 16 | import org.springframework.stereotype.Service; |
| 17 | +import org.springframework.transaction.annotation.Transactional; | ||
| 13 | import org.springframework.validation.annotation.Validated; | 18 | import org.springframework.validation.annotation.Validated; |
| 14 | 19 | ||
| 15 | import java.util.List; | 20 | import java.util.List; |
| @@ -31,6 +36,10 @@ public class IotProductServiceImpl implements IotProductService { | @@ -31,6 +36,10 @@ public class IotProductServiceImpl implements IotProductService { | ||
| 31 | @Resource | 36 | @Resource |
| 32 | private IotProductMapper productMapper; | 37 | private IotProductMapper productMapper; |
| 33 | 38 | ||
| 39 | + @Resource | ||
| 40 | + @Lazy | ||
| 41 | + private IotThinkModelFunctionService thinkModelFunctionService; | ||
| 42 | + | ||
| 34 | @Override | 43 | @Override |
| 35 | public Long createProduct(IotProductSaveReqVO createReqVO) { | 44 | public Long createProduct(IotProductSaveReqVO createReqVO) { |
| 36 | // 1. 生成 ProductKey | 45 | // 1. 生成 ProductKey |
| @@ -106,11 +115,17 @@ public class IotProductServiceImpl implements IotProductService { | @@ -106,11 +115,17 @@ public class IotProductServiceImpl implements IotProductService { | ||
| 106 | } | 115 | } |
| 107 | 116 | ||
| 108 | @Override | 117 | @Override |
| 118 | + @DSTransactional(rollbackFor = Exception.class) | ||
| 109 | public void updateProductStatus(Long id, Integer status) { | 119 | public void updateProductStatus(Long id, Integer status) { |
| 110 | // 1. 校验存在 | 120 | // 1. 校验存在 |
| 111 | validateProductExists(id); | 121 | validateProductExists(id); |
| 112 | // 2. 更新 | 122 | // 2. 更新 |
| 113 | IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); | 123 | IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); |
| 124 | + // 3. 产品是发布状态 | ||
| 125 | + if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getType())) { | ||
| 126 | + // 3.1 创建超级表数据模型 | ||
| 127 | + thinkModelFunctionService.createSuperTableDataModel(id); | ||
| 128 | + } | ||
| 114 | productMapper.updateById(updateObj); | 129 | productMapper.updateById(updateObj); |
| 115 | } | 130 | } |
| 116 | 131 |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.tdengine; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; | ||
| 5 | +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | ||
| 6 | +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 数据结构接口 | ||
| 12 | + */ | ||
| 13 | +public interface IotDbStructureDataService { | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 创建物模型定义 | ||
| 17 | + */ | ||
| 18 | + void createSuperTable(ThingModelRespVO thingModel, Integer deviceType); | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 更新物模型定义 | ||
| 22 | + */ | ||
| 23 | + void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType); | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 创建超级表数据模型 | ||
| 27 | + */ | ||
| 28 | + void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList); | ||
| 29 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.tdengine; | ||
| 2 | + | ||
| 3 | +import cn.hutool.json.JSONUtil; | ||
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; | ||
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; | ||
| 6 | +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | ||
| 7 | +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; | ||
| 8 | +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; | ||
| 9 | +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; | ||
| 10 | +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; | ||
| 11 | +import jakarta.annotation.Resource; | ||
| 12 | +import lombok.extern.slf4j.Slf4j; | ||
| 13 | +import org.springframework.stereotype.Service; | ||
| 14 | + | ||
| 15 | +import java.util.ArrayList; | ||
| 16 | +import java.util.List; | ||
| 17 | +import java.util.Objects; | ||
| 18 | +import java.util.stream.Collectors; | ||
| 19 | + | ||
| 20 | +@Service | ||
| 21 | +@Slf4j | ||
| 22 | +public class IotDbStructureDataServiceImpl implements IotDbStructureDataService { | ||
| 23 | + | ||
| 24 | + @Resource | ||
| 25 | + private TdEngineMapper tdEngineMapper; | ||
| 26 | + | ||
| 27 | + @Resource | ||
| 28 | + private TdRestApi tdRestApi; | ||
| 29 | + | ||
| 30 | + @Override | ||
| 31 | + public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { | ||
| 32 | + // 获取物模型中的属性定义 | ||
| 33 | + List<TdField> fields = FieldParser.parse(thingModel); | ||
| 34 | + String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); | ||
| 35 | + | ||
| 36 | + // 生成创建超级表的 SQL | ||
| 37 | + String sql = TableManager.getCreateSTableSql(tbName, fields, new TdField("device_id", "NCHAR", 64)); | ||
| 38 | + if (sql == null) { | ||
| 39 | + log.warn("生成的 SQL 为空,无法创建超级表"); | ||
| 40 | + return; | ||
| 41 | + } | ||
| 42 | + log.info("执行 SQL: {}", sql); | ||
| 43 | + | ||
| 44 | + // 执行 SQL 创建超级表 | ||
| 45 | + tdEngineMapper.createSuperTableDevice(sql); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + @Override | ||
| 49 | + public void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { | ||
| 50 | + try { | ||
| 51 | + // 获取旧字段信息 | ||
| 52 | + String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); | ||
| 53 | + String sql = TableManager.getDescTableSql(tbName); | ||
| 54 | + TdResponse response = tdRestApi.execSql(sql); | ||
| 55 | + if (response.getCode() != TdResponse.CODE_SUCCESS) { | ||
| 56 | + throw new RuntimeException("获取表描述错误: " + JSONUtil.toJsonStr(response)); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + List<TdField> oldFields = FieldParser.parse(response.getData()); | ||
| 60 | + List<TdField> newFields = FieldParser.parse(thingModel); | ||
| 61 | + | ||
| 62 | + // 找出新增的字段 | ||
| 63 | + List<TdField> addFields = newFields.stream() | ||
| 64 | + .filter(f -> oldFields.stream().noneMatch(old -> old.getName().equals(f.getName()))) | ||
| 65 | + .collect(Collectors.toList()); | ||
| 66 | + if (!addFields.isEmpty()) { | ||
| 67 | + sql = TableManager.getAddSTableColumnSql(tbName, addFields); | ||
| 68 | + response = tdRestApi.execSql(sql); | ||
| 69 | + if (response.getCode() != TdResponse.CODE_SUCCESS) { | ||
| 70 | + throw new RuntimeException("添加表字段错误: " + JSONUtil.toJsonStr(response)); | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + // 找出修改的字段 | ||
| 75 | + List<TdField> modifyFields = newFields.stream() | ||
| 76 | + .filter(f -> oldFields.stream().anyMatch(old -> | ||
| 77 | + old.getName().equals(f.getName()) && | ||
| 78 | + (!old.getType().equals(f.getType()) || old.getLength() != f.getLength()))) | ||
| 79 | + .collect(Collectors.toList()); | ||
| 80 | + if (!modifyFields.isEmpty()) { | ||
| 81 | + sql = TableManager.getModifySTableColumnSql(tbName, modifyFields); | ||
| 82 | + response = tdRestApi.execSql(sql); | ||
| 83 | + if (response.getCode() != TdResponse.CODE_SUCCESS) { | ||
| 84 | + throw new RuntimeException("修改表字段错误: " + JSONUtil.toJsonStr(response)); | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + // 找出删除的字段 | ||
| 89 | + List<TdField> dropFields = oldFields.stream() | ||
| 90 | + .filter(f -> !"time".equals(f.getName()) && !"device_id".equals(f.getName()) && | ||
| 91 | + newFields.stream().noneMatch(n -> n.getName().equals(f.getName()))) | ||
| 92 | + .collect(Collectors.toList()); | ||
| 93 | + if (!dropFields.isEmpty()) { | ||
| 94 | + sql = TableManager.getDropSTableColumnSql(tbName, dropFields); | ||
| 95 | + response = tdRestApi.execSql(sql); | ||
| 96 | + if (response.getCode() != TdResponse.CODE_SUCCESS) { | ||
| 97 | + throw new RuntimeException("删除表字段错误: " + JSONUtil.toJsonStr(response)); | ||
| 98 | + } | ||
| 99 | + } | ||
| 100 | + } catch (Throwable e) { | ||
| 101 | + log.error("更新物模型超级表失败", e); | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + @Override | ||
| 106 | + public void createSuperTableDataModel(IotProductDO product, List<IotThinkModelFunctionDO> functionList) { | ||
| 107 | + // 1. 生成 ThingModelRespVO | ||
| 108 | + ThingModelRespVO thingModel = new ThingModelRespVO(); | ||
| 109 | + thingModel.setId(product.getId()); | ||
| 110 | + thingModel.setProductKey(product.getProductKey()); | ||
| 111 | + | ||
| 112 | + // 1.1 设置属性、服务和事件 | ||
| 113 | + ThingModelRespVO.Model model = new ThingModelRespVO.Model(); | ||
| 114 | + List<ThingModelProperty> properties = new ArrayList<>(); | ||
| 115 | + | ||
| 116 | + // 1.2 遍历功能列表并分类 | ||
| 117 | + for (IotThinkModelFunctionDO function : functionList) { | ||
| 118 | + if (Objects.requireNonNull(IotProductFunctionTypeEnum.valueOf(function.getType())) == IotProductFunctionTypeEnum.PROPERTY) { | ||
| 119 | + ThingModelProperty property = new ThingModelProperty(); | ||
| 120 | + property.setIdentifier(function.getIdentifier()); | ||
| 121 | + property.setName(function.getName()); | ||
| 122 | + property.setDescription(function.getDescription()); | ||
| 123 | + property.setDataType(function.getProperty().getDataType()); | ||
| 124 | + properties.add(property); | ||
| 125 | + } | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + // 1.3 判断属性列表是否为空 | ||
| 129 | + if (properties.isEmpty()) { | ||
| 130 | + log.warn("物模型属性列表为空,不创建超级表"); | ||
| 131 | + return; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + model.setProperties(properties); | ||
| 135 | + thingModel.setModel(model); | ||
| 136 | + | ||
| 137 | + // 2. 判断是否已经创建,如果已经创建则进行更新 | ||
| 138 | + String tbName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); | ||
| 139 | + Integer iot = tdEngineMapper.checkTableExists("ruoyi_vue_pro", tbName); | ||
| 140 | + if (iot != null && iot > 0) { | ||
| 141 | + // 3. 更新 | ||
| 142 | + updateSuperTable(thingModel, product.getDeviceType()); | ||
| 143 | + } else { | ||
| 144 | + // 4. 创建 | ||
| 145 | + createSuperTable(thingModel, product.getDeviceType()); | ||
| 146 | + } | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + /** | ||
| 150 | + * 根据产品key获取产品属性超级表名 | ||
| 151 | + */ | ||
| 152 | + static String getProductPropertySTableName(Integer deviceType, String productKey) { | ||
| 153 | + if (deviceType == 1) { | ||
| 154 | + return String.format("gateway_sub_" + productKey).toLowerCase(); | ||
| 155 | + } else if (deviceType == 2) { | ||
| 156 | + return String.format("gateway_" + productKey).toLowerCase(); | ||
| 157 | + } else { | ||
| 158 | + return String.format("device_" + productKey).toLowerCase(); | ||
| 159 | + } | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + /** | ||
| 163 | + * 根据deviceId获取设备属性表名 | ||
| 164 | + */ | ||
| 165 | + static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) { | ||
| 166 | + return String.format(deviceType + "_" + productKey + "_" + deviceKey).toLowerCase(); | ||
| 167 | + } | ||
| 168 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.tdengine; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.iot.domain.FieldsVo; | ||
| 4 | +import cn.iocoder.yudao.module.iot.domain.SelectDto; | ||
| 5 | +import cn.iocoder.yudao.module.iot.domain.TableDto; | ||
| 6 | +import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; | ||
| 7 | +import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; | ||
| 8 | + | ||
| 9 | +import java.util.List; | ||
| 10 | +import java.util.Map; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * TdEngineService | ||
| 14 | + */ | ||
| 15 | +public interface TdEngineService { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 创建数据库 | ||
| 19 | + * | ||
| 20 | + * @param dataBaseName 数据库名称 | ||
| 21 | + * @throws Exception 异常 | ||
| 22 | + */ | ||
| 23 | + void createDateBase(String dataBaseName) throws Exception; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 创建超级表 | ||
| 27 | + * | ||
| 28 | + * @param schemaFields schema字段 | ||
| 29 | + * @param tagsFields tags字段 | ||
| 30 | + * @param dataBaseName 数据库名称 | ||
| 31 | + * @param superTableName 超级表名称 | ||
| 32 | + * @throws Exception 异常 | ||
| 33 | + */ | ||
| 34 | + void createSuperTable(List<FieldsVo> schemaFields, List<FieldsVo> tagsFields, String dataBaseName, | ||
| 35 | + String superTableName) throws Exception; | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * 创建表 | ||
| 39 | + * | ||
| 40 | + * @param tableDto 表信息 | ||
| 41 | + * @throws Exception 异常 | ||
| 42 | + */ | ||
| 43 | + void createTable(TableDto tableDto) throws Exception; | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * 插入数据 | ||
| 47 | + * | ||
| 48 | + * @param tableDto 表信息 | ||
| 49 | + * @throws Exception 异常 | ||
| 50 | + */ | ||
| 51 | + void insertData(TableDto tableDto) throws Exception; | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * 根据时间戳查询数据 | ||
| 55 | + * | ||
| 56 | + * @param selectDto 查询条件 | ||
| 57 | + * @return 数据 | ||
| 58 | + * @throws Exception 异常 | ||
| 59 | + */ | ||
| 60 | + List<Map<String, Object>> selectByTimesTamp(SelectDto selectDto) throws Exception; | ||
| 61 | + | ||
| 62 | + /** | ||
| 63 | + * 为超级表添加列 | ||
| 64 | + * | ||
| 65 | + * @param superTableName 超级表名称 | ||
| 66 | + * @param fieldsVo 字段信息 | ||
| 67 | + * @throws Exception 异常 | ||
| 68 | + */ | ||
| 69 | + void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception; | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 为超级表删除列 | ||
| 73 | + * | ||
| 74 | + * @param superTableName 超级表名称 | ||
| 75 | + * @param fieldsVo 字段信息 | ||
| 76 | + * @throws Exception 异常 | ||
| 77 | + */ | ||
| 78 | + void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception; | ||
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * 为超级表添加tag | ||
| 82 | + */ | ||
| 83 | + Long getCountByTimesTamp(SelectDto selectDto) throws Exception; | ||
| 84 | + | ||
| 85 | + /** | ||
| 86 | + * 检查表是否存在 | ||
| 87 | + * | ||
| 88 | + * @return 1存在 0不存在 | ||
| 89 | + * @throws Exception 异常 | ||
| 90 | + */ | ||
| 91 | + Integer checkTableExists(SelectDto selectDto) throws Exception; | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * 初始化超级表 | ||
| 95 | + * | ||
| 96 | + * @param msg 消息 | ||
| 97 | + * @throws Exception 异常 | ||
| 98 | + */ | ||
| 99 | + void initSTableFrame(String msg) throws Exception; | ||
| 100 | + | ||
| 101 | + /** | ||
| 102 | + * 获取最新数据 | ||
| 103 | + * | ||
| 104 | + * @param selectDto 查询条件 | ||
| 105 | + * @return 数据 | ||
| 106 | + * @throws Exception 异常 | ||
| 107 | + */ | ||
| 108 | + Map<String, Object> getLastData(SelectDto selectDto) throws Exception; | ||
| 109 | + | ||
| 110 | + /** | ||
| 111 | + * 根据tag查询最新数据 | ||
| 112 | + * | ||
| 113 | + * @param tagsSelectDao 查询条件 | ||
| 114 | + * @return 数据 | ||
| 115 | + */ | ||
| 116 | + Map<String, Map<String, Object>> getLastDataByTags(TagsSelectDao tagsSelectDao); | ||
| 117 | + | ||
| 118 | + /** | ||
| 119 | + * 获取历史数据 | ||
| 120 | + * | ||
| 121 | + * @param selectVisualDto 查询条件 | ||
| 122 | + * @return 数据 | ||
| 123 | + */ | ||
| 124 | + List<Map<String, Object>> getHistoryData(SelectVisualDto selectVisualDto); | ||
| 125 | + | ||
| 126 | + /** | ||
| 127 | + * 获取实时数据 | ||
| 128 | + * | ||
| 129 | + * @param selectVisualDto 查询条件 | ||
| 130 | + * @return 数据 | ||
| 131 | + */ | ||
| 132 | + List<Map<String, Object>> getRealtimeData(SelectVisualDto selectVisualDto); | ||
| 133 | + | ||
| 134 | + /** | ||
| 135 | + * 获取聚合数据 | ||
| 136 | + * | ||
| 137 | + * @param selectVisualDto 查询条件 | ||
| 138 | + * @return 数据 | ||
| 139 | + */ | ||
| 140 | + List<Map<String, Object>> getAggregateData(SelectVisualDto selectVisualDto); | ||
| 141 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.tdengine; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.iot.domain.FieldsVo; | ||
| 4 | +import cn.iocoder.yudao.module.iot.domain.SelectDto; | ||
| 5 | +import cn.iocoder.yudao.module.iot.domain.TableDto; | ||
| 6 | +import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; | ||
| 7 | +import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; | ||
| 8 | +import lombok.extern.slf4j.Slf4j; | ||
| 9 | +import org.springframework.stereotype.Service; | ||
| 10 | + | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +@Service | ||
| 15 | +@Slf4j | ||
| 16 | +public class TdEngineServiceImpl implements TdEngineService { | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + @Override | ||
| 20 | + public void createDateBase(String dataBaseName) { | ||
| 21 | + | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + @Override | ||
| 25 | + public void createSuperTable(List<FieldsVo> schemaFields, List<FieldsVo> tagsFields, String dataBaseName, String superTableName) { | ||
| 26 | + | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + @Override | ||
| 30 | + public void createTable(TableDto tableDto) { | ||
| 31 | + | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + @Override | ||
| 35 | + public void insertData(TableDto tableDto) { | ||
| 36 | + | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + @Override | ||
| 40 | + public List<Map<String, Object>> selectByTimesTamp(SelectDto selectDto) { | ||
| 41 | + return List.of(); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + @Override | ||
| 45 | + public void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) { | ||
| 46 | + | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + @Override | ||
| 50 | + public void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) { | ||
| 51 | + | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Override | ||
| 55 | + public Long getCountByTimesTamp(SelectDto selectDto) { | ||
| 56 | + return 0L; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + @Override | ||
| 60 | + public Integer checkTableExists(SelectDto selectDto) { | ||
| 61 | + return 0; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + @Override | ||
| 65 | + public void initSTableFrame(String msg) { | ||
| 66 | + | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + @Override | ||
| 70 | + public Map<String, Object> getLastData(SelectDto selectDto) { | ||
| 71 | + return Map.of(); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + @Override | ||
| 75 | + public Map<String, Map<String, Object>> getLastDataByTags(TagsSelectDao tagsSelectDao) { | ||
| 76 | + return Map.of(); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + @Override | ||
| 80 | + public List<Map<String, Object>> getHistoryData(SelectVisualDto selectVisualDto) { | ||
| 81 | + return List.of(); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + @Override | ||
| 85 | + public List<Map<String, Object>> getRealtimeData(SelectVisualDto selectVisualDto) { | ||
| 86 | + return List.of(); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + @Override | ||
| 90 | + public List<Map<String, Object>> getAggregateData(SelectVisualDto selectVisualDto) { | ||
| 91 | + return List.of(); | ||
| 92 | + } | ||
| 93 | +} | ||
| 0 | \ No newline at end of file | 94 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
| @@ -62,4 +62,10 @@ public interface IotThinkModelFunctionService { | @@ -62,4 +62,10 @@ public interface IotThinkModelFunctionService { | ||
| 62 | */ | 62 | */ |
| 63 | PageResult<IotThinkModelFunctionDO> getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO); | 63 | PageResult<IotThinkModelFunctionDO> getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO); |
| 64 | 64 | ||
| 65 | + /** | ||
| 66 | + * 创建超级表数据模型 | ||
| 67 | + * | ||
| 68 | + * @param productId 产品编号 | ||
| 69 | + */ | ||
| 70 | + void createSuperTableDataModel(Long productId); | ||
| 65 | } | 71 | } |
| 66 | \ No newline at end of file | 72 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
| @@ -15,10 +15,13 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode | @@ -15,10 +15,13 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode | ||
| 15 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; | 15 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; |
| 16 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; | 16 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; |
| 17 | import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; | 17 | import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; |
| 18 | +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | ||
| 18 | import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; | 19 | import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; |
| 19 | import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; | 20 | import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; |
| 20 | import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum; | 21 | import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum; |
| 21 | import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; | 22 | import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; |
| 23 | +import cn.iocoder.yudao.module.iot.service.product.IotProductService; | ||
| 24 | +import cn.iocoder.yudao.module.iot.service.tdengine.IotDbStructureDataService; | ||
| 22 | import jakarta.annotation.Resource; | 25 | import jakarta.annotation.Resource; |
| 23 | import lombok.extern.slf4j.Slf4j; | 26 | import lombok.extern.slf4j.Slf4j; |
| 24 | import org.springframework.stereotype.Service; | 27 | import org.springframework.stereotype.Service; |
| @@ -45,6 +48,11 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | @@ -45,6 +48,11 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | ||
| 45 | @Resource | 48 | @Resource |
| 46 | private IotThinkModelFunctionMapper thinkModelFunctionMapper; | 49 | private IotThinkModelFunctionMapper thinkModelFunctionMapper; |
| 47 | 50 | ||
| 51 | + @Resource | ||
| 52 | + private IotProductService productService; | ||
| 53 | + @Resource | ||
| 54 | + private IotDbStructureDataService dbStructureDataService; | ||
| 55 | + | ||
| 48 | @Override | 56 | @Override |
| 49 | @Transactional(rollbackFor = Exception.class) | 57 | @Transactional(rollbackFor = Exception.class) |
| 50 | public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { | 58 | public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { |
| @@ -162,6 +170,16 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | @@ -162,6 +170,16 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | ||
| 162 | return thinkModelFunctionMapper.selectPage(pageReqVO); | 170 | return thinkModelFunctionMapper.selectPage(pageReqVO); |
| 163 | } | 171 | } |
| 164 | 172 | ||
| 173 | + @Override | ||
| 174 | + public void createSuperTableDataModel(Long productId) { | ||
| 175 | + // 1. 查询产品 | ||
| 176 | + IotProductDO product = productService.getProduct(productId); | ||
| 177 | + // 2. 查询产品的物模型功能列表 | ||
| 178 | + List<IotThinkModelFunctionDO> functionList = thinkModelFunctionMapper.selectListByProductId(productId); | ||
| 179 | + // 3. 生成 TDengine 的数据模型 | ||
| 180 | + dbStructureDataService.createSuperTableDataModel(product, functionList); | ||
| 181 | + } | ||
| 182 | + | ||
| 165 | /** | 183 | /** |
| 166 | * 创建默认的事件和服务 | 184 | * 创建默认的事件和服务 |
| 167 | */ | 185 | */ |
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
| 3 | + | ||
| 4 | +<mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper"> | ||
| 5 | + | ||
| 6 | + <update id="createDatabase" parameterType="String"> | ||
| 7 | + create database if not exists #{dataBaseName} | ||
| 8 | + </update> | ||
| 9 | + | ||
| 10 | + <update id="createSuperTable"> | ||
| 11 | + create table if not exists #{dataBaseName}.#{superTableName} | ||
| 12 | + <foreach item="item" collection="schemaFields" separator="," | ||
| 13 | + open="(" close=")" index=""> | ||
| 14 | + <if test="item.fieldName != null || item.fieldName != ''"> | ||
| 15 | + ${item.fieldName} | ||
| 16 | + </if> | ||
| 17 | + <if test="item.dataType != null || item.dataType != ''"> | ||
| 18 | + <choose> | ||
| 19 | + <when test="item.dataType == 'timestamp'"> | ||
| 20 | + timestamp | ||
| 21 | + </when> | ||
| 22 | + <when test="item.dataType == 'tinyint'"> | ||
| 23 | + tinyint | ||
| 24 | + </when> | ||
| 25 | + <when test="item.dataType == 'smallint'"> | ||
| 26 | + smallint | ||
| 27 | + </when> | ||
| 28 | + <when test="item.dataType == 'int'"> | ||
| 29 | + int | ||
| 30 | + </when> | ||
| 31 | + <when test="item.dataType == 'bigint'"> | ||
| 32 | + bigint | ||
| 33 | + </when> | ||
| 34 | + <when test="item.dataType == 'float'"> | ||
| 35 | + float | ||
| 36 | + </when> | ||
| 37 | + <when test="item.dataType == 'double'"> | ||
| 38 | + double | ||
| 39 | + </when> | ||
| 40 | + <when test="item.dataType == 'binary'"> | ||
| 41 | + binary | ||
| 42 | + </when> | ||
| 43 | + <when test="item.dataType == 'nchar'"> | ||
| 44 | + nchar | ||
| 45 | + </when> | ||
| 46 | + <when test="item.dataType == 'bool'"> | ||
| 47 | + bool | ||
| 48 | + </when> | ||
| 49 | + <when test="item.dataType == 'json'"> | ||
| 50 | + json | ||
| 51 | + </when> | ||
| 52 | + </choose> | ||
| 53 | + </if> | ||
| 54 | + <if test="item.size != null"> | ||
| 55 | + (#{item.size}) | ||
| 56 | + </if> | ||
| 57 | + </foreach> | ||
| 58 | + tags | ||
| 59 | + <!--tdEngine不支持动态tags里的数据类型,只能使用choose标签比对--> | ||
| 60 | + <foreach item="item" collection="tagsFields" separator="," | ||
| 61 | + open="(" close=")" index=""> | ||
| 62 | + <if test="item.fieldName != null || item.fieldName != ''"> | ||
| 63 | + ${item.fieldName} | ||
| 64 | + </if> | ||
| 65 | + <if test="item.dataType != null || item.dataType != ''"> | ||
| 66 | + <choose> | ||
| 67 | + <when test="item.dataType == 'timestamp'"> | ||
| 68 | + timestamp | ||
| 69 | + </when> | ||
| 70 | + <when test="item.dataType == 'tinyint'"> | ||
| 71 | + tinyint | ||
| 72 | + </when> | ||
| 73 | + <when test="item.dataType == 'smallint'"> | ||
| 74 | + smallint | ||
| 75 | + </when> | ||
| 76 | + <when test="item.dataType == 'int'"> | ||
| 77 | + int | ||
| 78 | + </when> | ||
| 79 | + <when test="item.dataType == 'bigint'"> | ||
| 80 | + bigint | ||
| 81 | + </when> | ||
| 82 | + <when test="item.dataType == 'float'"> | ||
| 83 | + float | ||
| 84 | + </when> | ||
| 85 | + <when test="item.dataType == 'double'"> | ||
| 86 | + double | ||
| 87 | + </when> | ||
| 88 | + <when test="item.dataType == 'binary'"> | ||
| 89 | + binary | ||
| 90 | + </when> | ||
| 91 | + <when test="item.dataType == 'nchar'"> | ||
| 92 | + nchar | ||
| 93 | + </when> | ||
| 94 | + <when test="item.dataType == 'bool'"> | ||
| 95 | + bool | ||
| 96 | + </when> | ||
| 97 | + <when test="item.dataType == 'json'"> | ||
| 98 | + json | ||
| 99 | + </when> | ||
| 100 | + </choose> | ||
| 101 | + </if> | ||
| 102 | + <if test="item.size != null"> | ||
| 103 | + (#{item.size}) | ||
| 104 | + </if> | ||
| 105 | + </foreach> | ||
| 106 | + </update> | ||
| 107 | + | ||
| 108 | + <update id="createTable"> | ||
| 109 | + create table | ||
| 110 | + if not exists #{dataBaseName}.#{tableName} | ||
| 111 | + using #{dataBaseName}.#{superTableName} | ||
| 112 | + tags | ||
| 113 | + <foreach item="item" collection="tagsFieldValues" separator="," | ||
| 114 | + open="(" close=")" index=""> | ||
| 115 | + #{item.fieldValue} | ||
| 116 | + </foreach> | ||
| 117 | + </update> | ||
| 118 | + | ||
| 119 | + <insert id="insertData"> | ||
| 120 | + insert into #{dataBaseName}.#{tableName} | ||
| 121 | + <foreach item="item" collection="schemaFieldValues" separator="," | ||
| 122 | + open="(" close=")" index=""> | ||
| 123 | + #{item.fieldName} | ||
| 124 | + </foreach> | ||
| 125 | + using #{dataBaseName}.#{superTableName} | ||
| 126 | + tags | ||
| 127 | + <foreach item="item" collection="tagsFieldValues" separator="," | ||
| 128 | + open="(" close=")" index=""> | ||
| 129 | + #{item.fieldValue} | ||
| 130 | + </foreach> | ||
| 131 | + values | ||
| 132 | + <foreach item="item" collection="schemaFieldValues" separator="," | ||
| 133 | + open="(" close=")" index=""> | ||
| 134 | + #{item.fieldValue} | ||
| 135 | + </foreach> | ||
| 136 | + </insert> | ||
| 137 | + | ||
| 138 | + | ||
| 139 | + <select id="selectByTimestamp" parameterType="cn.iocoder.yudao.module.iot.domain.SelectDto" | ||
| 140 | + resultType="Map"> | ||
| 141 | + select * from #{dataBaseName}.#{tableName} | ||
| 142 | + <!--查询这里不能使用#{}占位符的方式,使用这种方式,tdEngine不识别为列名,只能使用${}占位的方式--> | ||
| 143 | + <!--因为tdEngine引擎一次只执行一条sql,所以有效预防了sql的注入,且该服务该接口为内部调用,所以可以使用${}--> | ||
| 144 | + where ${fieldName} | ||
| 145 | + between #{startTime} and #{endTime} | ||
| 146 | + </select> | ||
| 147 | + | ||
| 148 | + <update id="addColumnForSuperTable"> | ||
| 149 | + ALTER | ||
| 150 | + STABLE | ||
| 151 | + #{superTableName} | ||
| 152 | + ADD | ||
| 153 | + COLUMN | ||
| 154 | + <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''"> | ||
| 155 | + #{fieldsVo.fieldName} | ||
| 156 | + </if> | ||
| 157 | + <if test="fieldsVo.dataType != null || fieldsVo.dataType != ''"> | ||
| 158 | + <choose> | ||
| 159 | + <when test="fieldsVo.dataType == 'timestamp'"> | ||
| 160 | + timestamp | ||
| 161 | + </when> | ||
| 162 | + <when test="fieldsVo.dataType == 'tinyint'"> | ||
| 163 | + tinyint | ||
| 164 | + </when> | ||
| 165 | + <when test="fieldsVo.dataType == 'smallint'"> | ||
| 166 | + smallint | ||
| 167 | + </when> | ||
| 168 | + <when test="fieldsVo.dataType == 'int'"> | ||
| 169 | + int | ||
| 170 | + </when> | ||
| 171 | + <when test="fieldsVo.dataType == 'bigint'"> | ||
| 172 | + bigint | ||
| 173 | + </when> | ||
| 174 | + <when test="fieldsVo.dataType == 'float'"> | ||
| 175 | + float | ||
| 176 | + </when> | ||
| 177 | + <when test="fieldsVo.dataType == 'double'"> | ||
| 178 | + double | ||
| 179 | + </when> | ||
| 180 | + <when test="fieldsVo.dataType == 'binary'"> | ||
| 181 | + binary | ||
| 182 | + </when> | ||
| 183 | + <when test="fieldsVo.dataType == 'nchar'"> | ||
| 184 | + nchar | ||
| 185 | + </when> | ||
| 186 | + <when test="fieldsVo.dataType == 'bool'"> | ||
| 187 | + bool | ||
| 188 | + </when> | ||
| 189 | + <when test="fieldsVo.dataType == 'json'"> | ||
| 190 | + json | ||
| 191 | + </when> | ||
| 192 | + </choose> | ||
| 193 | + </if> | ||
| 194 | + <if test="fieldsVo.size != null"> | ||
| 195 | + ( | ||
| 196 | + #{fieldsVo.size} | ||
| 197 | + ) | ||
| 198 | + </if> | ||
| 199 | + </update> | ||
| 200 | + | ||
| 201 | + <update id="dropColumnForSuperTable"> | ||
| 202 | + ALTER | ||
| 203 | + STABLE | ||
| 204 | + #{superTableName} | ||
| 205 | + DROP | ||
| 206 | + COLUMN | ||
| 207 | + <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''"> | ||
| 208 | + #{fieldsVo.fieldName} | ||
| 209 | + </if> | ||
| 210 | + </update> | ||
| 211 | + | ||
| 212 | + <update id="addTagForSuperTable"> | ||
| 213 | + ALTER | ||
| 214 | + STABLE | ||
| 215 | + #{superTableName} | ||
| 216 | + ADD | ||
| 217 | + TAG | ||
| 218 | + <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''"> | ||
| 219 | + #{fieldsVo.fieldName} | ||
| 220 | + </if> | ||
| 221 | + <if test="fieldsVo.dataType != null || fieldsVo.dataType != ''"> | ||
| 222 | + <choose> | ||
| 223 | + <when test="fieldsVo.dataType == 'timestamp'"> | ||
| 224 | + timestamp | ||
| 225 | + </when> | ||
| 226 | + <when test="fieldsVo.dataType == 'tinyint'"> | ||
| 227 | + tinyint | ||
| 228 | + </when> | ||
| 229 | + <when test="fieldsVo.dataType == 'smallint'"> | ||
| 230 | + smallint | ||
| 231 | + </when> | ||
| 232 | + <when test="fieldsVo.dataType == 'int'"> | ||
| 233 | + int | ||
| 234 | + </when> | ||
| 235 | + <when test="fieldsVo.dataType == 'bigint'"> | ||
| 236 | + bigint | ||
| 237 | + </when> | ||
| 238 | + <when test="fieldsVo.dataType == 'float'"> | ||
| 239 | + float | ||
| 240 | + </when> | ||
| 241 | + <when test="fieldsVo.dataType == 'double'"> | ||
| 242 | + double | ||
| 243 | + </when> | ||
| 244 | + <when test="fieldsVo.dataType == 'binary'"> | ||
| 245 | + binary | ||
| 246 | + </when> | ||
| 247 | + <when test="fieldsVo.dataType == 'nchar'"> | ||
| 248 | + nchar | ||
| 249 | + </when> | ||
| 250 | + <when test="fieldsVo.dataType == 'bool'"> | ||
| 251 | + bool | ||
| 252 | + </when> | ||
| 253 | + <when test="fieldsVo.dataType == 'json'"> | ||
| 254 | + json | ||
| 255 | + </when> | ||
| 256 | + </choose> | ||
| 257 | + </if> | ||
| 258 | + <if test="fieldsVo.size != null"> | ||
| 259 | + ( | ||
| 260 | + #{fieldsVo.size} | ||
| 261 | + ) | ||
| 262 | + </if> | ||
| 263 | + </update> | ||
| 264 | + | ||
| 265 | + <update id="dropTagForSuperTable"> | ||
| 266 | + ALTER | ||
| 267 | + STABLE | ||
| 268 | + #{superTableName} | ||
| 269 | + DROP | ||
| 270 | + TAG | ||
| 271 | + <if test="fieldsVo.fieldName != null || fieldsVo.fieldName != ''"> | ||
| 272 | + #{fieldsVo.fieldName} | ||
| 273 | + </if> | ||
| 274 | + </update> | ||
| 275 | + | ||
| 276 | + <select id="getCountByTimestamp" parameterType="cn.iocoder.yudao.module.iot.domain.SelectDto" | ||
| 277 | + resultType="java.util.Map"> | ||
| 278 | + SELECT count(0) AS count | ||
| 279 | + FROM #{dataBaseName}.#{tableName} WHERE ${fieldName} BETWEEN #{startTime} AND #{endTime} | ||
| 280 | + </select> | ||
| 281 | + | ||
| 282 | + <select id="checkTableExists" resultType="java.lang.Integer"> | ||
| 283 | + SELECT COUNT(0) | ||
| 284 | + FROM information_schema.ins_tables | ||
| 285 | + WHERE db_name = #{dataBaseName} | ||
| 286 | + AND table_name = #{tableName} | ||
| 287 | + </select> | ||
| 288 | + | ||
| 289 | + <select id="getLastData" resultType="java.util.Map"> | ||
| 290 | + select last(time), * | ||
| 291 | + from #{tableName} | ||
| 292 | + where device_id = #{deviceId} | ||
| 293 | + </select> | ||
| 294 | + | ||
| 295 | + <select id="getLastDataByTags" parameterType="cn.iocoder.yudao.module.iot.domain.TagsSelectDao" | ||
| 296 | + resultType="Map"> | ||
| 297 | + select last(*) | ||
| 298 | + from #{dataBaseName}.#{stableName} group by ${tagsName} | ||
| 299 | + </select> | ||
| 300 | + | ||
| 301 | + <select id="getHistoryData" resultType="java.util.Map" | ||
| 302 | + parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto"> | ||
| 303 | + SELECT #{fieldName}, ts | ||
| 304 | + FROM #{dataBaseName}.#{tableName} WHERE ts BETWEEN #{startTime} AND #{endTime} | ||
| 305 | + LIMIT #{num} | ||
| 306 | + </select> | ||
| 307 | + <select id="getRealtimeData" resultType="java.util.Map" | ||
| 308 | + parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto"> | ||
| 309 | + SELECT #{fieldName}, ts | ||
| 310 | + FROM #{dataBaseName}.#{tableName} LIMIT #{num} | ||
| 311 | + </select> | ||
| 312 | + <select id="getAggregateData" resultType="java.util.Map" | ||
| 313 | + parameterType="cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto"> | ||
| 314 | + SELECT #{aggregate}(${fieldName}) | ||
| 315 | + FROM #{dataBaseName}.#{tableName} WHERE ts BETWEEN #{startTime} AND #{endTime} interval (${interval}) | ||
| 316 | + LIMIT #{num} | ||
| 317 | + </select> | ||
| 318 | + | ||
| 319 | + | ||
| 320 | + <insert id="createSuperTableDevice"> | ||
| 321 | + ${sql} | ||
| 322 | + </insert> | ||
| 323 | + | ||
| 324 | +</mapper> |