From 05c54827152157983661a391c73d04b2615638c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 23 Oct 2024 23:23:40 +0800 Subject: [PATCH 001/228] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91=20=E9=9B=86=E6=88=90=20tdengine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 7 + .../yudao-spring-boot-starter-mybatis/pom.xml | 4 + .../yudao/module/iot/domain/BaseEntity.java | 25 ++ .../iot/domain/DeviceDataExportExcelDto.java | 35 ++ .../yudao/module/iot/domain/DeviceDataVo.java | 19 + .../yudao/module/iot/domain/Fields.java | 72 ++++ .../yudao/module/iot/domain/FieldsVo.java | 68 ++++ .../module/iot/domain/IotSequential.java | 71 ++++ .../module/iot/domain/MessageCountVo.java | 25 ++ .../iot/domain/ProductSuperTableModel.java | 39 +++ .../yudao/module/iot/domain/SelectDto.java | 37 ++ .../module/iot/domain/SuperTableDto.java | 38 ++ .../yudao/module/iot/domain/TableDto.java | 33 ++ .../module/iot/domain/TagsSelectDao.java | 33 ++ .../yudao/module/iot/domain/Weather.java | 73 ++++ .../iot/domain/visual/SelectVisualDto.java | 58 ++++ .../product/IotProductFunctionTypeEnum.java | 9 + yudao-module-iot/yudao-module-iot-biz/pom.xml | 5 + .../admin/product/IotProductController.java | 5 +- .../thingModel/ThingModelRespVO.java | 51 +++ .../dal/dataobject/tdengine/FieldParser.java | 80 +++++ .../dal/dataobject/tdengine/TableData.java | 36 ++ .../dal/dataobject/tdengine/TableManager.java | 155 +++++++++ .../iot/dal/dataobject/tdengine/TdField.java | 29 ++ .../dal/dataobject/tdengine/TdResponse.java | 26 ++ .../dal/dataobject/tdengine/TdRestApi.java | 55 +++ .../iot/dal/dataobject/tdengine/TimeData.java | 25 ++ .../iot/dal/tdengine/TdEngineMapper.java | 74 ++++ .../iot/framework/aspect/TaosAspect.java | 38 ++ .../product/IotProductServiceImpl.java | 15 + .../tdengine/IotDbStructureDataService.java | 29 ++ .../IotDbStructureDataServiceImpl.java | 168 +++++++++ .../iot/service/tdengine/TdEngineService.java | 141 ++++++++ .../service/tdengine/TdEngineServiceImpl.java | 93 +++++ .../IotThinkModelFunctionService.java | 6 + .../IotThinkModelFunctionServiceImpl.java | 18 + .../mapper/tdengine/TdEngineMapper.xml | 324 ++++++++++++++++++ 37 files changed, 2016 insertions(+), 3 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataExportExcelDto.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataVo.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/IotSequential.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/MessageCountVo.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Weather.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdField.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 924e52eed..486fe124b 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -33,6 +33,7 @@ 8.1.3.62 8.6.0 5.0.2 + 3.3.3 2.3.0 @@ -253,6 +254,12 @@ ${kingbase.jdbc.version} + + com.taosdata.jdbc + taos-jdbcdriver + ${taos.version} + + cn.iocoder.boot diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml index 1f04e4a63..e907a2de4 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -63,6 +63,10 @@ opengauss-jdbc true + + com.taosdata.jdbc + taos-jdbcdriver + com.alibaba diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java new file mode 100644 index 000000000..74a4c8494 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.Data; + +/** + * @ClassDescription: tdEngine的基础实体类 + * @ClassName: BaseEntity + * @Author: fxlinks + * @Date: 2021-12-30 14:39:25 + * @Version 1.0 + */ +@Data +public class BaseEntity { + private static final long serialVersionUID = 1L; + + /** + * 数据库名称 + */ + private String dataBaseName; + + /** + * 超级表名称 + */ + private String superTableName; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataExportExcelDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataExportExcelDto.java new file mode 100644 index 000000000..cedb4d119 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataExportExcelDto.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.Data; + +/** + * 设备数据导出 excel DTO + */ +@Data +public class DeviceDataExportExcelDto { + + /** + * 设备标识 + */ + private String deviceKey; + + /** + * 导出形式 1 单个参数导出 2 全部参数导出 + */ + private String exportType; + + /** + * 导出开始时间 + */ + private String exportBeginTime; + + /** + * 导出结束时间 + */ + private String exportEndTime; + + /** + * 导出参数,空则导出全部 + */ + private String exportParameter; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataVo.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataVo.java new file mode 100644 index 000000000..b9f6fc412 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataVo.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.Data; + +/** + * @ClassDescription: 查询可视化所需入参对象 + * @ClassName: SelectDto + * @Author: andyz + * @Date: 2022-07-29 14:12:26 + * @Version 1.0 + */ +@Data +public class DeviceDataVo { + + + private String deviceId; + + private Long lastTime; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java new file mode 100644 index 000000000..bbd7bb74e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.Data; + +/** + * @ClassDescription: 建表的字段实体类 + * @ClassName: Fields + * @Author: fxlinks + * @Date: 2021-12-28 09:09:04 + * @Version 1.0 + */ +@Data +public class Fields { + private static final long serialVersionUID = 1L; + + /** + * 字段名称 + */ + private String fieldName; + + /** + * 字段值 + */ + private Object fieldValue; + + /** + * 字段数据类型 + */ +// private DataTypeEnum dataType; + + /** + * 字段字节大小 + */ + private Integer size; + + public Fields() { + } + + public Fields(String fieldName, String dataType, Integer size) { +// this.fieldName = fieldName; +// //根据规则匹配字段数据类型 +// switch (dataType.toLowerCase()) { +// case ("json"): +// this.dataType = DataTypeEnum.JSON; +// this.size = size; +// break; +// case ("string"): +// this.dataType = DataTypeEnum.NCHAR; +// this.size = size; +// break; +// case ("binary"): +// this.dataType = DataTypeEnum.BINARY; +// this.size = size; +// break; +// case ("int"): +// this.dataType = DataTypeEnum.INT; +// break; +// case ("bool"): +// this.dataType = DataTypeEnum.BOOL; +// break; +// case ("decimal"): +// this.dataType = DataTypeEnum.DOUBLE; +// break; +// case ("timestamp"): +// if ("eventTime".equals(fieldName)) { +// this.fieldName = "eventTime"; +// } +// this.dataType = DataTypeEnum.TIMESTAMP; +// break; +// } + } +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java new file mode 100644 index 000000000..554d52149 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.Data; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * @ClassDescription: 建表的字段实体类的vo类 + * @ClassName: FieldsVo + * @Author: fxlinks + * @Date: 2021-12-28 11:30:06 + * @Version 1.0 + */ +@Data +public class FieldsVo { + private static final long serialVersionUID = 1L; + + /** + * 字段名称 + */ + private String fieldName; + + /** + * 字段数据类型 + */ + private String dataType; + + /** + * 字段字节大小 + */ + private Integer size; + + /** + * @param fields 字段实体类 + * @return FieldsVo 字段实体vo类 + * @MethodDescription 字段实体类转为vo类 + * @author fx + * @Date 2021/12/28 13:48 + */ + public static FieldsVo fieldsTranscoding(Fields fields) throws SQLException { +// if (StringUtils.isBlank(fields.getFieldName()) || fields.getDataType() == null) { +// throw new SQLException("invalid operation: fieldName or dataType can not be null"); +// } +// FieldsVo fieldsVo = new FieldsVo(); +// fieldsVo.setFieldName(fields.getFieldName()); +// fieldsVo.setDataType(fields.getDataType().getDataType()); +// fieldsVo.setSize(fields.getSize()); +// return fieldsVo; + return null; + } + + /** + * @param fieldsList 字段实体类集合 + * @return List 字段实体vo类集合 + * @MethodDescription 字段实体类集合转为vo类集合 + * @author fx + * @Date 2021/12/28 14:00 + */ + public static List fieldsTranscoding(List fieldsList) throws SQLException { + List fieldsVoList = new ArrayList<>(); + for (Fields fields : fieldsList) { + fieldsVoList.add(fieldsTranscoding(fields)); + } + return fieldsVoList; + } +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/IotSequential.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/IotSequential.java new file mode 100644 index 000000000..349d6d137 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/IotSequential.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.sql.Timestamp; + +public class IotSequential extends BaseEntity { + private static final long serialVersionUID = 1L; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") + private Timestamp statetime; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") + private Timestamp endtime; + + private String deviceid; + + private String eventtime; + + private String serviceid; + + private String devices; + + public String getDeviceid() { + return deviceid; + } + + public void setDeviceid(String deviceid) { + this.deviceid = deviceid; + } + + public String getEventtime() { + return eventtime; + } + + public void setEventtime(String eventtime) { + this.eventtime = eventtime; + } + + public String getServiceid() { + return serviceid; + } + + public void setServiceid(String serviceid) { + this.serviceid = serviceid; + } + + public String getDevices() { + return devices; + } + + public void setDevices(String devices) { + this.devices = devices; + } + + public Timestamp getStatetime() { + return statetime; + } + + public void setStatetime(Timestamp statetime) { + this.statetime = statetime; + } + + public Timestamp getEndtime() { + return endtime; + } + + public void setEndtime(Timestamp endtime) { + this.endtime = endtime; + } +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/MessageCountVo.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/MessageCountVo.java new file mode 100644 index 000000000..e9e93cac0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/MessageCountVo.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 统计的时间数据 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MessageCountVo { + + /** + * 时间 + */ + private String time; + + /** + * 数据值 + */ + private Object data; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java new file mode 100644 index 000000000..49887415c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.iot.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.Optional; + +/** + * @Description: 产品超级表模型 + * @Author: fx + * @Website: http://www.sxfxck.com + * @CreateDate: 2022/1/1$ 19:37$ + * @UpdateUser: fx + * @UpdateDate: 2022/1/1$ 19:37$ + * @UpdateRemark: 修改内容 + * @Version: V1.0 + */ +@Data +public class ProductSuperTableModel { + private static final long serialVersionUID = 1L; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") + private Timestamp ts; + + private String superTableName; + + /** + * columnsName,columnsProperty + */ + private HashMap columns; + + /** + * tagsName,tagsProperty + */ + private HashMap tags; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java new file mode 100644 index 000000000..381ef3d6f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.Data; + +import java.util.Set; + +/** + * @ClassDescription: 查询所需入参对象 + * @ClassName: SelectDto + * @Author: fxlinks + * @Date: 2022-01-07 14:12:26 + * @Version 1.0 + */ +@Data +public class SelectDto { + + // @NotBlank(message = "invalid operation: dataBaseName can not be empty") + private String dataBaseName; + +// @NotBlank(message = "invalid operation: tableName can not be empty") + private String tableName; + + // @NotBlank(message = "invalid operation: fieldName can not be empty") + private String fieldName; + + // @NotNull(message = "invalid operation: startTime can not be null") + private Long startTime; + + // @NotNull(message = "invalid operation: endTime can not be null") + private Long endTime; + + private String type; + + private Set orgIds; + + private String deviceId; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java new file mode 100644 index 000000000..ee80d42cf --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.Data; + +import java.util.List; + +/** + * @ClassDescription: 创建超级表需要的入参的实体类 + * @ClassName: SuperTableDto + * @Author: fxlinks + * @Date: 2021-12-28 15:03:45 + * @Version 1.0 + */ +@Data +public class SuperTableDto extends BaseEntity { + + /** + * 超级表的表结构(业务相关) + * 第一个字段的数据类型必须为timestamp + * 字符相关数据类型必须指定大小 + * 字段名称和字段数据类型不能为空 + */ +// @NotEmpty(message = "invalid operation: schemaFields can not be empty") + private List schemaFields; + + /** + * 超级表的标签字段,可以作为子表在超级表里的标识 + * 字符相关数据类型必须指定大小 + * 字段名称和字段数据类型不能为空 + */ +// @NotEmpty(message = "invalid operation: tagsFields can not be empty") + private List tagsFields; + + /** + * 字段信息对象,超级表添加列时使用该属性 + */ + private Fields fields; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java new file mode 100644 index 000000000..f27beb1a6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.Data; + +import java.util.List; + +/** + * @ClassDescription: 创建超级表的子表需要的入参的实体类 + * @ClassName: TableDto + * @Author: fxlinks + * @Date: 2021-12-30 14:42:47 + * @Version 1.0 + */ +@Data +public class TableDto extends BaseEntity { + + /** + * 超级表普通列字段的值 + * 值需要与创建超级表时普通列字段的数据类型对应上 + */ + private List schemaFieldValues; + + /** + * 超级表标签字段的值 + * 值需要与创建超级表时标签字段的数据类型对应上 + */ + private List tagsFieldValues; + + /** + * 表名称 + */ + private String tableName; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java new file mode 100644 index 000000000..5cb9c5ed9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.domain; + +import lombok.Data; + + +/** + * @program: fxlinks + * @description: 标签查询模型 + * @packagename: com.fx.tdengine.api.domain.rule + * @author: fx + * @e-mainl: 13733918655@163.com + * @date: 2022-07-27 18:40 + **/ +@Data +public class TagsSelectDao { + +// @NotBlank(message = "invalid operation: dataBaseName can not be empty") + private String dataBaseName; + +// @NotBlank(message = "invalid operation: stableName can not be empty") + private String stableName; + +// @NotBlank(message = "invalid operation: tagsName can not be empty") + private String tagsName; + + // @NotNull(message = "invalid operation: startTime can not be null") + private Long startTime; + + // @NotNull(message = "invalid operation: endTime can not be null") + private Long endTime; + + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Weather.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Weather.java new file mode 100644 index 000000000..a4a1e983b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Weather.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.iot.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.sql.Timestamp; + +public class Weather { + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") + private Timestamp ts; + private Float temperature; + private Float humidity; + private String location; + private String note; + private int groupId; + + public Weather() { + } + + public Weather(Timestamp ts, float temperature, float humidity) { + this.ts = ts; + this.temperature = temperature; + this.humidity = humidity; + } + + public Timestamp getTs() { + return ts; + } + + public void setTs(Timestamp ts) { + this.ts = ts; + } + + public Float getTemperature() { + return temperature; + } + + public void setTemperature(Float temperature) { + this.temperature = temperature; + } + + public Float getHumidity() { + return humidity; + } + + public void setHumidity(Float humidity) { + this.humidity = humidity; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public int getGroupId() { + return groupId; + } + + public void setGroupId(int groupId) { + this.groupId = groupId; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java new file mode 100644 index 000000000..1444da972 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.iot.domain.visual; + +import lombok.Data; + +import java.util.Map; + +/** + * @ClassDescription: 查询可视化所需入参对象 + * @ClassName: SelectDto + * @Author: andyz + * @Date: 2022-07-29 14:12:26 + * @Version 1.0 + */ +@Data +public class SelectVisualDto { + +// @NotBlank(message = "invalid operation: tableName can not be empty") + private String dataBaseName; + +// @NotBlank(message = "invalid operation: tableName can not be empty") + private String tableName; + +// @NotBlank(message = "invalid operation: fieldName can not be empty") //属性 + private String fieldName; + /** + * 查询类型,0历史数据,1实时数据,2聚合数据 + */ + private int type; + /** + * 查询的数据量 + */ + private int num; + /** + * 聚合函数 + */ + private String aggregate; + /** + * 统计间隔数字+s/m/h/d + * 比如1s,1m,1h,1d代表1秒,1分钟,1小时,1天 + */ + private String interval; + // @NotNull(message = "invalid operation: startTime can not be null") + private Long startTime; + + // @NotNull(message = "invalid operation: endTime can not be null") + private Long endTime; + + /** + * 请求参数 + */ + private Map params; + + private String sql; + + private String deviceId; + + private Long lastTime; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java index 7a924997a..b99d2b093 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java +++ b/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 { */ private final String description; + public static IotProductFunctionTypeEnum valueOf(Integer type) { + for (IotProductFunctionTypeEnum value : values()) { + if (value.getType().equals(type)) { + return value; + } + } + return null; + } + @Override public int[] array() { return ARRAYS; diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index e3f93086a..cb2fd818f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -42,6 +42,11 @@ yudao-spring-boot-starter-mybatis + + cn.iocoder.boot + yudao-spring-boot-starter-redis + + cn.iocoder.boot diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index 5b0ecb27a..e7f41d91d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/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 { return success(BeanUtils.toBean(pageResult, IotProductRespVO.class)); } - // TODO @haohao:改成 simple-list 哈 - @GetMapping("/list-all-simple") + @GetMapping("/simple-list") @Operation(summary = "获得所有产品列表") @PreAuthorize("@ss.hasPermission('iot:product:query')") - public CommonResult> listAllSimpleProducts() { + public CommonResult> getSimpleProductList() { List list = productService.getProductList(); return success(BeanUtils.toBean(list, IotProductSimpleRespVO.class)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java new file mode 100644 index 000000000..6fc48ef4f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.*; + +import java.util.List; +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class ThingModelRespVO { + + /** + * 产品编号 + */ + private Long id; + + /** + * 产品标识 + */ + private String productKey; + + /** + * 物模型 + */ + private Model model; + + /** + * 物模型 + */ + @Data + public static class Model { + + /** + * 属性列表 + */ + private List properties; + + /** + * 服务列表 + */ + private List services; + + /** + * 事件列表 + */ + private List events; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java new file mode 100644 index 000000000..0a91e7cf1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + + +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelDataType; + +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +public class FieldParser { + + /** + * 物模型到td数据类型映射 + */ + private static final HashMap TYPE_MAPPING = new HashMap<>() {{ + put("INT", "INT"); + put("FLOAT", "FLOAT"); + put("DOUBLE", "DOUBLE"); + put("BOOL", "BOOL"); + put("ENUM", "NCHAR"); + put("TEXT", "NCHAR"); + put("DATE", "NCHAR"); + }}; + + + /** + * 将物模型字段转换为td字段 + * + * @param property 物模型属性 + * @return TdField对象 + */ + public static TdField parse(ThingModelProperty property) { + String fieldName = property.getIdentifier().toLowerCase(); + ThingModelDataType type = property.getDataType(); + + // 将物模型字段类型映射为td字段类型 + String fType = TYPE_MAPPING.get(type.getType().toUpperCase()); + + int len = -1; + // 如果字段类型为NCHAR,默认长度为64 + if ("NCHAR".equals(fType)) { + len = 64; + } + + return new TdField(fieldName, fType, len); + } + + /** + * 获取物模型中的字段列表 + */ + public static List parse(ThingModelRespVO thingModel) { + return thingModel.getModel().getProperties().stream().map(FieldParser::parse).collect(Collectors.toList()); + } + + /** + * 将从库中查出来的字段信息转换为td字段对象 + */ + public static List parse(List rows) { + return (List) rows.stream().map((r) -> { + List row = (List) r; + String type = row.get(1).toString().toUpperCase(); + return new TdField( + row.get(0).toString(), + type, + type.equals("NCHAR") ? Integer.parseInt(row.get(2).toString()) : -1); + }).collect(Collectors.toList()); + } + + /** + * 获取字段字义 + */ + public static String getFieldDefine(TdField field) { + return "`" + field.getName() + "`" + " " + (field.getLength() > 0 ? + String.format("%s(%d)", field.getType(), field.getLength()) + : field.getType()); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java new file mode 100644 index 000000000..1d42933d4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.Data; + +import java.util.List; + +@Data +public class TableData { + + /** + * 超级表普通列字段的名称 + */ + private List schemaFieldList; + + /** + * 超级表标签字段的值 + * 值需要与创建超级表时标签字段的数据类型对应上 + */ + private List tagsValueList; + + /** + * 超级表普通列字段的值 + * 值需要与创建超级表时普通列字段的数据类型对应上 + */ + private List schemaValueList; + + /** + * 表名称 + */ + private String tableName; + + /** + * 超级表名称 + */ + private String superTableName; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java new file mode 100644 index 000000000..1bf4ecf64 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java @@ -0,0 +1,155 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import java.util.List; + +public class TableManager { + + /** + * 创建超级表模板(含存在判断) + */ + private static final String CREATE_STABLE_INE_TPL = "CREATE STABLE IF NOT EXISTS %s (%s) TAGS (%s);"; + + /** + * 删除超级表 + */ + private static final String DROP_STABLE_TPL = "DROP STABLE IF EXISTS %s;"; + + /** + * 获取表的结构信息 + */ + private static final String DESC_TB_TPL = "DESCRIBE %s;"; + + /** + * 超级表增加列 + */ + private static final String ALTER_STABLE_ADD_COL_TPL = "ALTER STABLE %s ADD COLUMN %s;"; + + /** + * 超级表修改列 + */ + private static final String ALTER_STABLE_MODIFY_COL_TPL = "ALTER STABLE %s MODIFY COLUMN %s;"; + + /** + * 超级表删除列 + */ + private static final String ALTER_STABLE_DROP_COL_TPL = "ALTER STABLE %s DROP COLUMN %s;"; + + /** + * 创建普通表模板(含存在判断) + */ + private static final String CREATE_CTABLE_INE_TPL = "CREATE TABLE IF NOT EXISTS %s (%s)"; + + /** + * 获取创建表sql + */ + public static String getCreateSTableSql(String tbName, List fields, TdField... tags) { + if (fields.isEmpty()) { + return null; + } + + // 生成字段片段 + StringBuilder sbField = new StringBuilder("time TIMESTAMP,"); + + for (TdField field : fields) { + sbField.append(FieldParser.getFieldDefine(field)); + sbField.append(","); + } + sbField.deleteCharAt(sbField.length() - 1); + + String fieldFrag = sbField.toString(); + + // 生成tag + StringBuilder sbTag = new StringBuilder(); + for (TdField tag : tags) { + sbTag.append(FieldParser.getFieldDefine(tag)) + .append(","); + } + sbTag.deleteCharAt(sbTag.length() - 1); + + return String.format(CREATE_STABLE_INE_TPL, tbName, fieldFrag, sbTag); + + } + + /** + * 获取创建普通表sql + */ + public static String getCreateCTableSql(String tbName, List fields) { + if (fields.size() == 0) { + return null; + } + + //生成字段片段 + StringBuilder sbField = new StringBuilder("time timestamp,"); + + for (TdField field : fields) { + sbField.append(FieldParser.getFieldDefine(field)); + sbField.append(","); + } + sbField.deleteCharAt(sbField.length() - 1); + + String fieldFrag = sbField.toString(); + + return String.format(CREATE_CTABLE_INE_TPL, tbName, fieldFrag); + + } + + + /** + * 取正确的表名 + * + * @param name 表象 + */ + public static String rightTbName(String name) { + return name.toLowerCase().replace("-" , "_"); + } + + /** + * 获取表详情的sql + */ + public static String getDescTableSql(String tbName) { + return String.format(DESC_TB_TPL, tbName); + } + + /** + * 获取添加字段sql + */ + public static String getAddSTableColumnSql(String tbName, List fields) { + StringBuilder sbAdd = new StringBuilder(); + for (TdField field : fields) { + sbAdd.append(String.format(ALTER_STABLE_ADD_COL_TPL, + tbName, + FieldParser.getFieldDefine(field) + )); + } + return sbAdd.toString(); + } + + /** + * 获取修改字段sql + */ + public static String getModifySTableColumnSql(String tbName, List fields) { + StringBuilder sbModify = new StringBuilder(); + for (TdField field : fields) { + sbModify.append(String.format(ALTER_STABLE_MODIFY_COL_TPL, + tbName, + FieldParser.getFieldDefine(field) + )); + } + return sbModify.toString(); + } + + /** + * 获取删除字段sql + */ + public static String getDropSTableColumnSql(String tbName, List fields) { + StringBuilder sbDrop = new StringBuilder(); + for (TdField field : fields) { + sbDrop.append(String.format(ALTER_STABLE_DROP_COL_TPL, + tbName, + field.getName() + )); + } + return sbDrop.toString(); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdField.java new file mode 100644 index 000000000..f040a017a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdField.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * TD 引擎的字段 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TdField { + + /** + * 字段名称 + */ + private String name; + + /** + * 字段类型 + */ + private String type; + + /** + * 字段长度 + */ + private int length; +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java new file mode 100644 index 000000000..380807a1b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TdResponse { + + public static final int CODE_SUCCESS = 0; + public static final int CODE_TB_NOT_EXIST = 866; + + private String status; + + private int code; + + private String desc; + + //[["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]] + private List data; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java new file mode 100644 index 000000000..4506383f6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class TdRestApi { + + @Value("${spring.datasource.dynamic.datasource.master.url}") + private String url; + + @Value("${spring.datasource.dynamic.datasource.master.username}") + private String username; + + @Value("${spring.datasource.dynamic.datasource.master.password}") + private String password; + + private String getRestApiUrl() { + //jdbc:TAOS-RS://127.0.0.1:6041/iotkit?xxxx + String restUrl = url.replace("jdbc:TAOS-RS://" , "") + .replaceAll("\\?.*" , ""); + // /rest/sql/iotkit + int idx = restUrl.lastIndexOf("/"); + //127.0.0.1:6041/rest/sql/iotkit + return String.format("%s/rest/sql/%s" , restUrl.substring(0, idx), restUrl.substring(idx + 1)); + } + + + /** + * 新建td api请求对象 + */ + public HttpRequest newApiRequest(String sql) { + return HttpRequest + .post(getRestApiUrl()) + .body(sql) + .basicAuth(username, password); + } + + /** + * 执行sql + */ + public TdResponse execSql(String sql) { + log.info("exec td sql:{}" , sql); + HttpRequest request = newApiRequest(sql); + HttpResponse response = request.execute(); + return JSONUtil.toBean(response.body(), TdResponse.class); + } + + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java new file mode 100644 index 000000000..f7e251ea8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 统计的时间数据 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TimeData { + + /** + * 时间 + */ + private long time; + + /** + * 数据值 + */ + private Object data; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java new file mode 100644 index 000000000..6a925f4e5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.iocoder.yudao.module.iot.domain.FieldsVo; +import cn.iocoder.yudao.module.iot.domain.SelectDto; +import cn.iocoder.yudao.module.iot.domain.TableDto; +import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; +import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +@Mapper +@DS("tdengine") +public interface TdEngineMapper { + + void createDatabase(@Param("dataBaseName") String dataBaseName); + + void createSuperTable(@Param("schemaFields") List schemaFields, + @Param("tagsFields") List tagsFields, + @Param("dataBaseName") String dataBaseName, + @Param("superTableName") String superTableName); + + void createTable(TableDto tableDto); + + void insertData(TableDto tableDto); + + List> selectByTimestamp(SelectDto selectDto); + + void addColumnForSuperTable(@Param("superTableName") String superTableName, + @Param("fieldsVo") FieldsVo fieldsVo); + + void dropColumnForSuperTable(@Param("superTableName") String superTableName, + @Param("fieldsVo") FieldsVo fieldsVo); + + void addTagForSuperTable(@Param("superTableName") String superTableName, + @Param("fieldsVo") FieldsVo fieldsVo); + + void dropTagForSuperTable(@Param("superTableName") String superTableName, + @Param("fieldsVo") FieldsVo fieldsVo); + + Map getCountByTimestamp(SelectDto selectDto); + + /** + * 检查表是否存在 + * + * @param dataBaseName 数据库名称 + * @param tableName 表名称 + */ + Integer checkTableExists(@Param("dataBaseName") String dataBaseName, @Param("tableName") String tableName); + + Map getLastData(SelectDto selectDto); + + List> getHistoryData(SelectVisualDto selectVisualDto); + + List> getRealtimeData(SelectVisualDto selectVisualDto); + + List> getAggregateData(SelectVisualDto selectVisualDto); + + List> getLastDataByTags(TagsSelectDao tagsSelectDao); + + /** + * 创建超级表 + * + * @param sql sql + * @return 返回值 + */ + @InterceptorIgnore(tenantLine = "true") + Integer createSuperTableDevice(String sql); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java new file mode 100644 index 000000000..7c9fe7000 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.framework.aspect; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.util.Map; + +/** + * TaosAspect 是一个处理 Taos 数据库返回值的切面。 + */ +@Aspect +@Component +@Slf4j +public class TaosAspect { + + @Around("execution(java.util.Map cn.iocoder.yudao.module.iot.dal.tdengine.*.*(..))") + public Object handleType(ProceedingJoinPoint joinPoint) { + Map result = null; + try { + result = (Map) joinPoint.proceed(); + result.replaceAll((key, value) -> { + if (value instanceof byte[]) { + return new String((byte[]) value); + } else if (value instanceof Timestamp) { + return ((Timestamp) value).getTime(); + } + return value; + }); + } catch (Throwable e) { + log.error("TaosAspect handleType error", e); + } + return result; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 15391f70b..d0ca09288 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/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 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; +import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; + +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.List; @@ -31,6 +36,10 @@ public class IotProductServiceImpl implements IotProductService { @Resource private IotProductMapper productMapper; + @Resource + @Lazy + private IotThinkModelFunctionService thinkModelFunctionService; + @Override public Long createProduct(IotProductSaveReqVO createReqVO) { // 1. 生成 ProductKey @@ -106,11 +115,17 @@ public class IotProductServiceImpl implements IotProductService { } @Override + @DSTransactional(rollbackFor = Exception.class) public void updateProductStatus(Long id, Integer status) { // 1. 校验存在 validateProductExists(id); // 2. 更新 IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); + // 3. 产品是发布状态 + if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getType())) { + // 3.1 创建超级表数据模型 + thinkModelFunctionService.createSuperTableDataModel(id); + } productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataService.java new file mode 100644 index 000000000..42439e25a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataService.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + + +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; + +import java.util.List; + +/** + * 数据结构接口 + */ +public interface IotDbStructureDataService { + + /** + * 创建物模型定义 + */ + void createSuperTable(ThingModelRespVO thingModel, Integer deviceType); + + /** + * 更新物模型定义 + */ + void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType); + + /** + * 创建超级表数据模型 + */ + void createSuperTableDataModel(IotProductDO product, List functionList); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java new file mode 100644 index 000000000..f8dd6feb5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java @@ -0,0 +1,168 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class IotDbStructureDataServiceImpl implements IotDbStructureDataService { + + @Resource + private TdEngineMapper tdEngineMapper; + + @Resource + private TdRestApi tdRestApi; + + @Override + public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { + // 获取物模型中的属性定义 + List fields = FieldParser.parse(thingModel); + String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); + + // 生成创建超级表的 SQL + String sql = TableManager.getCreateSTableSql(tbName, fields, new TdField("device_id", "NCHAR", 64)); + if (sql == null) { + log.warn("生成的 SQL 为空,无法创建超级表"); + return; + } + log.info("执行 SQL: {}", sql); + + // 执行 SQL 创建超级表 + tdEngineMapper.createSuperTableDevice(sql); + } + + @Override + public void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { + try { + // 获取旧字段信息 + String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); + String sql = TableManager.getDescTableSql(tbName); + TdResponse response = tdRestApi.execSql(sql); + if (response.getCode() != TdResponse.CODE_SUCCESS) { + throw new RuntimeException("获取表描述错误: " + JSONUtil.toJsonStr(response)); + } + + List oldFields = FieldParser.parse(response.getData()); + List newFields = FieldParser.parse(thingModel); + + // 找出新增的字段 + List addFields = newFields.stream() + .filter(f -> oldFields.stream().noneMatch(old -> old.getName().equals(f.getName()))) + .collect(Collectors.toList()); + if (!addFields.isEmpty()) { + sql = TableManager.getAddSTableColumnSql(tbName, addFields); + response = tdRestApi.execSql(sql); + if (response.getCode() != TdResponse.CODE_SUCCESS) { + throw new RuntimeException("添加表字段错误: " + JSONUtil.toJsonStr(response)); + } + } + + // 找出修改的字段 + List modifyFields = newFields.stream() + .filter(f -> oldFields.stream().anyMatch(old -> + old.getName().equals(f.getName()) && + (!old.getType().equals(f.getType()) || old.getLength() != f.getLength()))) + .collect(Collectors.toList()); + if (!modifyFields.isEmpty()) { + sql = TableManager.getModifySTableColumnSql(tbName, modifyFields); + response = tdRestApi.execSql(sql); + if (response.getCode() != TdResponse.CODE_SUCCESS) { + throw new RuntimeException("修改表字段错误: " + JSONUtil.toJsonStr(response)); + } + } + + // 找出删除的字段 + List dropFields = oldFields.stream() + .filter(f -> !"time".equals(f.getName()) && !"device_id".equals(f.getName()) && + newFields.stream().noneMatch(n -> n.getName().equals(f.getName()))) + .collect(Collectors.toList()); + if (!dropFields.isEmpty()) { + sql = TableManager.getDropSTableColumnSql(tbName, dropFields); + response = tdRestApi.execSql(sql); + if (response.getCode() != TdResponse.CODE_SUCCESS) { + throw new RuntimeException("删除表字段错误: " + JSONUtil.toJsonStr(response)); + } + } + } catch (Throwable e) { + log.error("更新物模型超级表失败", e); + } + } + + @Override + public void createSuperTableDataModel(IotProductDO product, List functionList) { + // 1. 生成 ThingModelRespVO + ThingModelRespVO thingModel = new ThingModelRespVO(); + thingModel.setId(product.getId()); + thingModel.setProductKey(product.getProductKey()); + + // 1.1 设置属性、服务和事件 + ThingModelRespVO.Model model = new ThingModelRespVO.Model(); + List properties = new ArrayList<>(); + + // 1.2 遍历功能列表并分类 + for (IotThinkModelFunctionDO function : functionList) { + if (Objects.requireNonNull(IotProductFunctionTypeEnum.valueOf(function.getType())) == IotProductFunctionTypeEnum.PROPERTY) { + ThingModelProperty property = new ThingModelProperty(); + property.setIdentifier(function.getIdentifier()); + property.setName(function.getName()); + property.setDescription(function.getDescription()); + property.setDataType(function.getProperty().getDataType()); + properties.add(property); + } + } + + // 1.3 判断属性列表是否为空 + if (properties.isEmpty()) { + log.warn("物模型属性列表为空,不创建超级表"); + return; + } + + model.setProperties(properties); + thingModel.setModel(model); + + // 2. 判断是否已经创建,如果已经创建则进行更新 + String tbName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); + Integer iot = tdEngineMapper.checkTableExists("ruoyi_vue_pro", tbName); + if (iot != null && iot > 0) { + // 3. 更新 + updateSuperTable(thingModel, product.getDeviceType()); + } else { + // 4. 创建 + createSuperTable(thingModel, product.getDeviceType()); + } + } + + /** + * 根据产品key获取产品属性超级表名 + */ + static String getProductPropertySTableName(Integer deviceType, String productKey) { + if (deviceType == 1) { + return String.format("gateway_sub_" + productKey).toLowerCase(); + } else if (deviceType == 2) { + return String.format("gateway_" + productKey).toLowerCase(); + } else { + return String.format("device_" + productKey).toLowerCase(); + } + } + + /** + * 根据deviceId获取设备属性表名 + */ + static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) { + return String.format(deviceType + "_" + productKey + "_" + deviceKey).toLowerCase(); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java new file mode 100644 index 000000000..b3ae6f818 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java @@ -0,0 +1,141 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.domain.FieldsVo; +import cn.iocoder.yudao.module.iot.domain.SelectDto; +import cn.iocoder.yudao.module.iot.domain.TableDto; +import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; +import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; + +import java.util.List; +import java.util.Map; + +/** + * TdEngineService + */ +public interface TdEngineService { + + /** + * 创建数据库 + * + * @param dataBaseName 数据库名称 + * @throws Exception 异常 + */ + void createDateBase(String dataBaseName) throws Exception; + + /** + * 创建超级表 + * + * @param schemaFields schema字段 + * @param tagsFields tags字段 + * @param dataBaseName 数据库名称 + * @param superTableName 超级表名称 + * @throws Exception 异常 + */ + void createSuperTable(List schemaFields, List tagsFields, String dataBaseName, + String superTableName) throws Exception; + + /** + * 创建表 + * + * @param tableDto 表信息 + * @throws Exception 异常 + */ + void createTable(TableDto tableDto) throws Exception; + + /** + * 插入数据 + * + * @param tableDto 表信息 + * @throws Exception 异常 + */ + void insertData(TableDto tableDto) throws Exception; + + /** + * 根据时间戳查询数据 + * + * @param selectDto 查询条件 + * @return 数据 + * @throws Exception 异常 + */ + List> selectByTimesTamp(SelectDto selectDto) throws Exception; + + /** + * 为超级表添加列 + * + * @param superTableName 超级表名称 + * @param fieldsVo 字段信息 + * @throws Exception 异常 + */ + void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception; + + /** + * 为超级表删除列 + * + * @param superTableName 超级表名称 + * @param fieldsVo 字段信息 + * @throws Exception 异常 + */ + void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception; + + /** + * 为超级表添加tag + */ + Long getCountByTimesTamp(SelectDto selectDto) throws Exception; + + /** + * 检查表是否存在 + * + * @return 1存在 0不存在 + * @throws Exception 异常 + */ + Integer checkTableExists(SelectDto selectDto) throws Exception; + + /** + * 初始化超级表 + * + * @param msg 消息 + * @throws Exception 异常 + */ + void initSTableFrame(String msg) throws Exception; + + /** + * 获取最新数据 + * + * @param selectDto 查询条件 + * @return 数据 + * @throws Exception 异常 + */ + Map getLastData(SelectDto selectDto) throws Exception; + + /** + * 根据tag查询最新数据 + * + * @param tagsSelectDao 查询条件 + * @return 数据 + */ + Map> getLastDataByTags(TagsSelectDao tagsSelectDao); + + /** + * 获取历史数据 + * + * @param selectVisualDto 查询条件 + * @return 数据 + */ + List> getHistoryData(SelectVisualDto selectVisualDto); + + /** + * 获取实时数据 + * + * @param selectVisualDto 查询条件 + * @return 数据 + */ + List> getRealtimeData(SelectVisualDto selectVisualDto); + + /** + * 获取聚合数据 + * + * @param selectVisualDto 查询条件 + * @return 数据 + */ + List> getAggregateData(SelectVisualDto selectVisualDto); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java new file mode 100644 index 000000000..70933617f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.domain.FieldsVo; +import cn.iocoder.yudao.module.iot.domain.SelectDto; +import cn.iocoder.yudao.module.iot.domain.TableDto; +import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; +import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +@Slf4j +public class TdEngineServiceImpl implements TdEngineService { + + + @Override + public void createDateBase(String dataBaseName) { + + } + + @Override + public void createSuperTable(List schemaFields, List tagsFields, String dataBaseName, String superTableName) { + + } + + @Override + public void createTable(TableDto tableDto) { + + } + + @Override + public void insertData(TableDto tableDto) { + + } + + @Override + public List> selectByTimesTamp(SelectDto selectDto) { + return List.of(); + } + + @Override + public void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) { + + } + + @Override + public void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) { + + } + + @Override + public Long getCountByTimesTamp(SelectDto selectDto) { + return 0L; + } + + @Override + public Integer checkTableExists(SelectDto selectDto) { + return 0; + } + + @Override + public void initSTableFrame(String msg) { + + } + + @Override + public Map getLastData(SelectDto selectDto) { + return Map.of(); + } + + @Override + public Map> getLastDataByTags(TagsSelectDao tagsSelectDao) { + return Map.of(); + } + + @Override + public List> getHistoryData(SelectVisualDto selectVisualDto) { + return List.of(); + } + + @Override + public List> getRealtimeData(SelectVisualDto selectVisualDto) { + return List.of(); + } + + @Override + public List> getAggregateData(SelectVisualDto selectVisualDto) { + return List.of(); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java index ce8e472f5..3067772e6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/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 { */ PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO); + /** + * 创建超级表数据模型 + * + * @param productId 产品编号 + */ + void createSuperTableDataModel(Long productId); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 793786944..1e356c6b7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/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 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; +import cn.iocoder.yudao.module.iot.service.tdengine.IotDbStructureDataService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -45,6 +48,11 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Resource private IotThinkModelFunctionMapper thinkModelFunctionMapper; + @Resource + private IotProductService productService; + @Resource + private IotDbStructureDataService dbStructureDataService; + @Override @Transactional(rollbackFor = Exception.class) public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { @@ -162,6 +170,16 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe return thinkModelFunctionMapper.selectPage(pageReqVO); } + @Override + public void createSuperTableDataModel(Long productId) { + // 1. 查询产品 + IotProductDO product = productService.getProduct(productId); + // 2. 查询产品的物模型功能列表 + List functionList = thinkModelFunctionMapper.selectListByProductId(productId); + // 3. 生成 TDengine 的数据模型 + dbStructureDataService.createSuperTableDataModel(product, functionList); + } + /** * 创建默认的事件和服务 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml new file mode 100644 index 000000000..f722e0130 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml @@ -0,0 +1,324 @@ + + + + + + + create database if not exists #{dataBaseName} + + + + create table if not exists #{dataBaseName}.#{superTableName} + + + ${item.fieldName} + + + + + timestamp + + + tinyint + + + smallint + + + int + + + bigint + + + float + + + double + + + binary + + + nchar + + + bool + + + json + + + + + (#{item.size}) + + + tags + + + + ${item.fieldName} + + + + + timestamp + + + tinyint + + + smallint + + + int + + + bigint + + + float + + + double + + + binary + + + nchar + + + bool + + + json + + + + + (#{item.size}) + + + + + + create table + if not exists #{dataBaseName}.#{tableName} + using #{dataBaseName}.#{superTableName} + tags + + #{item.fieldValue} + + + + + insert into #{dataBaseName}.#{tableName} + + #{item.fieldName} + + using #{dataBaseName}.#{superTableName} + tags + + #{item.fieldValue} + + values + + #{item.fieldValue} + + + + + + + + ALTER + STABLE + #{superTableName} + ADD + COLUMN + + #{fieldsVo.fieldName} + + + + + timestamp + + + tinyint + + + smallint + + + int + + + bigint + + + float + + + double + + + binary + + + nchar + + + bool + + + json + + + + + ( + #{fieldsVo.size} + ) + + + + + ALTER + STABLE + #{superTableName} + DROP + COLUMN + + #{fieldsVo.fieldName} + + + + + ALTER + STABLE + #{superTableName} + ADD + TAG + + #{fieldsVo.fieldName} + + + + + timestamp + + + tinyint + + + smallint + + + int + + + bigint + + + float + + + double + + + binary + + + nchar + + + bool + + + json + + + + + ( + #{fieldsVo.size} + ) + + + + + ALTER + STABLE + #{superTableName} + DROP + TAG + + #{fieldsVo.fieldName} + + + + + + + + + + + + + + + + + + ${sql} + + + From 61a0c05279613e6b9a95ef4ecc80cce7b2d3dc44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 23 Oct 2024 23:26:24 +0800 Subject: [PATCH 002/228] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91=20=E9=9B=86=E6=88=90=20tdengine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/domain/BaseEntity.java | 7 ------- .../yudao/module/iot/domain/Fields.java | 7 ------- .../yudao/module/iot/domain/FieldsVo.java | 21 ------------------- .../iot/domain/ProductSuperTableModel.java | 12 +---------- .../yudao/module/iot/domain/SelectDto.java | 7 ------- .../module/iot/domain/SuperTableDto.java | 7 ------- .../yudao/module/iot/domain/TableDto.java | 7 ------- .../module/iot/domain/TagsSelectDao.java | 14 +++---------- 8 files changed, 4 insertions(+), 78 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java index 74a4c8494..496be9a24 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java @@ -2,13 +2,6 @@ package cn.iocoder.yudao.module.iot.domain; import lombok.Data; -/** - * @ClassDescription: tdEngine的基础实体类 - * @ClassName: BaseEntity - * @Author: fxlinks - * @Date: 2021-12-30 14:39:25 - * @Version 1.0 - */ @Data public class BaseEntity { private static final long serialVersionUID = 1L; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java index bbd7bb74e..ec0a7f148 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java @@ -2,13 +2,6 @@ package cn.iocoder.yudao.module.iot.domain; import lombok.Data; -/** - * @ClassDescription: 建表的字段实体类 - * @ClassName: Fields - * @Author: fxlinks - * @Date: 2021-12-28 09:09:04 - * @Version 1.0 - */ @Data public class Fields { private static final long serialVersionUID = 1L; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java index 554d52149..07aede29d 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java @@ -6,13 +6,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -/** - * @ClassDescription: 建表的字段实体类的vo类 - * @ClassName: FieldsVo - * @Author: fxlinks - * @Date: 2021-12-28 11:30:06 - * @Version 1.0 - */ @Data public class FieldsVo { private static final long serialVersionUID = 1L; @@ -32,13 +25,6 @@ public class FieldsVo { */ private Integer size; - /** - * @param fields 字段实体类 - * @return FieldsVo 字段实体vo类 - * @MethodDescription 字段实体类转为vo类 - * @author fx - * @Date 2021/12/28 13:48 - */ public static FieldsVo fieldsTranscoding(Fields fields) throws SQLException { // if (StringUtils.isBlank(fields.getFieldName()) || fields.getDataType() == null) { // throw new SQLException("invalid operation: fieldName or dataType can not be null"); @@ -51,13 +37,6 @@ public class FieldsVo { return null; } - /** - * @param fieldsList 字段实体类集合 - * @return List 字段实体vo类集合 - * @MethodDescription 字段实体类集合转为vo类集合 - * @author fx - * @Date 2021/12/28 14:00 - */ public static List fieldsTranscoding(List fieldsList) throws SQLException { List fieldsVoList = new ArrayList<>(); for (Fields fields : fieldsList) { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java index 49887415c..c5989811f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java @@ -7,21 +7,11 @@ import java.sql.Timestamp; import java.util.HashMap; import java.util.Optional; -/** - * @Description: 产品超级表模型 - * @Author: fx - * @Website: http://www.sxfxck.com - * @CreateDate: 2022/1/1$ 19:37$ - * @UpdateUser: fx - * @UpdateDate: 2022/1/1$ 19:37$ - * @UpdateRemark: 修改内容 - * @Version: V1.0 - */ @Data public class ProductSuperTableModel { private static final long serialVersionUID = 1L; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+8") private Timestamp ts; private String superTableName; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java index 381ef3d6f..c20e5ab5e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java @@ -4,13 +4,6 @@ import lombok.Data; import java.util.Set; -/** - * @ClassDescription: 查询所需入参对象 - * @ClassName: SelectDto - * @Author: fxlinks - * @Date: 2022-01-07 14:12:26 - * @Version 1.0 - */ @Data public class SelectDto { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java index ee80d42cf..a15f135cf 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java @@ -4,13 +4,6 @@ import lombok.Data; import java.util.List; -/** - * @ClassDescription: 创建超级表需要的入参的实体类 - * @ClassName: SuperTableDto - * @Author: fxlinks - * @Date: 2021-12-28 15:03:45 - * @Version 1.0 - */ @Data public class SuperTableDto extends BaseEntity { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java index f27beb1a6..5ffe9f84e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java @@ -4,13 +4,6 @@ import lombok.Data; import java.util.List; -/** - * @ClassDescription: 创建超级表的子表需要的入参的实体类 - * @ClassName: TableDto - * @Author: fxlinks - * @Date: 2021-12-30 14:42:47 - * @Version 1.0 - */ @Data public class TableDto extends BaseEntity { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java index 5cb9c5ed9..8833b0b50 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java @@ -3,24 +3,16 @@ package cn.iocoder.yudao.module.iot.domain; import lombok.Data; -/** - * @program: fxlinks - * @description: 标签查询模型 - * @packagename: com.fx.tdengine.api.domain.rule - * @author: fx - * @e-mainl: 13733918655@163.com - * @date: 2022-07-27 18:40 - **/ @Data public class TagsSelectDao { -// @NotBlank(message = "invalid operation: dataBaseName can not be empty") + // @NotBlank(message = "invalid operation: dataBaseName can not be empty") private String dataBaseName; -// @NotBlank(message = "invalid operation: stableName can not be empty") + // @NotBlank(message = "invalid operation: stableName can not be empty") private String stableName; -// @NotBlank(message = "invalid operation: tagsName can not be empty") + // @NotBlank(message = "invalid operation: tagsName can not be empty") private String tagsName; // @NotNull(message = "invalid operation: startTime can not be null") From ea8dd67e9ecc34e7e8af3402f00c819d53f5130a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 23 Oct 2024 23:38:55 +0800 Subject: [PATCH 003/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E5=A2=9E=E5=8A=A0=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/vo/IotDevicePageReqVO.java | 1 - .../admin/device/vo/IotDeviceRespVO.java | 1 - .../thingModel/ThingModelRespVO.java | 1 - .../vo/IotThinkModelFunctionRespVO.java | 1 - .../dal/dataobject/tdengine/FieldParser.java | 37 ++++++++++--------- .../dal/dataobject/tdengine/TableData.java | 3 ++ .../dal/dataobject/tdengine/TableManager.java | 3 ++ .../dal/dataobject/tdengine/TdResponse.java | 5 ++- .../dal/dataobject/tdengine/TdRestApi.java | 3 ++ 9 files changed, 33 insertions(+), 22 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java index 26bdaca05..1c29f9f81 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java @@ -10,7 +10,6 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; -import java.math.BigDecimal; import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java index 488f6b907..0b2cf25f5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java @@ -5,7 +5,6 @@ import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import java.math.BigDecimal; import java.time.LocalDateTime; @Schema(description = "管理后台 - IoT 设备 Response VO") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java index 6fc48ef4f..d7478e54a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMod import lombok.*; import java.util.List; -import java.util.Map; @Data @Builder diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java index 9ef3f58d8..e2f3d2ddc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java @@ -9,7 +9,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; -import java.util.List; @Schema(description = "管理后台 - IoT 产品物模型 Response VO") @Data diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index 0a91e7cf1..e045e5ea3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelDataType; @@ -9,21 +8,26 @@ import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; +/** + * FieldParser 类用于解析和转换物模型字段到 TDengine 字段 + * + */ public class FieldParser { /** * 物模型到td数据类型映射 */ - private static final HashMap TYPE_MAPPING = new HashMap<>() {{ - put("INT", "INT"); - put("FLOAT", "FLOAT"); - put("DOUBLE", "DOUBLE"); - put("BOOL", "BOOL"); - put("ENUM", "NCHAR"); - put("TEXT", "NCHAR"); - put("DATE", "NCHAR"); - }}; - + private static final HashMap TYPE_MAPPING = new HashMap<>() { + { + put("INT", "INT"); + put("FLOAT", "FLOAT"); + put("DOUBLE", "DOUBLE"); + put("BOOL", "BOOL"); + put("ENUM", "NCHAR"); + put("TEXT", "NCHAR"); + put("DATE", "NCHAR"); + } + }; /** * 将物模型字段转换为td字段 @@ -57,9 +61,8 @@ public class FieldParser { /** * 将从库中查出来的字段信息转换为td字段对象 */ - public static List parse(List rows) { - return (List) rows.stream().map((r) -> { - List row = (List) r; + public static List parse(List> rows) { + return rows.stream().map(row -> { String type = row.get(1).toString().toUpperCase(); return new TdField( row.get(0).toString(), @@ -72,9 +75,9 @@ public class FieldParser { * 获取字段字义 */ public static String getFieldDefine(TdField field) { - return "`" + field.getName() + "`" + " " + (field.getLength() > 0 ? - String.format("%s(%d)", field.getType(), field.getLength()) - : field.getType()); + return "`" + field.getName() + "`" + " " + + (field.getLength() > 0 ? String.format("%s(%d)", field.getType(), field.getLength()) + : field.getType()); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java index 1d42933d4..5c3c585e7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java @@ -4,6 +4,9 @@ import lombok.Data; import java.util.List; +/** + * TableData 类用于存储和操作 TDengine 表数据 + */ @Data public class TableData { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java index 1bf4ecf64..b2762f6ed 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; import java.util.List; +/** + * TableManager 类用于管理 TDengine 表的创建、删除和结构信息获取 + */ public class TableManager { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java index 380807a1b..9353565be 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java @@ -6,6 +6,9 @@ import lombok.NoArgsConstructor; import java.util.List; +/** + * TdResponse 类用于处理 TDengine 的响应 + */ @Data @NoArgsConstructor @AllArgsConstructor @@ -21,6 +24,6 @@ public class TdResponse { private String desc; //[["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]] - private List data; + private List data; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java index 4506383f6..ef6b8b5b4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java @@ -7,6 +7,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +/** + * TdRestApi 类用于处理 TDengine 的 REST API 请求 + */ @Slf4j @Service public class TdRestApi { From 7b5aa23d5cdc55779ff3048d6cc2e04e82b24b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 26 Oct 2024 23:15:31 +0800 Subject: [PATCH 004/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=20=E4=BA=A7=E5=93=81=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E8=B6=85=E7=BA=A7=E8=A1=A8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/domain/FieldsVo.java | 26 +- .../dal/dataobject/tdengine/FieldParser.java | 44 +-- .../dal/dataobject/tdengine/TableData.java | 2 +- .../dal/dataobject/tdengine/TableManager.java | 26 +- .../tdengine/{TdField.java => TdFieldDO.java} | 10 +- .../dal/dataobject/tdengine/TdResponse.java | 18 +- .../dal/dataobject/tdengine/TdRestApi.java | 23 +- .../iot/dal/tdengine/TdEngineMapper.java | 87 ++++-- .../IotDbStructureDataServiceImpl.java | 282 +++++++++++------- .../iot/service/tdengine/TdEngineService.java | 75 ++--- .../service/tdengine/TdEngineServiceImpl.java | 44 ++- .../IotThinkModelFunctionServiceImpl.java | 2 + .../mapper/tdengine/TdEngineMapper.xml | 223 +++++++------- 13 files changed, 491 insertions(+), 371 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/{TdField.java => TdFieldDO.java} (68%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java index 07aede29d..fc86a8f7e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java @@ -1,14 +1,18 @@ package cn.iocoder.yudao.module.iot.domain; +import lombok.Builder; import lombok.Data; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +/** + * 字段信息 VO + */ @Data +@Builder public class FieldsVo { - private static final long serialVersionUID = 1L; /** * 字段名称 @@ -24,24 +28,4 @@ public class FieldsVo { * 字段字节大小 */ private Integer size; - - public static FieldsVo fieldsTranscoding(Fields fields) throws SQLException { -// if (StringUtils.isBlank(fields.getFieldName()) || fields.getDataType() == null) { -// throw new SQLException("invalid operation: fieldName or dataType can not be null"); -// } -// FieldsVo fieldsVo = new FieldsVo(); -// fieldsVo.setFieldName(fields.getFieldName()); -// fieldsVo.setDataType(fields.getDataType().getDataType()); -// fieldsVo.setSize(fields.getSize()); -// return fieldsVo; - return null; - } - - public static List fieldsTranscoding(List fieldsList) throws SQLException { - List fieldsVoList = new ArrayList<>(); - for (Fields fields : fieldsList) { - fieldsVoList.add(fieldsTranscoding(fields)); - } - return fieldsVoList; - } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index e045e5ea3..344d65c9a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -10,7 +10,6 @@ import java.util.stream.Collectors; /** * FieldParser 类用于解析和转换物模型字段到 TDengine 字段 - * */ public class FieldParser { @@ -35,49 +34,58 @@ public class FieldParser { * @param property 物模型属性 * @return TdField对象 */ - public static TdField parse(ThingModelProperty property) { + public static TdFieldDO parse(ThingModelProperty property) { String fieldName = property.getIdentifier().toLowerCase(); ThingModelDataType type = property.getDataType(); // 将物模型字段类型映射为td字段类型 String fType = TYPE_MAPPING.get(type.getType().toUpperCase()); - int len = -1; // 如果字段类型为NCHAR,默认长度为64 + int dataLength = 0; if ("NCHAR".equals(fType)) { - len = 64; + dataLength = 64; } - - return new TdField(fieldName, fType, len); + return new TdFieldDO(fieldName, fType, dataLength); } /** - * 获取物模型中的字段列表 + * 从物模型中获取字段列表 + * + * @param thingModel 物模型响应对象 + * @return 字段列表 */ - public static List parse(ThingModelRespVO thingModel) { - return thingModel.getModel().getProperties().stream().map(FieldParser::parse).collect(Collectors.toList()); + public static List parse(ThingModelRespVO thingModel) { + return thingModel.getModel().getProperties().stream() + .map(FieldParser::parse) + .collect(Collectors.toList()); } /** - * 将从库中查出来的字段信息转换为td字段对象 + * 将从库中查出来的字段信息转换为 TDengine 字段对象 + * + * @param rows 从库中查出的字段信息列表 + * @return 转换后的 TDengine 字段对象列表 */ - public static List parse(List> rows) { + public static List parse(List> rows) { return rows.stream().map(row -> { String type = row.get(1).toString().toUpperCase(); - return new TdField( + int dataLength = "NCHAR".equals(type) ? Integer.parseInt(row.get(2).toString()) : -1; + return new TdFieldDO( row.get(0).toString(), type, - type.equals("NCHAR") ? Integer.parseInt(row.get(2).toString()) : -1); + dataLength + ); }).collect(Collectors.toList()); } /** * 获取字段字义 */ - public static String getFieldDefine(TdField field) { - return "`" + field.getName() + "`" + " " - + (field.getLength() > 0 ? String.format("%s(%d)", field.getType(), field.getLength()) - : field.getType()); + public static String getFieldDefine(TdFieldDO field) { + return "`" + field.getFieldName() + "`" + " " + + (field.getDataLength() > 0 ? String.format("%s(%d)", field.getDataType(), field.getDataLength()) + : field.getDataType()); } -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java index 5c3c585e7..e9acbb7f0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java @@ -36,4 +36,4 @@ public class TableData { * 超级表名称 */ private String superTableName; -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java index b2762f6ed..65663d805 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java @@ -45,7 +45,7 @@ public class TableManager { /** * 获取创建表sql */ - public static String getCreateSTableSql(String tbName, List fields, TdField... tags) { + public static String getCreateSTableSql(String tbName, List fields, TdFieldDO... tags) { if (fields.isEmpty()) { return null; } @@ -53,7 +53,7 @@ public class TableManager { // 生成字段片段 StringBuilder sbField = new StringBuilder("time TIMESTAMP,"); - for (TdField field : fields) { + for (TdFieldDO field : fields) { sbField.append(FieldParser.getFieldDefine(field)); sbField.append(","); } @@ -63,7 +63,7 @@ public class TableManager { // 生成tag StringBuilder sbTag = new StringBuilder(); - for (TdField tag : tags) { + for (TdFieldDO tag : tags) { sbTag.append(FieldParser.getFieldDefine(tag)) .append(","); } @@ -76,7 +76,7 @@ public class TableManager { /** * 获取创建普通表sql */ - public static String getCreateCTableSql(String tbName, List fields) { + public static String getCreateCTableSql(String tbName, List fields) { if (fields.size() == 0) { return null; } @@ -84,7 +84,7 @@ public class TableManager { //生成字段片段 StringBuilder sbField = new StringBuilder("time timestamp,"); - for (TdField field : fields) { + for (TdFieldDO field : fields) { sbField.append(FieldParser.getFieldDefine(field)); sbField.append(","); } @@ -116,9 +116,9 @@ public class TableManager { /** * 获取添加字段sql */ - public static String getAddSTableColumnSql(String tbName, List fields) { + public static String getAddSTableColumnSql(String tbName, List fields) { StringBuilder sbAdd = new StringBuilder(); - for (TdField field : fields) { + for (TdFieldDO field : fields) { sbAdd.append(String.format(ALTER_STABLE_ADD_COL_TPL, tbName, FieldParser.getFieldDefine(field) @@ -130,9 +130,9 @@ public class TableManager { /** * 获取修改字段sql */ - public static String getModifySTableColumnSql(String tbName, List fields) { + public static String getModifySTableColumnSql(String tbName, List fields) { StringBuilder sbModify = new StringBuilder(); - for (TdField field : fields) { + for (TdFieldDO field : fields) { sbModify.append(String.format(ALTER_STABLE_MODIFY_COL_TPL, tbName, FieldParser.getFieldDefine(field) @@ -144,15 +144,15 @@ public class TableManager { /** * 获取删除字段sql */ - public static String getDropSTableColumnSql(String tbName, List fields) { + public static String getDropSTableColumnSql(String tbName, List fields) { StringBuilder sbDrop = new StringBuilder(); - for (TdField field : fields) { + for (TdFieldDO field : fields) { sbDrop.append(String.format(ALTER_STABLE_DROP_COL_TPL, tbName, - field.getName() + field.getFieldName() )); } return sbDrop.toString(); } -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java similarity index 68% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdField.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java index f040a017a..d9cf28f1b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdField.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @@ -10,20 +11,21 @@ import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor -public class TdField { +@Builder +public class TdFieldDO { /** * 字段名称 */ - private String name; + private String fieldName; /** * 字段类型 */ - private String type; + private String dataType; /** * 字段长度 */ - private int length; + private Integer dataLength = 0; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java index 9353565be..aca5cece5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java @@ -17,13 +17,25 @@ public class TdResponse { public static final int CODE_SUCCESS = 0; public static final int CODE_TB_NOT_EXIST = 866; + /** + * 状态 + */ private String status; + /** + * 错误码 + */ private int code; + /** + * 错误信息 + */ private String desc; - //[["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]] - private List data; + /** + * 列信息 + * [["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]] + */ + private List data; -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java index ef6b8b5b4..6653ece40 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java @@ -14,23 +14,23 @@ import org.springframework.stereotype.Service; @Service public class TdRestApi { - @Value("${spring.datasource.dynamic.datasource.master.url}") + @Value("${spring.datasource.dynamic.datasource.tdengine.url}") private String url; - @Value("${spring.datasource.dynamic.datasource.master.username}") + @Value("${spring.datasource.dynamic.datasource.tdengine.username}") private String username; - @Value("${spring.datasource.dynamic.datasource.master.password}") + @Value("${spring.datasource.dynamic.datasource.tdengine.password}") private String password; + /** + * 获取 REST API URL + */ private String getRestApiUrl() { - //jdbc:TAOS-RS://127.0.0.1:6041/iotkit?xxxx - String restUrl = url.replace("jdbc:TAOS-RS://" , "") - .replaceAll("\\?.*" , ""); - // /rest/sql/iotkit + String restUrl = url.replace("jdbc:TAOS-RS://", "") + .replaceAll("\\?.*", ""); int idx = restUrl.lastIndexOf("/"); - //127.0.0.1:6041/rest/sql/iotkit - return String.format("%s/rest/sql/%s" , restUrl.substring(0, idx), restUrl.substring(idx + 1)); + return String.format("%s/rest/sql/%s", restUrl.substring(0, idx), restUrl.substring(idx + 1)); } @@ -48,11 +48,10 @@ public class TdRestApi { * 执行sql */ public TdResponse execSql(String sql) { - log.info("exec td sql:{}" , sql); + log.info("exec td sql:{}", sql); HttpRequest request = newApiRequest(sql); HttpResponse response = request.execute(); return JSONUtil.toBean(response.body(), TdResponse.class); } - -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java index 6a925f4e5..85e324a77 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.domain.FieldsVo; import cn.iocoder.yudao.module.iot.domain.SelectDto; import cn.iocoder.yudao.module.iot.domain.TableDto; @@ -17,24 +18,80 @@ import java.util.Map; @DS("tdengine") public interface TdEngineMapper { + /** + * 创建数据库 + * + * @param dataBaseName 数据库名称 + */ + @InterceptorIgnore(tenantLine = "true") void createDatabase(@Param("dataBaseName") String dataBaseName); - void createSuperTable(@Param("schemaFields") List schemaFields, - @Param("tagsFields") List tagsFields, + /** + * 创建超级表 + * + * @param schemaFields schema字段 + * @param tagsFields tags字段 + * @param dataBaseName 数据库名称 + * @param superTableName 超级表名称 + */ + @InterceptorIgnore(tenantLine = "true") + void createSuperTable(@Param("schemaFields") List schemaFields, + @Param("tagsFields") List tagsFields, @Param("dataBaseName") String dataBaseName, @Param("superTableName") String superTableName); + /** + * 查看超级表 - 显示当前数据库下的所有超级表信息 + * SQL:SHOW STABLES [LIKE tb_name_wildcard]; + * + * @param dataBaseName 数据库名称 + * @param superTableName 超级表名称 + */ + @InterceptorIgnore(tenantLine = "true") + List> showSuperTables(@Param("dataBaseName") String dataBaseName, + @Param("superTableName") String superTableName); + + /** + * 查看超级表 - 获取超级表的结构信息 + * SQL:DESCRIBE [db_name.]stb_name; + *

+ * * @param dataBaseName 数据库名称 + * * @param superTableName 超级表名称 + */ + @InterceptorIgnore(tenantLine = "true") + List> describeSuperTable(@Param("dataBaseName") String dataBaseName, + @Param("superTableName") String superTableName); + + /** + * 为超级表添加列 + * + * @param dataBaseName 数据库名称 + * @param superTableName 超级表名称 + * @param field 字段信息 + */ + @InterceptorIgnore(tenantLine = "true") + void addColumnForSuperTable(@Param("dataBaseName") String dataBaseName, + @Param("superTableName") String superTableName, + @Param("field") TdFieldDO field); + + /** + * 为超级表删除列 + * + * @param dataBaseName 数据库名称 + * @param superTableName 超级表名称 + * @param field 字段信息 + */ + @InterceptorIgnore(tenantLine = "true") + void dropColumnForSuperTable(@Param("dataBaseName") String dataBaseName, + @Param("superTableName") String superTableName, + @Param("field") TdFieldDO field); + void createTable(TableDto tableDto); void insertData(TableDto tableDto); List> selectByTimestamp(SelectDto selectDto); - void addColumnForSuperTable(@Param("superTableName") String superTableName, - @Param("fieldsVo") FieldsVo fieldsVo); - - void dropColumnForSuperTable(@Param("superTableName") String superTableName, - @Param("fieldsVo") FieldsVo fieldsVo); void addTagForSuperTable(@Param("superTableName") String superTableName, @Param("fieldsVo") FieldsVo fieldsVo); @@ -44,14 +101,6 @@ public interface TdEngineMapper { Map getCountByTimestamp(SelectDto selectDto); - /** - * 检查表是否存在 - * - * @param dataBaseName 数据库名称 - * @param tableName 表名称 - */ - Integer checkTableExists(@Param("dataBaseName") String dataBaseName, @Param("tableName") String tableName); - Map getLastData(SelectDto selectDto); List> getHistoryData(SelectVisualDto selectVisualDto); @@ -62,13 +111,5 @@ public interface TdEngineMapper { List> getLastDataByTags(TagsSelectDao tagsSelectDao); - /** - * 创建超级表 - * - * @param sql sql - * @return 返回值 - */ - @InterceptorIgnore(tenantLine = "true") - Integer createSuperTableDevice(String sql); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java index f8dd6feb5..d42fd72fc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java @@ -1,19 +1,22 @@ package cn.iocoder.yudao.module.iot.service.tdengine; -import cn.hutool.json.JSONUtil; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdRestApi; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -22,147 +25,206 @@ import java.util.stream.Collectors; public class IotDbStructureDataServiceImpl implements IotDbStructureDataService { @Resource - private TdEngineMapper tdEngineMapper; + private TdEngineService tdEngineService; @Resource private TdRestApi tdRestApi; + @Value("${spring.datasource.dynamic.datasource.tdengine.url}") + private String url; + @Override public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { - // 获取物模型中的属性定义 - List fields = FieldParser.parse(thingModel); - String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); + // 1. 解析物模型,获得字段列表 + List schemaFields = new ArrayList<>(); + schemaFields.add(TdFieldDO.builder(). + fieldName("time"). + dataType("TIMESTAMP"). + build()); + schemaFields.addAll(FieldParser.parse(thingModel)); - // 生成创建超级表的 SQL - String sql = TableManager.getCreateSTableSql(tbName, fields, new TdField("device_id", "NCHAR", 64)); - if (sql == null) { - log.warn("生成的 SQL 为空,无法创建超级表"); - return; - } - log.info("执行 SQL: {}", sql); + // 3. 设置超级表的标签 + List tagsFields = new ArrayList<>(); + tagsFields.add(TdFieldDO.builder(). + fieldName("product_key"). + dataType("NCHAR"). + dataLength(64). + build()); + tagsFields.add(TdFieldDO.builder(). + fieldName("device_key"). + dataType("NCHAR"). + dataLength(64). + build()); + tagsFields.add(TdFieldDO.builder(). + fieldName("device_name"). + dataType("NCHAR"). + dataLength(64). + build()); + // 年 + tagsFields.add(TdFieldDO.builder(). + fieldName("year"). + dataType("INT"). + build()); + // 月 + tagsFields.add(TdFieldDO.builder(). + fieldName("month"). + dataType("INT"). + build()); + // 日 + tagsFields.add(TdFieldDO.builder(). + fieldName("day"). + dataType("INT"). + build()); + // 时 + tagsFields.add(TdFieldDO.builder(). + fieldName("hour"). + dataType("INT"). + build()); - // 执行 SQL 创建超级表 - tdEngineMapper.createSuperTableDevice(sql); + + // 4. 获取超级表的名称 + String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); + + // 5. 创建超级表 + String dataBaseName = url.substring(url.lastIndexOf("/") + 1); + tdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); } @Override public void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { try { - // 获取旧字段信息 String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); - String sql = TableManager.getDescTableSql(tbName); - TdResponse response = tdRestApi.execSql(sql); - if (response.getCode() != TdResponse.CODE_SUCCESS) { - throw new RuntimeException("获取表描述错误: " + JSONUtil.toJsonStr(response)); - } + List oldFields = getTableFields(tbName); + List newFields = FieldParser.parse(thingModel); - List oldFields = FieldParser.parse(response.getData()); - List newFields = FieldParser.parse(thingModel); - - // 找出新增的字段 - List addFields = newFields.stream() - .filter(f -> oldFields.stream().noneMatch(old -> old.getName().equals(f.getName()))) - .collect(Collectors.toList()); - if (!addFields.isEmpty()) { - sql = TableManager.getAddSTableColumnSql(tbName, addFields); - response = tdRestApi.execSql(sql); - if (response.getCode() != TdResponse.CODE_SUCCESS) { - throw new RuntimeException("添加表字段错误: " + JSONUtil.toJsonStr(response)); - } - } - - // 找出修改的字段 - List modifyFields = newFields.stream() - .filter(f -> oldFields.stream().anyMatch(old -> - old.getName().equals(f.getName()) && - (!old.getType().equals(f.getType()) || old.getLength() != f.getLength()))) - .collect(Collectors.toList()); - if (!modifyFields.isEmpty()) { - sql = TableManager.getModifySTableColumnSql(tbName, modifyFields); - response = tdRestApi.execSql(sql); - if (response.getCode() != TdResponse.CODE_SUCCESS) { - throw new RuntimeException("修改表字段错误: " + JSONUtil.toJsonStr(response)); - } - } - - // 找出删除的字段 - List dropFields = oldFields.stream() - .filter(f -> !"time".equals(f.getName()) && !"device_id".equals(f.getName()) && - newFields.stream().noneMatch(n -> n.getName().equals(f.getName()))) - .collect(Collectors.toList()); - if (!dropFields.isEmpty()) { - sql = TableManager.getDropSTableColumnSql(tbName, dropFields); - response = tdRestApi.execSql(sql); - if (response.getCode() != TdResponse.CODE_SUCCESS) { - throw new RuntimeException("删除表字段错误: " + JSONUtil.toJsonStr(response)); - } - } + updateTableFields(tbName, oldFields, newFields); } catch (Throwable e) { log.error("更新物模型超级表失败", e); } } + // 获取表字段 + private List getTableFields(String tableName) { + List fields = new ArrayList<>(); + // 获取超级表的描述信息 + List> maps = tdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), tableName); + if (maps != null) { + // 过滤掉 note 字段为 TAG 的记录 + maps = maps.stream().filter(map -> !"TAG".equals(map.get("note"))).toList(); + // 过滤掉 time 字段 + maps = maps.stream().filter(map -> !"time".equals(map.get("field"))).toList(); + // 解析字段信息 + fields = FieldParser.parse(maps.stream() + .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) + .collect(Collectors.toList())); + } + return fields; + } + + // 更新表字段 + private void updateTableFields(String tableName, List oldFields, List newFields) { + // 获取新增字段 + List addFields = getAddFields(oldFields, newFields); + // 获取修改字段 + List modifyFields = getModifyFields(oldFields, newFields); + // 获取删除字段 + List dropFields = getDropFields(oldFields, newFields); + + String dataBaseName = url.substring(url.lastIndexOf("/") + 1); + // 添加新增字段 + if (CollUtil.isNotEmpty(addFields)) { + tdEngineService.addColumnForSuperTable(dataBaseName,tableName, addFields); + } + // 删除旧字段 + if (CollUtil.isNotEmpty(dropFields)) { + tdEngineService.dropColumnForSuperTable(dataBaseName,tableName, dropFields); + } + // 修改字段(先删除再添加) + if (CollUtil.isNotEmpty(modifyFields)) { + tdEngineService.dropColumnForSuperTable(dataBaseName,tableName, modifyFields); + tdEngineService.addColumnForSuperTable(dataBaseName,tableName, modifyFields); + } + } + + // 获取新增字段 + private List getAddFields(List oldFields, List newFields) { + return newFields.stream() + .filter(f -> oldFields.stream().noneMatch(old -> old.getFieldName().equals(f.getFieldName()))) + .collect(Collectors.toList()); + } + + // 获取修改字段 + private List getModifyFields(List oldFields, List newFields) { + return newFields.stream() + .filter(f -> oldFields.stream().anyMatch(old -> + old.getFieldName().equals(f.getFieldName()) && + (!old.getDataType().equals(f.getDataType()) || !Objects.equals(old.getDataLength(), f.getDataLength())))) + .collect(Collectors.toList()); + } + + // 获取删除字段 + private List getDropFields(List oldFields, List newFields) { + return oldFields.stream() + .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName()) && + newFields.stream().noneMatch(n -> n.getFieldName().equals(f.getFieldName()))) + .collect(Collectors.toList()); + } + @Override public void createSuperTableDataModel(IotProductDO product, List functionList) { - // 1. 生成 ThingModelRespVO - ThingModelRespVO thingModel = new ThingModelRespVO(); - thingModel.setId(product.getId()); - thingModel.setProductKey(product.getProductKey()); + ThingModelRespVO thingModel = buildThingModel(product, functionList); - // 1.1 设置属性、服务和事件 - ThingModelRespVO.Model model = new ThingModelRespVO.Model(); - List properties = new ArrayList<>(); - - // 1.2 遍历功能列表并分类 - for (IotThinkModelFunctionDO function : functionList) { - if (Objects.requireNonNull(IotProductFunctionTypeEnum.valueOf(function.getType())) == IotProductFunctionTypeEnum.PROPERTY) { - ThingModelProperty property = new ThingModelProperty(); - property.setIdentifier(function.getIdentifier()); - property.setName(function.getName()); - property.setDescription(function.getDescription()); - property.setDataType(function.getProperty().getDataType()); - properties.add(property); - } - } - - // 1.3 判断属性列表是否为空 - if (properties.isEmpty()) { + if (thingModel.getModel().getProperties().isEmpty()) { log.warn("物模型属性列表为空,不创建超级表"); return; } - model.setProperties(properties); - thingModel.setModel(model); + String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); + String dataBaseName = url.substring(url.lastIndexOf("/") + 1); + Integer tableExists = tdEngineService.checkSuperTableExists(dataBaseName, superTableName); - // 2. 判断是否已经创建,如果已经创建则进行更新 - String tbName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); - Integer iot = tdEngineMapper.checkTableExists("ruoyi_vue_pro", tbName); - if (iot != null && iot > 0) { - // 3. 更新 + if (tableExists != null && tableExists > 0) { updateSuperTable(thingModel, product.getDeviceType()); } else { - // 4. 创建 createSuperTable(thingModel, product.getDeviceType()); } } - /** - * 根据产品key获取产品属性超级表名 - */ - static String getProductPropertySTableName(Integer deviceType, String productKey) { - if (deviceType == 1) { - return String.format("gateway_sub_" + productKey).toLowerCase(); - } else if (deviceType == 2) { - return String.format("gateway_" + productKey).toLowerCase(); - } else { - return String.format("device_" + productKey).toLowerCase(); - } + private ThingModelRespVO buildThingModel(IotProductDO product, List functionList) { + ThingModelRespVO thingModel = new ThingModelRespVO(); + thingModel.setId(product.getId()); + thingModel.setProductKey(product.getProductKey()); + + ThingModelRespVO.Model model = new ThingModelRespVO.Model(); + List properties = functionList.stream() + .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals(IotProductFunctionTypeEnum.valueOf(function.getType()))) + .map(this::buildThingModelProperty) + .collect(Collectors.toList()); + + model.setProperties(properties); + thingModel.setModel(model); + + return thingModel; } - /** - * 根据deviceId获取设备属性表名 - */ - static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) { - return String.format(deviceType + "_" + productKey + "_" + deviceKey).toLowerCase(); + private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) { + ThingModelProperty property = new ThingModelProperty(); + property.setIdentifier(function.getIdentifier()); + property.setName(function.getName()); + property.setDescription(function.getDescription()); + property.setDataType(function.getProperty().getDataType()); + return property; } -} + + static String getProductPropertySTableName(Integer deviceType, String productKey) { + return switch (deviceType) { + case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); + case 2 -> String.format("gateway_%s", productKey).toLowerCase(); + default -> String.format("device_%s", productKey).toLowerCase(); + }; + } + + static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) { + return String.format("%s_%s_%s", deviceType, productKey, deviceKey).toLowerCase(); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java index b3ae6f818..9319adbd7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.service.tdengine; -import cn.iocoder.yudao.module.iot.domain.FieldsVo; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.domain.SelectDto; import cn.iocoder.yudao.module.iot.domain.TableDto; import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; @@ -27,12 +27,44 @@ public interface TdEngineService { * * @param schemaFields schema字段 * @param tagsFields tags字段 - * @param dataBaseName 数据库名称 * @param superTableName 超级表名称 - * @throws Exception 异常 */ - void createSuperTable(List schemaFields, List tagsFields, String dataBaseName, - String superTableName) throws Exception; + void createSuperTable(List schemaFields, List tagsFields, String dataBaseName, String superTableName); + + /** + * 检查超级表是否存在 + */ + Integer checkSuperTableExists(String dataBaseName, String superTableName); + + + /** + * 获取超级表的结构信息 + */ + List> describeSuperTable(String dataBaseName, String superTableName); + + /** + * 为超级表添加列 + * + * @param dataBaseName 数据库名称 + * @param superTableName 超级表名称 + * @param fieldsVo 字段信息 + */ + void addColumnForSuperTable(String dataBaseName,String superTableName, List fieldsVo); + + /** + * 为超级表删除列 + * + * @param dataBaseName 数据库名称 + * @param superTableName 超级表名称 + * @param fieldsVo 字段信息 + */ + void dropColumnForSuperTable(String dataBaseName,String superTableName, List fieldsVo); + + /** + * 为超级表添加tag + */ + Long getCountByTimesTamp(SelectDto selectDto) throws Exception; + /** * 创建表 @@ -59,37 +91,6 @@ public interface TdEngineService { */ List> selectByTimesTamp(SelectDto selectDto) throws Exception; - /** - * 为超级表添加列 - * - * @param superTableName 超级表名称 - * @param fieldsVo 字段信息 - * @throws Exception 异常 - */ - void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception; - - /** - * 为超级表删除列 - * - * @param superTableName 超级表名称 - * @param fieldsVo 字段信息 - * @throws Exception 异常 - */ - void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) throws Exception; - - /** - * 为超级表添加tag - */ - Long getCountByTimesTamp(SelectDto selectDto) throws Exception; - - /** - * 检查表是否存在 - * - * @return 1存在 0不存在 - * @throws Exception 异常 - */ - Integer checkTableExists(SelectDto selectDto) throws Exception; - /** * 初始化超级表 * @@ -138,4 +139,6 @@ public interface TdEngineService { * @return 数据 */ List> getAggregateData(SelectVisualDto selectVisualDto); + + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java index 70933617f..d61b78922 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.iot.service.tdengine; -import cn.iocoder.yudao.module.iot.domain.FieldsVo; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; import cn.iocoder.yudao.module.iot.domain.SelectDto; import cn.iocoder.yudao.module.iot.domain.TableDto; import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -15,25 +17,27 @@ import java.util.Map; @Slf4j public class TdEngineServiceImpl implements TdEngineService { + @Resource + private TdEngineMapper tdEngineMapper; @Override public void createDateBase(String dataBaseName) { - + tdEngineMapper.createDatabase(dataBaseName); } @Override - public void createSuperTable(List schemaFields, List tagsFields, String dataBaseName, String superTableName) { - + public void createSuperTable(List schemaFields, List tagsFields, String dataBaseName, String superTableName) { + tdEngineMapper.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); } @Override public void createTable(TableDto tableDto) { - + tdEngineMapper.createTable(tableDto); } @Override public void insertData(TableDto tableDto) { - + tdEngineMapper.insertData(tableDto); } @Override @@ -42,13 +46,17 @@ public class TdEngineServiceImpl implements TdEngineService { } @Override - public void addColumnForSuperTable(String superTableName, FieldsVo fieldsVo) { - + public void addColumnForSuperTable(String dataBaseName,String superTableName, List fields) { + for (TdFieldDO field : fields) { + tdEngineMapper.addColumnForSuperTable(dataBaseName,superTableName, field); + } } @Override - public void dropColumnForSuperTable(String superTableName, FieldsVo fieldsVo) { - + public void dropColumnForSuperTable(String dataBaseName,String superTableName, List fields) { + for (TdFieldDO field : fields) { + tdEngineMapper.dropColumnForSuperTable(dataBaseName,superTableName, field); + } } @Override @@ -56,11 +64,6 @@ public class TdEngineServiceImpl implements TdEngineService { return 0L; } - @Override - public Integer checkTableExists(SelectDto selectDto) { - return 0; - } - @Override public void initSTableFrame(String msg) { @@ -90,4 +93,15 @@ public class TdEngineServiceImpl implements TdEngineService { public List> getAggregateData(SelectVisualDto selectVisualDto) { return List.of(); } + + @Override + public Integer checkSuperTableExists(String dataBaseName, String superTableName) { + List> results = tdEngineMapper.showSuperTables(dataBaseName, superTableName); + return results == null || results.isEmpty() ? 0 : results.size(); + } + + @Override + public List> describeSuperTable(String dataBaseName, String superTableName) { + return tdEngineMapper.describeSuperTable(dataBaseName, superTableName); + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 1e356c6b7..3f698999c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -174,8 +174,10 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe public void createSuperTableDataModel(Long productId) { // 1. 查询产品 IotProductDO product = productService.getProduct(productId); + // 2. 查询产品的物模型功能列表 List functionList = thinkModelFunctionMapper.selectListByProductId(productId); + // 3. 生成 TDengine 的数据模型 dbStructureDataService.createSuperTableDataModel(product, functionList); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml index f722e0130..f1d748198 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml @@ -8,7 +8,7 @@ - create table if not exists #{dataBaseName}.#{superTableName} + CREATE STABLE IF NOT EXISTS ${dataBaseName}.${superTableName} @@ -16,46 +16,48 @@ - - timestamp + + TIMESTAMP - - tinyint + + TINYINT - - smallint + + SMALLINT - - int + + INT - - bigint + + BIGINT - - float + + FLOAT - - double + + DOUBLE - - binary + + BINARY - - nchar + + NCHAR - - bool + + BOOL - - json + + JSON - - (#{item.size}) + + ( + ${item.dataLength} + ) - tags + TAGS @@ -64,43 +66,45 @@ - - timestamp + + TIMESTAMP - - tinyint + + TINYINT - - smallint + + SMALLINT - - int + + INT - - bigint + + BIGINT - - float + + FLOAT - - double + + DOUBLE - - binary + + BINARY - - nchar + + NCHAR - - bool + + BOOL - - json + + JSON - - (#{item.size}) + + ( + ${item.dataLength} + ) @@ -135,7 +139,6 @@ - - ALTER - STABLE - #{superTableName} - ADD - COLUMN - - #{fieldsVo.fieldName} + ALTER STABLE ${dataBaseName}.${superTableName} ADD COLUMN + + #{field.fieldName} - + - - timestamp + + TIMESTAMP - - tinyint + + TINYINT - - smallint + + SMALLINT - - int + + INT - - bigint + + BIGINT - - float + + FLOAT - - double + + DOUBLE - - binary + + BINARY - - nchar + + NCHAR - - bool + + BOOL - - json + + JSON - + ( - #{fieldsVo.size} + #{field.dataLength} ) - ALTER - STABLE - #{superTableName} - DROP - COLUMN - - #{fieldsVo.fieldName} + ALTER STABLE ${dataBaseName}.${superTableName} DROP COLUMN + + #{field.fieldName} @@ -215,49 +210,49 @@ #{superTableName} ADD TAG - - #{fieldsVo.fieldName} + + #{fieldDO.fieldName} - + - + timestamp - + tinyint - + smallint - + int - + bigint - + float - + double - + binary - + nchar - + bool - + json - + ( - #{fieldsVo.size} + #{fieldDO.dataLength} ) @@ -279,11 +274,8 @@ FROM #{dataBaseName}.#{tableName} WHERE ${fieldName} BETWEEN #{startTime} AND #{endTime} - + SHOW ${dataBaseName}.STABLES LIKE '${superTableName}' + + - - - ${sql} - + From 88088c798799bfebd00439199914f2fb08a7a8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 26 Oct 2024 23:26:26 +0800 Subject: [PATCH 005/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=20=E4=BA=A7=E5=93=81=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E5=90=8E=E7=89=A9=E6=A8=A1=E5=9E=8B=E4=B8=8D=E5=8F=AF=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../IotThinkModelFunctionServiceImpl.java | 25 ++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 31702e1e6..be9d28ecb 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -13,6 +13,7 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在"); ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); + ErrorCode PRODUCT_STATUS_NOT_ALLOW_FUNCTION = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); // ========== IoT 产品物模型 1-050-002-000 ============ ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 3f698999c..dd7a51786 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkMod import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotDbStructureDataService; import jakarta.annotation.Resource; @@ -65,17 +66,27 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3. 系统保留字段,不能用于标识符定义 validateNotDefaultEventAndService(createReqVO.getIdentifier()); - // 3. 插入数据库 + // 4. 校验产品状态,发布状态下,不允许新增功能 + validateProductStatus(createReqVO.getProductId()); + + // 5. 插入数据库 IotThinkModelFunctionDO function = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); thinkModelFunctionMapper.insert(function); - // 4. 如果创建的是属性,需要更新默认的事件和服务 + // 6. 如果创建的是属性,需要更新默认的事件和服务 if (Objects.equals(createReqVO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } return function.getId(); } + private void validateProductStatus(Long createReqVO) { + IotProductDO product = productService.getProduct(createReqVO); + if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getType())) { + throw exception(PRODUCT_STATUS_NOT_ALLOW_FUNCTION); + } + } + private void validateNotDefaultEventAndService(String identifier) { // set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义 if (CollUtil.containsAny(Arrays.asList("set", "get", "post", "property", "event", "time", "value"), Collections.singletonList(identifier))) { @@ -109,11 +120,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 2. 校验功能标识符是否唯一 validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); - // 3. 更新数据库 + // 3. 校验产品状态,发布状态下,不允许操作功能 + validateProductStatus(updateReqVO.getProductId()); + + // 4. 更新数据库 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); thinkModelFunctionMapper.updateById(thinkModelFunction); - // 4. 如果更新的是属性,需要更新默认的事件和服务 + // 5. 如果更新的是属性,需要更新默认的事件和服务 if (Objects.equals(updateReqVO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } @@ -135,6 +149,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); } + // 3. 校验产品状态,发布状态下,不允许操作功能 + validateProductStatus(functionDO.getProductId()); + // 2. 删除功能 thinkModelFunctionMapper.deleteById(id); From 8c84ac9d8a88dd73d03746274f4f6e2de7004668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 27 Oct 2024 21:26:35 +0800 Subject: [PATCH 006/228] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91=20mqtt=20=E6=95=B0=E6=8D=AE=E6=8E=A5?= =?UTF-8?q?=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/yudao-module-iot-biz/pom.xml | 5 ++ .../tdengine/ThingModelMessage.java | 70 +++++++++++++++++++ .../iot/emq/service/EmqxServiceImpl.java | 14 +++- .../service/device/IotDeviceDataService.java | 26 +++++++ .../device/IotDeviceDataServiceImpl.java | 39 +++++++++++ .../iot/service/device/IotDeviceService.java | 9 +++ ...iceImpl.java => IotDeviceServiceImpl.java} | 9 ++- .../IotDbStructureDataServiceImpl.java | 16 ++--- ...neService.java => IotTdEngineService.java} | 10 +-- ...eImpl.java => IotTdEngineServiceImpl.java} | 2 +- .../tdengine/IotThingModelMessageService.java | 16 +++++ .../IotThingModelMessageServiceImpl.java | 13 ++++ .../mapper/tdengine/TdEngineMapper.xml | 18 +++-- 13 files changed, 224 insertions(+), 23 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/{DeviceServiceImpl.java => IotDeviceServiceImpl.java} (95%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/{TdEngineService.java => IotTdEngineService.java} (91%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/{TdEngineServiceImpl.java => IotTdEngineServiceImpl.java} (97%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index cb2fd818f..013287d2b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -25,6 +25,11 @@ ${revision} + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + + cn.iocoder.boot diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java new file mode 100644 index 000000000..d5009dc24 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +/** + * 物模型消息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ThingModelMessage { + + /** + * 消息ID + */ + private String id; + + /** + * 扩展功能的参数 + */ + private Object sys; + + /** + * 请求方法 例如:thing.event.property.post + */ + private String method; + + /** + * 请求参数 + */ + private Object params; + + /** + * 属性上报时间戳 + */ + private Long time; + + /** + * 设备信息 + */ + private String productKey; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 设备 key + */ + private String deviceKey; + + /** + * 转换为 Map 类型 + */ + public Map dataToMap() { + Map mapData = new HashMap<>(); + if (params instanceof Map) { + ((Map) params).forEach((key, value) -> mapData.put(key.toString(), value)); + } + return mapData; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index 0c1a87f7f..c82d0d305 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.iot.emq.service; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttMessage; @@ -16,13 +19,20 @@ import org.springframework.stereotype.Service; @Service public class EmqxServiceImpl implements EmqxService { + @Resource + private IotDeviceDataService iotDeviceDataService; + // TODO 多线程处理消息 @Override public void subscribeCallback(String topic, MqttMessage mqttMessage) { log.info("收到消息,主题: {}, 内容: {}", topic, new String(mqttMessage.getPayload())); // 根据不同的主题,处理不同的业务逻辑 if (topic.contains("/property/post")) { - // 设备上报数据 + // 设备上报数据 topic /sys/f13f57c63e9/dianbiao1/thing/event/property/post + String productKey = topic.split("/")[2]; + String deviceName = topic.split("/")[3]; + String message = new String(mqttMessage.getPayload()); + iotDeviceDataService.saveDeviceData(productKey, deviceName, message); } } @@ -30,7 +40,7 @@ public class EmqxServiceImpl implements EmqxService { public void subscribe(MqttClient client) { try { // 订阅默认主题,可以根据需要修改 -// client.subscribe("$share/yudao/+/+/#", 1); + client.subscribe("/sys/+/+/#", 1); log.info("订阅默认主题成功"); } catch (Exception e) { log.error("订阅默认主题失败", e); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java new file mode 100644 index 000000000..4f3ef37d6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import jakarta.validation.Valid; + +/** + * IoT 设备数据 Service 接口 + * + * @author 芋道源码 + */ +public interface IotDeviceDataService { + + + /** + * 保存设备数据 + * + * @param productKey 产品 key + * @param deviceName 设备名称 + * @param message 消息 + */ + void saveDeviceData(String productKey, String deviceName, String message); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java new file mode 100644 index 000000000..8f0c859ad --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import cn.hutool.json.JSONObject; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class IotDeviceDataServiceImpl implements IotDeviceDataService { + + @Resource + private IotDeviceService deviceService; + @Resource + private IotThingModelMessageService thingModelMessageService; + + @Override + public void saveDeviceData(String productKey, String deviceName, String message) { + // 1. 根据产品 key 和设备名称,获得设备信息 + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(productKey, deviceName); + // 2. 解析消息,保存数据 + JSONObject jsonObject = new JSONObject(message); + log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", productKey, deviceName, jsonObject); + ThingModelMessage thingModelMessage = ThingModelMessage.builder() + .id(jsonObject.getStr("id")) + .sys(jsonObject.get("sys")) + .method(jsonObject.getStr("method")) + .params(jsonObject.get("params")) + .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time")) + .productKey(productKey) + .deviceName(deviceName) + .deviceKey(device.getDeviceKey()) + .build(); + thingModelMessageService.saveThingModelMessage(thingModelMessage); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 032a7478e..c967a957e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -64,4 +64,13 @@ public interface IotDeviceService { * @return 设备数量 */ Long getDeviceCountByProductId(Long productId); + + /** + * 根据产品 key 和设备名称,获得设备信息 + * + * @param productKey 产品 key + * @param deviceName 设备名称 + * @return 设备信息 + */ + IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java similarity index 95% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 2ae08bb94..d24975b72 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; @@ -32,7 +33,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @Service @Validated @Slf4j -public class DeviceServiceImpl implements IotDeviceService { +public class IotDeviceServiceImpl implements IotDeviceService { @Resource private IotDeviceMapper deviceMapper; @@ -224,4 +225,10 @@ public class DeviceServiceImpl implements IotDeviceService { return deviceMapper.selectCountByProductId(productId); } + @Override + @TenantIgnore + public IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName) { + return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java index d42fd72fc..0506546be 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java @@ -25,7 +25,7 @@ import java.util.stream.Collectors; public class IotDbStructureDataServiceImpl implements IotDbStructureDataService { @Resource - private TdEngineService tdEngineService; + private IotTdEngineService iotTdEngineService; @Resource private TdRestApi tdRestApi; @@ -87,7 +87,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService // 5. 创建超级表 String dataBaseName = url.substring(url.lastIndexOf("/") + 1); - tdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); + iotTdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); } @Override @@ -107,7 +107,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService private List getTableFields(String tableName) { List fields = new ArrayList<>(); // 获取超级表的描述信息 - List> maps = tdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), tableName); + List> maps = iotTdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), tableName); if (maps != null) { // 过滤掉 note 字段为 TAG 的记录 maps = maps.stream().filter(map -> !"TAG".equals(map.get("note"))).toList(); @@ -133,16 +133,16 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService String dataBaseName = url.substring(url.lastIndexOf("/") + 1); // 添加新增字段 if (CollUtil.isNotEmpty(addFields)) { - tdEngineService.addColumnForSuperTable(dataBaseName,tableName, addFields); + iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, addFields); } // 删除旧字段 if (CollUtil.isNotEmpty(dropFields)) { - tdEngineService.dropColumnForSuperTable(dataBaseName,tableName, dropFields); + iotTdEngineService.dropColumnForSuperTable(dataBaseName, tableName, dropFields); } // 修改字段(先删除再添加) if (CollUtil.isNotEmpty(modifyFields)) { - tdEngineService.dropColumnForSuperTable(dataBaseName,tableName, modifyFields); - tdEngineService.addColumnForSuperTable(dataBaseName,tableName, modifyFields); + iotTdEngineService.dropColumnForSuperTable(dataBaseName, tableName, modifyFields); + iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, modifyFields); } } @@ -181,7 +181,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); String dataBaseName = url.substring(url.lastIndexOf("/") + 1); - Integer tableExists = tdEngineService.checkSuperTableExists(dataBaseName, superTableName); + Integer tableExists = iotTdEngineService.checkSuperTableExists(dataBaseName, superTableName); if (tableExists != null && tableExists > 0) { updateSuperTable(thingModel, product.getDeviceType()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java similarity index 91% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java index 9319adbd7..3175d2839 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java @@ -12,7 +12,7 @@ import java.util.Map; /** * TdEngineService */ -public interface TdEngineService { +public interface IotTdEngineService { /** * 创建数据库 @@ -45,20 +45,20 @@ public interface TdEngineService { /** * 为超级表添加列 * - * @param dataBaseName 数据库名称 + * @param dataBaseName 数据库名称 * @param superTableName 超级表名称 * @param fieldsVo 字段信息 */ - void addColumnForSuperTable(String dataBaseName,String superTableName, List fieldsVo); + void addColumnForSuperTable(String dataBaseName, String superTableName, List fieldsVo); /** * 为超级表删除列 * - * @param dataBaseName 数据库名称 + * @param dataBaseName 数据库名称 * @param superTableName 超级表名称 * @param fieldsVo 字段信息 */ - void dropColumnForSuperTable(String dataBaseName,String superTableName, List fieldsVo); + void dropColumnForSuperTable(String dataBaseName, String superTableName, List fieldsVo); /** * 为超级表添加tag diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java index d61b78922..3c87f624d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java @@ -15,7 +15,7 @@ import java.util.Map; @Service @Slf4j -public class TdEngineServiceImpl implements TdEngineService { +public class IotTdEngineServiceImpl implements IotTdEngineService { @Resource private TdEngineMapper tdEngineMapper; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java new file mode 100644 index 000000000..937338544 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; + +/** + * 物模型消息 Service + */ +public interface IotThingModelMessageService { + + /** + * 保存物模型消息 + * + * @param thingModelMessage 物模型消息 + */ + void saveThingModelMessage(ThingModelMessage thingModelMessage); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java new file mode 100644 index 000000000..d47756423 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import org.springframework.stereotype.Service; + +@Service +public class IotThingModelMessageServiceImpl implements IotThingModelMessageService { + + @Override + public void saveThingModelMessage(ThingModelMessage thingModelMessage) { + // TODO 芋艿,后续实现 + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml index f1d748198..d3f1088a1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml @@ -2,9 +2,10 @@ + - create database if not exists #{dataBaseName} + CREATE DATABASE IF NOT EXISTS ${dataBaseName} @@ -271,7 +272,8 @@ select last(*) - from #{dataBaseName}.#{stableName} group by ${tagsName} + from #{dataBaseName}.#{stableName} + group by ${tagsName} From 3dafd31da6ba6dad4beba2954ca5ed689a209699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Thu, 31 Oct 2024 21:47:54 +0800 Subject: [PATCH 007/228] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91=20=E6=95=B0=E6=8D=AE=E6=8E=A5=E6=94=B6?= =?UTF-8?q?=EF=BC=8CJSON=20=E6=A0=87=E5=87=86=E6=A0=BC=E5=BC=8F=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8E=A5=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/dal/dataobject/tdengine/TableDO.java | 27 ++++ .../dal/dataobject/tdengine/TableData.java | 17 ++- .../dal/dataobject/tdengine/TdFieldDO.java | 16 +++ .../IotThinkModelFunctionMapper.java | 3 + .../iot/dal/tdengine/TdEngineMapper.java | 17 ++- .../iot/emq/service/EmqxServiceImpl.java | 2 + .../device/IotDeviceDataServiceImpl.java | 2 +- .../service/device/IotDeviceServiceImpl.java | 23 +++- .../IotDbStructureDataServiceImpl.java | 19 +-- .../service/tdengine/IotTdEngineService.java | 8 +- .../tdengine/IotTdEngineServiceImpl.java | 6 +- .../tdengine/IotThingModelMessageService.java | 4 +- .../IotThingModelMessageServiceImpl.java | 118 +++++++++++++++++- .../IotThinkModelFunctionService.java | 8 ++ .../IotThinkModelFunctionServiceImpl.java | 5 + .../mapper/tdengine/TdEngineMapper.xml | 27 ++-- 16 files changed, 247 insertions(+), 55 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableDO.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableDO.java new file mode 100644 index 000000000..11751ff64 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableDO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import cn.iocoder.yudao.module.iot.domain.BaseEntity; +import lombok.Data; + +import java.util.List; + +@Data +public class TableDO extends BaseEntity { + + /** + * 超级表普通列字段的值 + * 值需要与创建超级表时普通列字段的数据类型对应上 + */ + private List schemaFieldValues; + + /** + * 超级表标签字段的值 + * 值需要与创建超级表时标签字段的数据类型对应上 + */ + private List tagsFieldValues; + + /** + * 表名称 + */ + private String tableName; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java index e9acbb7f0..dfb3ed212 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java @@ -15,18 +15,23 @@ public class TableData { */ private List schemaFieldList; - /** - * 超级表标签字段的值 - * 值需要与创建超级表时标签字段的数据类型对应上 - */ - private List tagsValueList; - /** * 超级表普通列字段的值 * 值需要与创建超级表时普通列字段的数据类型对应上 */ private List schemaValueList; + /** + * 超级表标签字段的名称 + */ + private List tagsFieldList; + + /** + * 超级表标签字段的值 + * 值需要与创建超级表时标签字段的数据类型对应上 + */ + private List tagsValueList; + /** * 表名称 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java index d9cf28f1b..765652748 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java @@ -19,6 +19,11 @@ public class TdFieldDO { */ private String fieldName; + /** + * 字段值 + */ + private Object fieldValue; + /** * 字段类型 */ @@ -28,4 +33,15 @@ public class TdFieldDO { * 字段长度 */ private Integer dataLength = 0; + + public TdFieldDO(String fieldName, String dataType, Integer dataLength) { + this.fieldName = fieldName; + this.dataType = dataType; + this.dataLength = dataLength; + } + + public TdFieldDO(String fieldName, Object fieldValue) { + this.fieldName = fieldName; + this.fieldValue = fieldValue; + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index e8b96e022..2883abe4e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -55,4 +55,7 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX selectListByProductKey(String productKey){ + return selectList(IotThinkModelFunctionDO::getProductKey, productKey); + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java index 85e324a77..94db527c2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.domain.FieldsVo; import cn.iocoder.yudao.module.iot.domain.SelectDto; -import cn.iocoder.yudao.module.iot.domain.TableDto; import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; import com.baomidou.dynamic.datasource.annotation.DS; @@ -86,9 +86,20 @@ public interface TdEngineMapper { @Param("superTableName") String superTableName, @Param("field") TdFieldDO field); - void createTable(TableDto tableDto); + /** + * 创建表 - 创建超级表的子表 + * @param tableDO 表信息 + */ + @InterceptorIgnore(tenantLine = "true") + void createTable(TableDO tableDO); - void insertData(TableDto tableDto); + /** + * 插入数据 - 指定列插入数据 + * + * @param tableDto 数据 + */ + @InterceptorIgnore(tenantLine = "true") + void insertData(TableDO tableDto); List> selectByTimestamp(SelectDto selectDto); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index c82d0d305..f338d6249 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -6,6 +6,7 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; // TODO @芋艿:在瞅瞅 @@ -24,6 +25,7 @@ public class EmqxServiceImpl implements EmqxService { // TODO 多线程处理消息 @Override + @Async public void subscribeCallback(String topic, MqttMessage mqttMessage) { log.info("收到消息,主题: {}, 内容: {}", topic, new String(mqttMessage.getPayload())); // 根据不同的主题,处理不同的业务逻辑 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 8f0c859ad..6b7aac21f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -34,6 +34,6 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { .deviceName(deviceName) .deviceKey(device.getDeviceKey()) .build(); - thingModelMessageService.saveThingModelMessage(thingModelMessage); + thingModelMessageService.saveThingModelMessage(device,thingModelMessage); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index d24975b72..f3243900e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -20,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; +import java.util.Objects; import java.util.UUID; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -213,10 +214,30 @@ public class IotDeviceServiceImpl implements IotDeviceService { @Override public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) { // 校验存在 - validateDeviceExists(updateReqVO.getId()); + IotDeviceDO iotDeviceDO = validateDeviceExists(updateReqVO.getId()); // 更新状态和更新时间 IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); + + // 以前是未激活,现在是上线,设置设备激活时间 + if (Objects.equals(iotDeviceDO.getStatus(), IotDeviceStatusEnum.INACTIVE.getStatus()) + && Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { + updateObj.setActiveTime(LocalDateTime.now()); + } + + // 如果是上线,设置上线时间 + if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { + updateObj.setLastOnlineTime(LocalDateTime.now()); + } + + // 如果是离线,设置离线时间 + if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.OFFLINE.getStatus())) { + updateObj.setLastOfflineTime(LocalDateTime.now()); + } + + // 设置状态更新时间 + updateObj.setStatusLastUpdateTime(LocalDateTime.now()); + deviceMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java index 0506546be..b7de8882a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java @@ -60,27 +60,10 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService dataType("NCHAR"). dataLength(64). build()); - // 年 tagsFields.add(TdFieldDO.builder(). - fieldName("year"). + fieldName("device_type"). dataType("INT"). build()); - // 月 - tagsFields.add(TdFieldDO.builder(). - fieldName("month"). - dataType("INT"). - build()); - // 日 - tagsFields.add(TdFieldDO.builder(). - fieldName("day"). - dataType("INT"). - build()); - // 时 - tagsFields.add(TdFieldDO.builder(). - fieldName("hour"). - dataType("INT"). - build()); - // 4. 获取超级表的名称 String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java index 3175d2839..753284aca 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.service.tdengine; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.domain.SelectDto; -import cn.iocoder.yudao.module.iot.domain.TableDto; import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; @@ -70,17 +70,15 @@ public interface IotTdEngineService { * 创建表 * * @param tableDto 表信息 - * @throws Exception 异常 */ - void createTable(TableDto tableDto) throws Exception; + void createTable(TableDO tableDto); /** * 插入数据 * * @param tableDto 表信息 - * @throws Exception 异常 */ - void insertData(TableDto tableDto) throws Exception; + void insertData(TableDO tableDto); /** * 根据时间戳查询数据 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java index 3c87f624d..c7f7e7309 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.iot.service.tdengine; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; import cn.iocoder.yudao.module.iot.domain.SelectDto; -import cn.iocoder.yudao.module.iot.domain.TableDto; import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; import jakarta.annotation.Resource; @@ -31,12 +31,12 @@ public class IotTdEngineServiceImpl implements IotTdEngineService { } @Override - public void createTable(TableDto tableDto) { + public void createTable(TableDO tableDto) { tdEngineMapper.createTable(tableDto); } @Override - public void insertData(TableDto tableDto) { + public void insertData(TableDO tableDto) { tdEngineMapper.insertData(tableDto); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java index 937338544..b2f51a7f8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.tdengine; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; /** @@ -10,7 +11,8 @@ public interface IotThingModelMessageService { /** * 保存物模型消息 * + * @param device 设备 * @param thingModelMessage 物模型消息 */ - void saveThingModelMessage(ThingModelMessage thingModelMessage); + void saveThingModelMessage(IotDeviceDO device,ThingModelMessage thingModelMessage); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index d47756423..ae7fa51ee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -1,13 +1,127 @@ package cn.iocoder.yudao.module.iot.service.tdengine; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j @Service public class IotThingModelMessageServiceImpl implements IotThingModelMessageService { + @Value("${spring.datasource.dynamic.datasource.tdengine.url}") + private String url; + + @Resource + private IotThinkModelFunctionService iotThinkModelFunctionService; + @Resource + private IotDeviceService iotDeviceService; + @Resource + private IotTdEngineService iotTdEngineService; + @Override - public void saveThingModelMessage(ThingModelMessage thingModelMessage) { - // TODO 芋艿,后续实现 + @TenantIgnore + public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) { + // 判断设备状态,如果为未激活状态,创建数据表 + if (device.getStatus().equals(0)) { + // 创建设备数据表 + createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); + // 更新设备状态 + IotDeviceStatusUpdateReqVO updateReqVO = new IotDeviceStatusUpdateReqVO(); + updateReqVO.setId(device.getId()); + updateReqVO.setStatus(IotDeviceStatusEnum.ONLINE.getStatus()); + iotDeviceService.updateDeviceStatus(updateReqVO); + } + + // 1. 获取设备属性 + Map params = thingModelMessage.dataToMap(); + + // 2. 物模型校验,过滤非物模型属性 + List thinkModelFunctionListByProductKey = iotThinkModelFunctionService.getThinkModelFunctionListByProductKey(thingModelMessage.getProductKey()); + + // 2.1 筛选是属性 IotProductFunctionTypeEnum + thinkModelFunctionListByProductKey.removeIf(iotThinkModelFunctionDO -> !iotThinkModelFunctionDO.getType().equals(IotProductFunctionTypeEnum.PROPERTY.getType())); + if (thinkModelFunctionListByProductKey.isEmpty()) { + return; + } + // 2.2 获取属性名称 + Map thingModelProperties = thinkModelFunctionListByProductKey.stream().collect(Collectors.toMap(IotThinkModelFunctionDO::getIdentifier, IotThinkModelFunctionDO::getName)); + + // 4. 保存属性记录 + List schemaFieldValues = new ArrayList<>(); + + // 1. 设置字段名 + schemaFieldValues.add(new TdFieldDO("time", thingModelMessage.getTime())); + + // 2. 遍历新属性 + params.forEach((key, val) -> { + if (thingModelProperties.containsKey(key)) { + schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val)); + } + }); + + // 3. 保存设备属性 + TableDO tableData = new TableDO(); + tableData.setDataBaseName(url.substring(url.lastIndexOf("/") + 1)); + tableData.setSuperTableName(getProductPropertySTableName(device.getDeviceType(), device.getProductKey())); + tableData.setTableName("device_" + device.getProductKey().toLowerCase() + "_" + device.getDeviceName().toLowerCase()); + tableData.setSchemaFieldValues(schemaFieldValues); + + // 4. 保存数据 + iotTdEngineService.insertData(tableData); + } + + private void createDeviceTable(Integer deviceType, String productKey, String deviceName, String deviceKey) { + List tagsFieldValues = new ArrayList<>(); + String SuperTableName = getProductPropertySTableName(deviceType, productKey); + List> maps = iotTdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), SuperTableName); + if (maps != null) { + List> taggedNotesList = maps.stream().filter(map -> "TAG".equals(map.get("note"))).toList(); + tagsFieldValues = FieldParser.parse(taggedNotesList.stream() + .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) + .collect(Collectors.toList())); + for (TdFieldDO tagsFieldValue : tagsFieldValues) { + switch (tagsFieldValue.getFieldName()) { + case "product_key" -> tagsFieldValue.setFieldValue(productKey); + case "device_key" -> tagsFieldValue.setFieldValue(deviceKey); + case "device_name" -> tagsFieldValue.setFieldValue(deviceName); + case "device_type" -> tagsFieldValue.setFieldValue(deviceType); + } + } + } + + // 1. 创建设备数据表 + String tableName = "device_" + productKey.toLowerCase() + "_" + deviceName.toLowerCase(); + TableDO tableDto = new TableDO(); + tableDto.setDataBaseName(url.substring(url.lastIndexOf("/") + 1)); + tableDto.setSuperTableName(SuperTableName); + tableDto.setTableName(tableName); + tableDto.setTagsFieldValues(tagsFieldValues); + iotTdEngineService.createTable(tableDto); + } + + static String getProductPropertySTableName(Integer deviceType, String productKey) { + return switch (deviceType) { + case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); + case 2 -> String.format("gateway_%s", productKey).toLowerCase(); + default -> String.format("device_%s", productKey).toLowerCase(); + }; } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java index 3067772e6..a6bf7b458 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java @@ -68,4 +68,12 @@ public interface IotThinkModelFunctionService { * @param productId 产品编号 */ void createSuperTableDataModel(Long productId); + + /** + * 获得产品物模型列表 + * + * @param productKey 产品 Key + * @return 产品物模型列表 + */ + List getThinkModelFunctionListByProductKey(String productKey); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index dd7a51786..25cfe7b46 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -199,6 +199,11 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe dbStructureDataService.createSuperTableDataModel(product, functionList); } + @Override + public List getThinkModelFunctionListByProductKey(String productKey) { + return thinkModelFunctionMapper.selectListByProductKey(productKey); + } + /** * 创建默认的事件和服务 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml index d3f1088a1..9d5cf2a43 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml @@ -110,30 +110,27 @@ + - create table - if not exists #{dataBaseName}.#{tableName} - using #{dataBaseName}.#{superTableName} - tags - + CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} + USING ${dataBaseName}.${superTableName} + + ${item.fieldName} + + TAGS + #{item.fieldValue} + - insert into #{dataBaseName}.#{tableName} + INSERT INTO ${dataBaseName}.${tableName} - #{item.fieldName} + ${item.fieldName} - using #{dataBaseName}.#{superTableName} - tags - - #{item.fieldValue} - - values + VALUES #{item.fieldValue} From 624f5283b3ec89295f3562a068bd009881b1c487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 3 Nov 2024 00:16:46 +0800 Subject: [PATCH 008/228] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91=20=E8=AE=BE=E5=A4=87=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E5=92=8C=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/IotProductFunctionTypeEnum.java | 2 +- .../admin/device/IotDeviceController.java | 8 +- .../admin/device/IotDeviceDataController.java | 38 +++++ .../vo/{ => device}/IotDevicePageReqVO.java | 2 +- .../vo/{ => device}/IotDeviceRespVO.java | 2 +- .../vo/{ => device}/IotDeviceSaveReqVO.java | 2 +- .../IotDeviceStatusUpdateReqVO.java | 2 +- .../vo/deviceData/IotDeviceDataReqVO.java | 21 +++ .../vo/deviceData/IotDeviceDataRespVO.java | 42 ++++++ .../convert/device/IotDeviceDataConvert.java | 46 ++++++ .../dataobject/device/IotDeviceDataDO.java | 71 +++++++++ .../iot/dal/mysql/device/IotDeviceMapper.java | 2 +- .../iot/dal/redis/RedisKeyConstants.java | 20 +++ .../redis/deviceData/DeviceDataRedisDAO.java | 43 ++++++ .../service/device/IotDeviceDataService.java | 17 ++- .../device/IotDeviceDataServiceImpl.java | 57 ++++++- .../iot/service/device/IotDeviceService.java | 4 +- .../service/device/IotDeviceServiceImpl.java | 6 +- .../IotDbStructureDataServiceImpl.java | 106 ++++++------- .../IotThingModelMessageServiceImpl.java | 140 ++++++++++++++---- 20 files changed, 523 insertions(+), 108 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/{ => device}/IotDevicePageReqVO.java (97%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/{ => device}/IotDeviceRespVO.java (97%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/{ => device}/IotDeviceSaveReqVO.java (89%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/{ => device}/IotDeviceStatusUpdateReqVO.java (91%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java index b99d2b093..c8a03a4d3 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java @@ -30,7 +30,7 @@ public enum IotProductFunctionTypeEnum implements IntArrayValuable { */ private final String description; - public static IotProductFunctionTypeEnum valueOf(Integer type) { + public static IotProductFunctionTypeEnum valueOfType(Integer type) { for (IotProductFunctionTypeEnum value : values()) { if (value.getType().equals(type)) { return value; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 6d75f1cdd..ba68e0232 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import io.swagger.v3.oas.annotations.Operation; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java new file mode 100644 index 000000000..93b368bd8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 设备数据") +@RestController +@RequestMapping("/iot/device/data") +@Validated +public class IotDeviceDataController { + + @Resource + private IotDeviceDataService deviceDataService; + + @GetMapping("/latest-data") + @Operation(summary = "获取设备属性最新数据") + public CommonResult> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) { + List list = deviceDataService.getDevicePropertiesLatestData(deviceDataReqVO); + return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java index 1c29f9f81..90ded8089 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java index 0b2cf25f5..fd2fbaa68 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java index 620e5310f..85fde9d3d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceStatusUpdateReqVO.java similarity index 91% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceStatusUpdateReqVO.java index a91a58690..daa1efde8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceStatusUpdateReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java new file mode 100644 index 000000000..b8a95f607 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 设备数据 Request VO") +@Data +public class IotDeviceDataReqVO { + + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + private Long deviceId; + + @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED) + private String identifier; + + @Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String name; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java new file mode 100644 index 000000000..256bf84fa --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 设备数据 Response VO") +@Data +public class IotDeviceDataRespVO { + + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + private Long deviceId; + + @Schema(description = "物模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") + private Long thinkModelFunctionId; + + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + private String productKey; + + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String deviceName; + + @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED) + private String identifier; + + @Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String name; + + @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED) + private String dataType; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + + @Schema(description = "最新值", requiredMode = Schema.RequiredMode.REQUIRED) + private String value; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java new file mode 100644 index 000000000..3bad54ba0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.iot.convert.device; + +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@Mapper +public interface IotDeviceDataConvert { + + IotDeviceDataConvert INSTANCE = Mappers.getMapper(IotDeviceDataConvert.class); + +// default List convert(Map deviceData, IotDeviceDO device){ +// List list = new ArrayList<>(); +// deviceData.forEach((identifier, value) -> { +//// ThingModelProperty property = ThingModelService.INSTANCE.getProperty(device.getProductId(), identifier); +//// if (Objects.isNull(property)) { +//// return; +//// } +// IotDeviceDataRespVO vo = new IotDeviceDataRespVO(); +// vo.setDeviceId(device.getId()); +// vo.setProductKey(device.getProductKey()); +// vo.setDeviceName(device.getDeviceName()); +// vo.setIdentifier(identifier); +//// vo.setName(property.getName()); +//// vo.setDataType(property.getDataType().getType()); +// vo.setUpdateTime(device.getUpdateTime()); +// vo.setValue(value.toString()); +// list.add(vo); +// }); +// return list; +// } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java new file mode 100644 index 000000000..5d8051172 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.device; + +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * IoT 设备数据 DO + * + * @author haohao + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotDeviceDataDO { + + /** + * 设备编号 + */ + private Long deviceId; + + /** + * 物模型编号 + */ + private Long thinkModelFunctionId; + + /** + * 产品标识 + */ + private String productKey; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 属性标识符 + */ + private String identifier; + + /** + * 属性名称 + */ + private String name; + + /** + * 数据类型 + */ + private String dataType; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 最新值 + */ + private String value; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 0e5552f83..3129f400c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.mysql.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import org.apache.ibatis.annotations.Mapper; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java new file mode 100644 index 000000000..25ea7a292 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.dal.redis; + + + +/** + * Iot Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 设备属性数据缓存 + *

+ * KEY 格式:device_property_data:{deviceId} + * VALUE 数据类型:String 设备属性数据 + */ + String DEVICE_PROPERTY_DATA = "device_property_data:%s_%s_%s"; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java new file mode 100644 index 000000000..b1b69f8dc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.iot.dal.redis.deviceData; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants.DEVICE_PROPERTY_DATA; + +/** + * {@link IotDeviceDataDO} 的 Redis DAO + */ +@Repository +public class DeviceDataRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public IotDeviceDataDO get(String productKey, String deviceName, String identifier) { + String redisKey = formatKey(productKey, deviceName, identifier); + return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), IotDeviceDataDO.class); + } + + public void set(IotDeviceDataDO deviceData) { + String redisKey = formatKey(deviceData.getProductKey(), deviceData.getDeviceName(), deviceData.getIdentifier()); + stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(deviceData)); + } + + public void delete(String productKey, String deviceName, String identifier) { + String redisKey = formatKey(productKey, deviceName, identifier); + stringRedisTemplate.delete(redisKey); + } + + private static String formatKey(String productKey, String deviceName, String identifier) { + return String.format(DEVICE_PROPERTY_DATA, productKey, deviceName, identifier); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index 4f3ef37d6..f67f42685 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -1,12 +1,11 @@ package cn.iocoder.yudao.module.iot.service.device; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import jakarta.validation.Valid; +import java.util.List; + /** * IoT 设备数据 Service 接口 * @@ -23,4 +22,12 @@ public interface IotDeviceDataService { * @param message 消息 */ void saveDeviceData(String productKey, String deviceName, String message); + + /** + * 获得设备属性最新数据 + * + * @param deviceId 设备编号 + * @return 设备属性最新数据 + */ + List getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceId); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 6b7aac21f..86ac630c6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -1,13 +1,23 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.hutool.json.JSONObject; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; +import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import jakarta.annotation.Resource; +import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; + @Slf4j @Service public class IotDeviceDataServiceImpl implements IotDeviceDataService { @@ -16,6 +26,11 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { private IotDeviceService deviceService; @Resource private IotThingModelMessageService thingModelMessageService; + @Resource + private IotThinkModelFunctionService thinkModelFunctionService; + + @Resource + private DeviceDataRedisDAO deviceDataRedisDAO; @Override public void saveDeviceData(String productKey, String deviceName, String message) { @@ -34,6 +49,46 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { .deviceName(deviceName) .deviceKey(device.getDeviceKey()) .build(); - thingModelMessageService.saveThingModelMessage(device,thingModelMessage); + thingModelMessageService.saveThingModelMessage(device, thingModelMessage); + } + + @Override + public List getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) { + List list = new ArrayList<>(); + // 1. 获取设备信息 + IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); + // 2. 获取设备属性最新数据 + List thinkModelFunctionList = thinkModelFunctionService.getThinkModelFunctionListByProductKey(device.getProductKey()); + thinkModelFunctionList = thinkModelFunctionList.stream() + .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType() + .equals(function.getType())).toList(); + + // 3. 过滤标识符和属性名称 + if (deviceDataReqVO.getIdentifier() != null) { + thinkModelFunctionList = thinkModelFunctionList.stream() + .filter(function -> function.getIdentifier().toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())) + .toList(); + } + if (deviceDataReqVO.getName() != null) { + thinkModelFunctionList = thinkModelFunctionList.stream() + .filter(function -> function.getName().toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())) + .toList(); + } + // 4. 获取设备属性最新数据 + thinkModelFunctionList.forEach(function -> { + IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), function.getIdentifier()); + if (deviceData == null) { + deviceData = new IotDeviceDataDO(); + deviceData.setProductKey(device.getProductKey()); + deviceData.setDeviceName(device.getDeviceName()); + deviceData.setIdentifier(function.getIdentifier()); + deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); + deviceData.setThinkModelFunctionId(function.getId()); + deviceData.setName(function.getName()); + deviceData.setDataType(function.getProperty().getDataType().getType()); + } + list.add(deviceData); + }); + return list; } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index c967a957e..ed4c6a60c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import jakarta.validation.*; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index f3243900e..60743f671 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -5,9 +5,9 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java index b7de8882a..947178102 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java @@ -1,12 +1,12 @@ package cn.iocoder.yudao.module.iot.service.tdengine; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdRestApi; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import jakarta.annotation.Resource; @@ -14,10 +14,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; @Service @@ -27,9 +24,6 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService @Resource private IotTdEngineService iotTdEngineService; - @Resource - private TdRestApi tdRestApi; - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") private String url; @@ -37,39 +31,25 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { // 1. 解析物模型,获得字段列表 List schemaFields = new ArrayList<>(); - schemaFields.add(TdFieldDO.builder(). - fieldName("time"). - dataType("TIMESTAMP"). - build()); + schemaFields.add(TdFieldDO.builder() + .fieldName("time") + .dataType("TIMESTAMP") + .build()); schemaFields.addAll(FieldParser.parse(thingModel)); // 3. 设置超级表的标签 - List tagsFields = new ArrayList<>(); - tagsFields.add(TdFieldDO.builder(). - fieldName("product_key"). - dataType("NCHAR"). - dataLength(64). - build()); - tagsFields.add(TdFieldDO.builder(). - fieldName("device_key"). - dataType("NCHAR"). - dataLength(64). - build()); - tagsFields.add(TdFieldDO.builder(). - fieldName("device_name"). - dataType("NCHAR"). - dataLength(64). - build()); - tagsFields.add(TdFieldDO.builder(). - fieldName("device_type"). - dataType("INT"). - build()); + List tagsFields = Arrays.asList( + TdFieldDO.builder().fieldName("product_key").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("device_name").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("device_type").dataType("INT").build() + ); // 4. 获取超级表的名称 String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); // 5. 创建超级表 - String dataBaseName = url.substring(url.lastIndexOf("/") + 1); + String dataBaseName = getDatabaseName(); iotTdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); } @@ -81,7 +61,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService List newFields = FieldParser.parse(thingModel); updateTableFields(tbName, oldFields, newFields); - } catch (Throwable e) { + } catch (Exception e) { log.error("更新物模型超级表失败", e); } } @@ -90,14 +70,15 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService private List getTableFields(String tableName) { List fields = new ArrayList<>(); // 获取超级表的描述信息 - List> maps = iotTdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), tableName); + List> maps = iotTdEngineService.describeSuperTable(getDatabaseName(), tableName); if (maps != null) { - // 过滤掉 note 字段为 TAG 的记录 - maps = maps.stream().filter(map -> !"TAG".equals(map.get("note"))).toList(); - // 过滤掉 time 字段 - maps = maps.stream().filter(map -> !"time".equals(map.get("field"))).toList(); + // 过滤掉 note 字段为 TAG 的记录和 time 字段 + List> filteredMaps = maps.stream() + .filter(map -> !"TAG".equals(map.get("note"))) + .filter(map -> !"time".equals(map.get("field"))) + .toList(); // 解析字段信息 - fields = FieldParser.parse(maps.stream() + fields = FieldParser.parse(filteredMaps.stream() .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) .collect(Collectors.toList())); } @@ -113,7 +94,7 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService // 获取删除字段 List dropFields = getDropFields(oldFields, newFields); - String dataBaseName = url.substring(url.lastIndexOf("/") + 1); + String dataBaseName = getDatabaseName(); // 添加新增字段 if (CollUtil.isNotEmpty(addFields)) { iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, addFields); @@ -131,25 +112,37 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService // 获取新增字段 private List getAddFields(List oldFields, List newFields) { + Set oldFieldNames = oldFields.stream() + .map(TdFieldDO::getFieldName) + .collect(Collectors.toSet()); return newFields.stream() - .filter(f -> oldFields.stream().noneMatch(old -> old.getFieldName().equals(f.getFieldName()))) + .filter(f -> !oldFieldNames.contains(f.getFieldName())) .collect(Collectors.toList()); } // 获取修改字段 private List getModifyFields(List oldFields, List newFields) { + Map oldFieldMap = oldFields.stream() + .collect(Collectors.toMap(TdFieldDO::getFieldName, f -> f)); + return newFields.stream() - .filter(f -> oldFields.stream().anyMatch(old -> - old.getFieldName().equals(f.getFieldName()) && - (!old.getDataType().equals(f.getDataType()) || !Objects.equals(old.getDataLength(), f.getDataLength())))) + .filter(f -> { + TdFieldDO oldField = oldFieldMap.get(f.getFieldName()); + return oldField != null && + (!oldField.getDataType().equals(f.getDataType()) || + !Objects.equals(oldField.getDataLength(), f.getDataLength())); + }) .collect(Collectors.toList()); } // 获取删除字段 private List getDropFields(List oldFields, List newFields) { + Set newFieldNames = newFields.stream() + .map(TdFieldDO::getFieldName) + .collect(Collectors.toSet()); return oldFields.stream() - .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName()) && - newFields.stream().noneMatch(n -> n.getFieldName().equals(f.getFieldName()))) + .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName())) + .filter(f -> !newFieldNames.contains(f.getFieldName())) .collect(Collectors.toList()); } @@ -157,13 +150,13 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService public void createSuperTableDataModel(IotProductDO product, List functionList) { ThingModelRespVO thingModel = buildThingModel(product, functionList); - if (thingModel.getModel().getProperties().isEmpty()) { + if (thingModel.getModel() == null || CollUtil.isEmpty(thingModel.getModel().getProperties())) { log.warn("物模型属性列表为空,不创建超级表"); return; } String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); - String dataBaseName = url.substring(url.lastIndexOf("/") + 1); + String dataBaseName = getDatabaseName(); Integer tableExists = iotTdEngineService.checkSuperTableExists(dataBaseName, superTableName); if (tableExists != null && tableExists > 0) { @@ -180,7 +173,8 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService ThingModelRespVO.Model model = new ThingModelRespVO.Model(); List properties = functionList.stream() - .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals(IotProductFunctionTypeEnum.valueOf(function.getType()))) + .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals( + IotProductFunctionTypeEnum.valueOfType(function.getType()))) .map(this::buildThingModelProperty) .collect(Collectors.toList()); @@ -191,14 +185,15 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService } private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) { - ThingModelProperty property = new ThingModelProperty(); - property.setIdentifier(function.getIdentifier()); - property.setName(function.getName()); - property.setDescription(function.getDescription()); + ThingModelProperty property = BeanUtil.copyProperties(function, ThingModelProperty.class); property.setDataType(function.getProperty().getDataType()); return property; } + private String getDatabaseName() { + return url.substring(url.lastIndexOf("/") + 1); + } + static String getProductPropertySTableName(Integer deviceType, String productKey) { return switch (deviceType) { case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); @@ -207,7 +202,4 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService }; } - static String getDevicePropertyTableName(String deviceType, String productKey, String deviceKey) { - return String.format("%s_%s_%s", deviceType, productKey, deviceKey).toLowerCase(); - } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index ae7fa51ee..9bad7613e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -1,13 +1,16 @@ package cn.iocoder.yudao.module.iot.service.tdengine; +import cn.hutool.core.date.DateUtil; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; @@ -17,9 +20,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; @Slf4j @@ -36,11 +37,14 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Resource private IotTdEngineService iotTdEngineService; + @Resource + private DeviceDataRedisDAO deviceDataRedisDAO; + @Override @TenantIgnore public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) { // 判断设备状态,如果为未激活状态,创建数据表 - if (device.getStatus().equals(0)) { + if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { // 创建设备数据表 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); // 更新设备状态 @@ -50,53 +54,99 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ iotDeviceService.updateDeviceStatus(updateReqVO); } - // 1. 获取设备属性 + // 获取设备属性 Map params = thingModelMessage.dataToMap(); - // 2. 物模型校验,过滤非物模型属性 - List thinkModelFunctionListByProductKey = iotThinkModelFunctionService.getThinkModelFunctionListByProductKey(thingModelMessage.getProductKey()); + // 物模型校验,过滤非物模型属性 + List functionList = iotThinkModelFunctionService + .getThinkModelFunctionListByProductKey(thingModelMessage.getProductKey()) + .stream() + .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType().equals(function.getType())) + .toList(); - // 2.1 筛选是属性 IotProductFunctionTypeEnum - thinkModelFunctionListByProductKey.removeIf(iotThinkModelFunctionDO -> !iotThinkModelFunctionDO.getType().equals(IotProductFunctionTypeEnum.PROPERTY.getType())); - if (thinkModelFunctionListByProductKey.isEmpty()) { + if (functionList.isEmpty()) { return; } - // 2.2 获取属性名称 - Map thingModelProperties = thinkModelFunctionListByProductKey.stream().collect(Collectors.toMap(IotThinkModelFunctionDO::getIdentifier, IotThinkModelFunctionDO::getName)); - // 4. 保存属性记录 + // 获取属性标识符集合 + Set propertyIdentifiers = functionList.stream() + .map(IotThinkModelFunctionDO::getIdentifier) + .collect(Collectors.toSet()); + + Map functionMap = functionList.stream() + .collect(Collectors.toMap(IotThinkModelFunctionDO::getIdentifier, function -> function)); + + // 过滤并收集有效的属性字段 List schemaFieldValues = new ArrayList<>(); - - // 1. 设置字段名 schemaFieldValues.add(new TdFieldDO("time", thingModelMessage.getTime())); - - // 2. 遍历新属性 params.forEach((key, val) -> { - if (thingModelProperties.containsKey(key)) { + if (propertyIdentifiers.contains(key)) { schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val)); + // 缓存设备属性 + setDeviceDataCache(device, functionMap.get(key), val, thingModelMessage.getTime()); } }); + if (schemaFieldValues.size() == 1) { + return; + } - // 3. 保存设备属性 + // 构建并保存设备属性 TableDO tableData = new TableDO(); - tableData.setDataBaseName(url.substring(url.lastIndexOf("/") + 1)); + tableData.setDataBaseName(getDatabaseName()); tableData.setSuperTableName(getProductPropertySTableName(device.getDeviceType(), device.getProductKey())); - tableData.setTableName("device_" + device.getProductKey().toLowerCase() + "_" + device.getDeviceName().toLowerCase()); + tableData.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); tableData.setSchemaFieldValues(schemaFieldValues); - // 4. 保存数据 iotTdEngineService.insertData(tableData); } + /** + * 缓存设备属性 + * + * @param device 设备信息 + * @param iotThinkModelFunctionDO 物模型属性 + * @param val 属性值 + * @param time 时间 + */ + private void setDeviceDataCache(IotDeviceDO device, IotThinkModelFunctionDO iotThinkModelFunctionDO, Object val, Long time) { + IotDeviceDataDO deviceData = IotDeviceDataDO.builder() + .productKey(device.getProductKey()) + .deviceName(device.getDeviceName()) + .identifier(iotThinkModelFunctionDO.getIdentifier()) + .value(val != null ? val.toString() : null) + .updateTime(DateUtil.toLocalDateTime(new Date(time))) + .deviceId(device.getId()) + .thinkModelFunctionId(iotThinkModelFunctionDO.getId()) + .name(iotThinkModelFunctionDO.getName()) + .dataType(iotThinkModelFunctionDO.getProperty().getDataType().getType()) + .build(); + deviceDataRedisDAO.set(deviceData); + } + + /** + * 创建设备数据表 + * + * @param deviceType 设备类型 + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @param deviceKey 设备 Key + */ private void createDeviceTable(Integer deviceType, String productKey, String deviceName, String deviceKey) { + String superTableName = getProductPropertySTableName(deviceType, productKey); + String dataBaseName = getDatabaseName(); + + List> maps = iotTdEngineService.describeSuperTable(dataBaseName, superTableName); List tagsFieldValues = new ArrayList<>(); - String SuperTableName = getProductPropertySTableName(deviceType, productKey); - List> maps = iotTdEngineService.describeSuperTable(url.substring(url.lastIndexOf("/") + 1), SuperTableName); + if (maps != null) { - List> taggedNotesList = maps.stream().filter(map -> "TAG".equals(map.get("note"))).toList(); + List> taggedNotesList = maps.stream() + .filter(map -> "TAG".equals(map.get("note"))) + .toList(); + tagsFieldValues = FieldParser.parse(taggedNotesList.stream() .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) .collect(Collectors.toList())); + for (TdFieldDO tagsFieldValue : tagsFieldValues) { switch (tagsFieldValue.getFieldName()) { case "product_key" -> tagsFieldValue.setFieldValue(productKey); @@ -107,21 +157,49 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ } } - // 1. 创建设备数据表 - String tableName = "device_" + productKey.toLowerCase() + "_" + deviceName.toLowerCase(); + // 创建设备数据表 + String tableName = getDeviceTableName(productKey, deviceName); TableDO tableDto = new TableDO(); - tableDto.setDataBaseName(url.substring(url.lastIndexOf("/") + 1)); - tableDto.setSuperTableName(SuperTableName); + tableDto.setDataBaseName(dataBaseName); + tableDto.setSuperTableName(superTableName); tableDto.setTableName(tableName); tableDto.setTagsFieldValues(tagsFieldValues); + iotTdEngineService.createTable(tableDto); } - static String getProductPropertySTableName(Integer deviceType, String productKey) { + /** + * 获取数据库名称 + * + * @return 数据库名称 + */ + private String getDatabaseName() { + return url.substring(url.lastIndexOf("/") + 1); + } + + /** + * 获取产品属性表名 + * + * @param deviceType 设备类型 + * @param productKey 产品 Key + * @return 产品属性表名 + */ + private static String getProductPropertySTableName(Integer deviceType, String productKey) { return switch (deviceType) { case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); case 2 -> String.format("gateway_%s", productKey).toLowerCase(); default -> String.format("device_%s", productKey).toLowerCase(); }; } + + /** + * 获取设备表名 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 设备表名 + */ + private static String getDeviceTableName(String productKey, String deviceName) { + return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase()); + } } \ No newline at end of file From d7b8cf547f4d96b49c3371fbbf4535a1c4dfab3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Tue, 5 Nov 2024 23:26:34 +0800 Subject: [PATCH 009/228] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91=20=E8=AE=BE=E5=A4=87=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/domain/visual/SelectVisualDto.java | 29 +++++++------ .../admin/device/IotDeviceDataController.java | 10 +++++ .../vo/deviceData/IotDeviceDataReqVO.java | 12 +++++- .../vo/deviceData/IotTimeDataRespVO.java} | 8 ++-- .../iot/dal/tdengine/TdEngineMapper.java | 7 ++- .../service/device/IotDeviceDataService.java | 10 +++++ .../device/IotDeviceDataServiceImpl.java | 43 +++++++++++++++++++ .../mapper/tdengine/TdEngineMapper.xml | 19 +++++--- 8 files changed, 112 insertions(+), 26 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{dal/dataobject/tdengine/TimeData.java => controller/admin/device/vo/deviceData/IotTimeDataRespVO.java} (67%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java index 1444da972..071c76303 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java @@ -4,24 +4,24 @@ import lombok.Data; import java.util.Map; -/** - * @ClassDescription: 查询可视化所需入参对象 - * @ClassName: SelectDto - * @Author: andyz - * @Date: 2022-07-29 14:12:26 - * @Version 1.0 - */ @Data public class SelectVisualDto { -// @NotBlank(message = "invalid operation: tableName can not be empty") + /** + * 数据库名称 + */ private String dataBaseName; -// @NotBlank(message = "invalid operation: tableName can not be empty") + /** + * 表名 + */ private String tableName; -// @NotBlank(message = "invalid operation: fieldName can not be empty") //属性 + /** + * 属性 + */ private String fieldName; + /** * 查询类型,0历史数据,1实时数据,2聚合数据 */ @@ -39,10 +39,15 @@ public class SelectVisualDto { * 比如1s,1m,1h,1d代表1秒,1分钟,1小时,1天 */ private String interval; - // @NotNull(message = "invalid operation: startTime can not be null") + + /** + * 开始时间 + */ private Long startTime; - // @NotNull(message = "invalid operation: endTime can not be null") + /** + * 结束时间 + */ private Long endTime; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 93b368bd8..e710d0ea8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotTimeDataRespVO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -16,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -35,4 +38,11 @@ public class IotDeviceDataController { return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); } + @GetMapping("/history-data") + @Operation(summary = "获取设备属性历史数据") + public CommonResult> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO) { + PageResult> list = deviceDataService.getDevicePropertiesHistoryData(deviceDataReqVO); + return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java index b8a95f607..5f87a1cb8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java @@ -1,13 +1,18 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; +import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Size; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + @Schema(description = "管理后台 - IoT 设备数据 Request VO") @Data -public class IotDeviceDataReqVO { +public class IotDeviceDataReqVO extends PageParam { @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") private Long deviceId; @@ -18,4 +23,9 @@ public class IotDeviceDataReqVO { @Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED) private String name; + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Size(min = 2, max = 2, message = "请选择时间范围") + private LocalDateTime[] times; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotTimeDataRespVO.java similarity index 67% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotTimeDataRespVO.java index f7e251ea8..1bf085c54 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TimeData.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotTimeDataRespVO.java @@ -1,16 +1,14 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -/** - * 统计的时间数据 - */ + @Data @NoArgsConstructor @AllArgsConstructor -public class TimeData { +public class IotTimeDataRespVO { /** * 时间 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java index 94db527c2..c126946f1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java @@ -88,6 +88,7 @@ public interface TdEngineMapper { /** * 创建表 - 创建超级表的子表 + * * @param tableDO 表信息 */ @InterceptorIgnore(tenantLine = "true") @@ -114,6 +115,7 @@ public interface TdEngineMapper { Map getLastData(SelectDto selectDto); + @InterceptorIgnore(tenantLine = "true") List> getHistoryData(SelectVisualDto selectVisualDto); List> getRealtimeData(SelectVisualDto selectVisualDto); @@ -122,5 +124,6 @@ public interface TdEngineMapper { List> getLastDataByTags(TagsSelectDao tagsSelectDao); - -} + @InterceptorIgnore(tenantLine = "true") + Long getHistoryCount(SelectVisualDto selectVisualDto); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index f67f42685..96181fd26 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import jakarta.validation.Valid; import java.util.List; +import java.util.Map; /** * IoT 设备数据 Service 接口 @@ -30,4 +32,12 @@ public interface IotDeviceDataService { * @return 设备属性最新数据 */ List getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceId); + + /** + * 获得设备属性历史数据 + * + * @param deviceDataReqVO 设备属性历史数据 Request VO + * @return 设备属性历史数据 + */ + PageResult> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 86ac630c6..1b44bd5d0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -1,27 +1,38 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.hutool.core.date.DateUtil; import cn.hutool.json.JSONObject; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; +import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.time.ZoneId; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Slf4j @Service public class IotDeviceDataServiceImpl implements IotDeviceDataService { + @Value("${spring.datasource.dynamic.datasource.tdengine.url}") + private String url; + @Resource private IotDeviceService deviceService; @Resource @@ -32,6 +43,9 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { @Resource private DeviceDataRedisDAO deviceDataRedisDAO; + @Resource + private TdEngineMapper tdEngineMapper; + @Override public void saveDeviceData(String productKey, String deviceName, String message) { // 1. 根据产品 key 和设备名称,获得设备信息 @@ -91,4 +105,33 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { }); return list; } + + @Override + public PageResult> getDevicePropertiesHistoryData(IotDeviceDataReqVO deviceDataReqVO) { + PageResult> pageResult = new PageResult<>(); + // 1. 获取设备信息 + IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); + // 2. 获取设备属性历史数据 + SelectVisualDto selectVisualDto = new SelectVisualDto(); + selectVisualDto.setDataBaseName(getDatabaseName()); + selectVisualDto.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); + selectVisualDto.setFieldName(deviceDataReqVO.getIdentifier()); + selectVisualDto.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); + selectVisualDto.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); + Map params = new HashMap<>(); + params.put("rows", deviceDataReqVO.getPageSize()); + params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); + selectVisualDto.setParams(params); + pageResult.setList(tdEngineMapper.getHistoryData(selectVisualDto)); + pageResult.setTotal(tdEngineMapper.getHistoryCount(selectVisualDto)); + return pageResult; + } + + private String getDatabaseName() { + return url.substring(url.lastIndexOf("/") + 1); + } + + private static String getDeviceTableName(String productKey, String deviceName) { + return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase()); + } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml index 9d5cf2a43..4e127e44b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml @@ -292,17 +292,18 @@ + From e3dcea9cb3792bfebb489c3ccfb568bcec6bf7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 8 Nov 2024 23:07:37 +0800 Subject: [PATCH 010/228] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91=20=E4=BC=98=E5=8C=96=20tdengine=20=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=95=B0=E6=8D=AE=E5=BA=93=E7=9B=B8=E5=85=B3=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/domain/BaseEntity.java | 18 - .../iot/domain/DeviceDataExportExcelDto.java | 35 -- .../yudao/module/iot/domain/DeviceDataVo.java | 19 - .../yudao/module/iot/domain/Fields.java | 65 ---- .../yudao/module/iot/domain/FieldsVo.java | 31 -- .../module/iot/domain/IotSequential.java | 71 ---- .../module/iot/domain/MessageCountVo.java | 25 -- .../iot/domain/ProductSuperTableModel.java | 29 -- .../yudao/module/iot/domain/SelectDto.java | 30 -- .../module/iot/domain/SuperTableDto.java | 31 -- .../yudao/module/iot/domain/TableDto.java | 26 -- .../module/iot/domain/TagsSelectDao.java | 25 -- .../yudao/module/iot/domain/Weather.java | 73 ---- .../iot/dal/dataobject/tdengine/SelectDO.java | 51 +++ .../dataobject/tdengine/SelectVisualDO.java} | 4 +- .../iot/dal/dataobject/tdengine/TableDO.java | 27 -- .../dal/dataobject/tdengine/TableData.java | 44 --- .../dal/dataobject/tdengine/TagsSelectDO.java | 36 ++ .../dal/dataobject/tdengine/TdFieldDO.java | 10 +- .../dal/dataobject/tdengine/TdTableDO.java | 65 ++++ .../tdengine/TdEngineDataWriterMapper.java | 25 ++ .../dal/tdengine/TdEngineDatabaseMapper.java | 23 ++ .../iot/dal/tdengine/TdEngineMapper.java | 129 ------- .../iot/dal/tdengine/TdEngineQueryMapper.java | 85 +++++ .../tdengine/TdEngineSuperTableMapper.java | 111 ++++++ .../iot/dal/tdengine/TdEngineTableMapper.java | 41 +++ .../device/IotDeviceDataServiceImpl.java | 27 +- ...Service.java => IotSuperTableService.java} | 15 +- ...mpl.java => IotSuperTableServiceImpl.java} | 309 ++++++++++------- .../service/tdengine/IotTdEngineService.java | 142 -------- .../tdengine/IotTdEngineServiceImpl.java | 107 ------ .../tdengine/IotThingModelMessageService.java | 4 +- .../IotThingModelMessageServiceImpl.java | 38 +- .../tdengine/TdEngineDataWriterService.java | 19 + .../TdEngineDataWriterServiceImpl.java | 21 ++ .../tdengine/TdEngineDatabaseService.java | 14 + .../tdengine/TdEngineDatabaseServiceImpl.java | 22 ++ .../tdengine/TdEngineQueryService.java | 28 ++ .../tdengine/TdEngineQueryServiceImpl.java | 26 ++ .../tdengine/TdEngineSuperTableService.java | 123 +++++++ .../TdEngineSuperTableServiceImpl.java | 90 +++++ .../tdengine/TdEngineTableService.java | 21 ++ .../tdengine/TdEngineTableServiceImpl.java | 23 ++ .../IotThinkModelFunctionService.java | 2 +- .../IotThinkModelFunctionServiceImpl.java | 4 +- .../tdengine/TdEngineDataWriterMapper.xml | 22 ++ .../tdengine/TdEngineDatabaseMapper.xml | 13 + .../mapper/tdengine/TdEngineMapper.xml | 327 ------------------ .../mapper/tdengine/TdEngineQueryMapper.xml | 73 ++++ .../tdengine/TdEngineSuperTableMapper.xml | 72 ++++ .../mapper/tdengine/TdEngineTableMapper.xml | 33 ++ 51 files changed, 1262 insertions(+), 1442 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataExportExcelDto.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataVo.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/IotSequential.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/MessageCountVo.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Weather.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java rename yudao-module-iot/{yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java => yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java} (90%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableDO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDataWriterMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineSuperTableMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineTableMapper.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/{IotDbStructureDataService.java => IotSuperTableService.java} (50%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/{IotDbStructureDataServiceImpl.java => IotSuperTableServiceImpl.java} (55%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java deleted file mode 100644 index 496be9a24..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/BaseEntity.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.Data; - -@Data -public class BaseEntity { - private static final long serialVersionUID = 1L; - - /** - * 数据库名称 - */ - private String dataBaseName; - - /** - * 超级表名称 - */ - private String superTableName; -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataExportExcelDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataExportExcelDto.java deleted file mode 100644 index cedb4d119..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataExportExcelDto.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.Data; - -/** - * 设备数据导出 excel DTO - */ -@Data -public class DeviceDataExportExcelDto { - - /** - * 设备标识 - */ - private String deviceKey; - - /** - * 导出形式 1 单个参数导出 2 全部参数导出 - */ - private String exportType; - - /** - * 导出开始时间 - */ - private String exportBeginTime; - - /** - * 导出结束时间 - */ - private String exportEndTime; - - /** - * 导出参数,空则导出全部 - */ - private String exportParameter; -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataVo.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataVo.java deleted file mode 100644 index b9f6fc412..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/DeviceDataVo.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.Data; - -/** - * @ClassDescription: 查询可视化所需入参对象 - * @ClassName: SelectDto - * @Author: andyz - * @Date: 2022-07-29 14:12:26 - * @Version 1.0 - */ -@Data -public class DeviceDataVo { - - - private String deviceId; - - private Long lastTime; -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java deleted file mode 100644 index ec0a7f148..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Fields.java +++ /dev/null @@ -1,65 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.Data; - -@Data -public class Fields { - private static final long serialVersionUID = 1L; - - /** - * 字段名称 - */ - private String fieldName; - - /** - * 字段值 - */ - private Object fieldValue; - - /** - * 字段数据类型 - */ -// private DataTypeEnum dataType; - - /** - * 字段字节大小 - */ - private Integer size; - - public Fields() { - } - - public Fields(String fieldName, String dataType, Integer size) { -// this.fieldName = fieldName; -// //根据规则匹配字段数据类型 -// switch (dataType.toLowerCase()) { -// case ("json"): -// this.dataType = DataTypeEnum.JSON; -// this.size = size; -// break; -// case ("string"): -// this.dataType = DataTypeEnum.NCHAR; -// this.size = size; -// break; -// case ("binary"): -// this.dataType = DataTypeEnum.BINARY; -// this.size = size; -// break; -// case ("int"): -// this.dataType = DataTypeEnum.INT; -// break; -// case ("bool"): -// this.dataType = DataTypeEnum.BOOL; -// break; -// case ("decimal"): -// this.dataType = DataTypeEnum.DOUBLE; -// break; -// case ("timestamp"): -// if ("eventTime".equals(fieldName)) { -// this.fieldName = "eventTime"; -// } -// this.dataType = DataTypeEnum.TIMESTAMP; -// break; -// } - } -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java deleted file mode 100644 index fc86a8f7e..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/FieldsVo.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.Builder; -import lombok.Data; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - -/** - * 字段信息 VO - */ -@Data -@Builder -public class FieldsVo { - - /** - * 字段名称 - */ - private String fieldName; - - /** - * 字段数据类型 - */ - private String dataType; - - /** - * 字段字节大小 - */ - private Integer size; -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/IotSequential.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/IotSequential.java deleted file mode 100644 index 349d6d137..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/IotSequential.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import com.fasterxml.jackson.annotation.JsonFormat; - -import java.sql.Timestamp; - -public class IotSequential extends BaseEntity { - private static final long serialVersionUID = 1L; - - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") - private Timestamp statetime; - - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") - private Timestamp endtime; - - private String deviceid; - - private String eventtime; - - private String serviceid; - - private String devices; - - public String getDeviceid() { - return deviceid; - } - - public void setDeviceid(String deviceid) { - this.deviceid = deviceid; - } - - public String getEventtime() { - return eventtime; - } - - public void setEventtime(String eventtime) { - this.eventtime = eventtime; - } - - public String getServiceid() { - return serviceid; - } - - public void setServiceid(String serviceid) { - this.serviceid = serviceid; - } - - public String getDevices() { - return devices; - } - - public void setDevices(String devices) { - this.devices = devices; - } - - public Timestamp getStatetime() { - return statetime; - } - - public void setStatetime(Timestamp statetime) { - this.statetime = statetime; - } - - public Timestamp getEndtime() { - return endtime; - } - - public void setEndtime(Timestamp endtime) { - this.endtime = endtime; - } -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/MessageCountVo.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/MessageCountVo.java deleted file mode 100644 index e9e93cac0..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/MessageCountVo.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * 统计的时间数据 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class MessageCountVo { - - /** - * 时间 - */ - private String time; - - /** - * 数据值 - */ - private Object data; - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java deleted file mode 100644 index c5989811f..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/ProductSuperTableModel.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import com.fasterxml.jackson.annotation.JsonFormat; -import lombok.Data; - -import java.sql.Timestamp; -import java.util.HashMap; -import java.util.Optional; - -@Data -public class ProductSuperTableModel { - private static final long serialVersionUID = 1L; - - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+8") - private Timestamp ts; - - private String superTableName; - - /** - * columnsName,columnsProperty - */ - private HashMap columns; - - /** - * tagsName,tagsProperty - */ - private HashMap tags; - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java deleted file mode 100644 index c20e5ab5e..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SelectDto.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.Data; - -import java.util.Set; - -@Data -public class SelectDto { - - // @NotBlank(message = "invalid operation: dataBaseName can not be empty") - private String dataBaseName; - -// @NotBlank(message = "invalid operation: tableName can not be empty") - private String tableName; - - // @NotBlank(message = "invalid operation: fieldName can not be empty") - private String fieldName; - - // @NotNull(message = "invalid operation: startTime can not be null") - private Long startTime; - - // @NotNull(message = "invalid operation: endTime can not be null") - private Long endTime; - - private String type; - - private Set orgIds; - - private String deviceId; -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java deleted file mode 100644 index a15f135cf..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/SuperTableDto.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.Data; - -import java.util.List; - -@Data -public class SuperTableDto extends BaseEntity { - - /** - * 超级表的表结构(业务相关) - * 第一个字段的数据类型必须为timestamp - * 字符相关数据类型必须指定大小 - * 字段名称和字段数据类型不能为空 - */ -// @NotEmpty(message = "invalid operation: schemaFields can not be empty") - private List schemaFields; - - /** - * 超级表的标签字段,可以作为子表在超级表里的标识 - * 字符相关数据类型必须指定大小 - * 字段名称和字段数据类型不能为空 - */ -// @NotEmpty(message = "invalid operation: tagsFields can not be empty") - private List tagsFields; - - /** - * 字段信息对象,超级表添加列时使用该属性 - */ - private Fields fields; -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java deleted file mode 100644 index 5ffe9f84e..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TableDto.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.Data; - -import java.util.List; - -@Data -public class TableDto extends BaseEntity { - - /** - * 超级表普通列字段的值 - * 值需要与创建超级表时普通列字段的数据类型对应上 - */ - private List schemaFieldValues; - - /** - * 超级表标签字段的值 - * 值需要与创建超级表时标签字段的数据类型对应上 - */ - private List tagsFieldValues; - - /** - * 表名称 - */ - private String tableName; -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java deleted file mode 100644 index 8833b0b50..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/TagsSelectDao.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import lombok.Data; - - -@Data -public class TagsSelectDao { - - // @NotBlank(message = "invalid operation: dataBaseName can not be empty") - private String dataBaseName; - - // @NotBlank(message = "invalid operation: stableName can not be empty") - private String stableName; - - // @NotBlank(message = "invalid operation: tagsName can not be empty") - private String tagsName; - - // @NotNull(message = "invalid operation: startTime can not be null") - private Long startTime; - - // @NotNull(message = "invalid operation: endTime can not be null") - private Long endTime; - - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Weather.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Weather.java deleted file mode 100644 index a4a1e983b..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/Weather.java +++ /dev/null @@ -1,73 +0,0 @@ -package cn.iocoder.yudao.module.iot.domain; - -import com.fasterxml.jackson.annotation.JsonFormat; - -import java.sql.Timestamp; - -public class Weather { - - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS" , timezone = "GMT+8") - private Timestamp ts; - private Float temperature; - private Float humidity; - private String location; - private String note; - private int groupId; - - public Weather() { - } - - public Weather(Timestamp ts, float temperature, float humidity) { - this.ts = ts; - this.temperature = temperature; - this.humidity = humidity; - } - - public Timestamp getTs() { - return ts; - } - - public void setTs(Timestamp ts) { - this.ts = ts; - } - - public Float getTemperature() { - return temperature; - } - - public void setTemperature(Float temperature) { - this.temperature = temperature; - } - - public Float getHumidity() { - return humidity; - } - - public void setHumidity(Float humidity) { - this.humidity = humidity; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - public int getGroupId() { - return groupId; - } - - public void setGroupId(int groupId) { - this.groupId = groupId; - } - - public String getNote() { - return note; - } - - public void setNote(String note) { - this.note = note; - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java new file mode 100644 index 000000000..503b26310 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.Data; + +import java.util.Set; +/** + * 查询DO + */ +@Data +public class SelectDO { + + /** + * 数据库名称 + */ + private String dataBaseName; + + /** + * 超级表名称 + */ + private String tableName; + + /** + * 查询字段 + */ + private String fieldName; + + /** + * 开始时间 + */ + private Long startTime; + + /** + * 结束时间 + */ + private Long endTime; + + /** + * 查询类型 + */ + private String type; + + /** + * 查询条件 + */ + private Set orgIds; + + /** + * 设备ID + */ + private String deviceId; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java similarity index 90% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java index 071c76303..d5faf45a9 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/domain/visual/SelectVisualDto.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.domain.visual; +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; import lombok.Data; import java.util.Map; @Data -public class SelectVisualDto { +public class SelectVisualDO { /** * 数据库名称 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableDO.java deleted file mode 100644 index 11751ff64..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableDO.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import cn.iocoder.yudao.module.iot.domain.BaseEntity; -import lombok.Data; - -import java.util.List; - -@Data -public class TableDO extends BaseEntity { - - /** - * 超级表普通列字段的值 - * 值需要与创建超级表时普通列字段的数据类型对应上 - */ - private List schemaFieldValues; - - /** - * 超级表标签字段的值 - * 值需要与创建超级表时标签字段的数据类型对应上 - */ - private List tagsFieldValues; - - /** - * 表名称 - */ - private String tableName; -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java deleted file mode 100644 index dfb3ed212..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableData.java +++ /dev/null @@ -1,44 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import lombok.Data; - -import java.util.List; - -/** - * TableData 类用于存储和操作 TDengine 表数据 - */ -@Data -public class TableData { - - /** - * 超级表普通列字段的名称 - */ - private List schemaFieldList; - - /** - * 超级表普通列字段的值 - * 值需要与创建超级表时普通列字段的数据类型对应上 - */ - private List schemaValueList; - - /** - * 超级表标签字段的名称 - */ - private List tagsFieldList; - - /** - * 超级表标签字段的值 - * 值需要与创建超级表时标签字段的数据类型对应上 - */ - private List tagsValueList; - - /** - * 表名称 - */ - private String tableName; - - /** - * 超级表名称 - */ - private String superTableName; -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java new file mode 100644 index 000000000..9fae91599 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.Data; + +/** + * tags查询DO + */ +@Data +public class TagsSelectDO { + + /** + * 数据库名称 + */ + private String dataBaseName; + + /** + * 超级表名称 + */ + private String stableName; + + /** + * tags名称 + */ + private String tagsName; + + /** + * tags值 + */ + private Long startTime; + + /** + * tags值 + */ + private Long endTime; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java index 765652748..2e1751509 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java @@ -19,11 +19,6 @@ public class TdFieldDO { */ private String fieldName; - /** - * 字段值 - */ - private Object fieldValue; - /** * 字段类型 */ @@ -34,6 +29,11 @@ public class TdFieldDO { */ private Integer dataLength = 0; + /** + * 字段值 + */ + private Object fieldValue; + public TdFieldDO(String fieldName, String dataType, Integer dataLength) { this.fieldName = fieldName; this.dataType = dataType; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java new file mode 100644 index 000000000..314c51de3 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * TD 引擎的数据库 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TdTableDO { + + /** + * 数据库名称 + */ + private String dataBaseName; + + /** + * 超级表名称 + */ + private String superTableName; + + /** + * 表名称 + */ + private String tableName; + + /** + * COLUMN 字段 + */ + private TdFieldDO column; + + /** + * TAG 字段 + */ + private TdFieldDO tag; + + /** + * COLUMN 字段 - 列表 + */ + private List columns; + + /** + * TAG 字段 - 列表 + */ + private List tags; + + public TdTableDO(String dataBaseName, String superTableName, List columns, List tags) { + this.dataBaseName = dataBaseName; + this.superTableName = superTableName; + this.columns = columns; + this.tags = tags; + } + + public TdTableDO(String dataBaseName, String superTableName) { + this.dataBaseName = dataBaseName; + this.superTableName = superTableName; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDataWriterMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDataWriterMapper.java new file mode 100644 index 000000000..51f4229a0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDataWriterMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; + +/** + * TD 引擎的数据写入 Mapper + */ +@Mapper +@DS("tdengine") +public interface TdEngineDataWriterMapper { + + /** + * 插入数据 - 指定列插入数据 + * + * @param table 数据 + * dataBaseName 数据库名 + * tableName 表名 + * columns 列 + */ + @InterceptorIgnore(tenantLine = "true") + void insertData(TdTableDO table); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java new file mode 100644 index 000000000..bc562ccca --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** + * TD 引擎的数据库 Mapper + */ +@Mapper +@DS("tdengine") +public interface TdEngineDatabaseMapper { + + /** + * 创建数据库 + * SQL:CREATE DATABASE [IF NOT EXISTS] db_name [database_options]; + * + * @param dataBaseName 数据库名称 + */ + @InterceptorIgnore(tenantLine = "true") + void createDatabase(@Param("dataBaseName") String dataBaseName); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java deleted file mode 100644 index c126946f1..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineMapper.java +++ /dev/null @@ -1,129 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.domain.FieldsVo; -import cn.iocoder.yudao.module.iot.domain.SelectDto; -import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; -import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; -import com.baomidou.dynamic.datasource.annotation.DS; -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.util.List; -import java.util.Map; - -@Mapper -@DS("tdengine") -public interface TdEngineMapper { - - /** - * 创建数据库 - * - * @param dataBaseName 数据库名称 - */ - @InterceptorIgnore(tenantLine = "true") - void createDatabase(@Param("dataBaseName") String dataBaseName); - - /** - * 创建超级表 - * - * @param schemaFields schema字段 - * @param tagsFields tags字段 - * @param dataBaseName 数据库名称 - * @param superTableName 超级表名称 - */ - @InterceptorIgnore(tenantLine = "true") - void createSuperTable(@Param("schemaFields") List schemaFields, - @Param("tagsFields") List tagsFields, - @Param("dataBaseName") String dataBaseName, - @Param("superTableName") String superTableName); - - /** - * 查看超级表 - 显示当前数据库下的所有超级表信息 - * SQL:SHOW STABLES [LIKE tb_name_wildcard]; - * - * @param dataBaseName 数据库名称 - * @param superTableName 超级表名称 - */ - @InterceptorIgnore(tenantLine = "true") - List> showSuperTables(@Param("dataBaseName") String dataBaseName, - @Param("superTableName") String superTableName); - - /** - * 查看超级表 - 获取超级表的结构信息 - * SQL:DESCRIBE [db_name.]stb_name; - *

- * * @param dataBaseName 数据库名称 - * * @param superTableName 超级表名称 - */ - @InterceptorIgnore(tenantLine = "true") - List> describeSuperTable(@Param("dataBaseName") String dataBaseName, - @Param("superTableName") String superTableName); - - /** - * 为超级表添加列 - * - * @param dataBaseName 数据库名称 - * @param superTableName 超级表名称 - * @param field 字段信息 - */ - @InterceptorIgnore(tenantLine = "true") - void addColumnForSuperTable(@Param("dataBaseName") String dataBaseName, - @Param("superTableName") String superTableName, - @Param("field") TdFieldDO field); - - /** - * 为超级表删除列 - * - * @param dataBaseName 数据库名称 - * @param superTableName 超级表名称 - * @param field 字段信息 - */ - @InterceptorIgnore(tenantLine = "true") - void dropColumnForSuperTable(@Param("dataBaseName") String dataBaseName, - @Param("superTableName") String superTableName, - @Param("field") TdFieldDO field); - - /** - * 创建表 - 创建超级表的子表 - * - * @param tableDO 表信息 - */ - @InterceptorIgnore(tenantLine = "true") - void createTable(TableDO tableDO); - - /** - * 插入数据 - 指定列插入数据 - * - * @param tableDto 数据 - */ - @InterceptorIgnore(tenantLine = "true") - void insertData(TableDO tableDto); - - List> selectByTimestamp(SelectDto selectDto); - - - void addTagForSuperTable(@Param("superTableName") String superTableName, - @Param("fieldsVo") FieldsVo fieldsVo); - - void dropTagForSuperTable(@Param("superTableName") String superTableName, - @Param("fieldsVo") FieldsVo fieldsVo); - - Map getCountByTimestamp(SelectDto selectDto); - - Map getLastData(SelectDto selectDto); - - @InterceptorIgnore(tenantLine = "true") - List> getHistoryData(SelectVisualDto selectVisualDto); - - List> getRealtimeData(SelectVisualDto selectVisualDto); - - List> getAggregateData(SelectVisualDto selectVisualDto); - - List> getLastDataByTags(TagsSelectDao tagsSelectDao); - - @InterceptorIgnore(tenantLine = "true") - Long getHistoryCount(SelectVisualDto selectVisualDto); -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java new file mode 100644 index 000000000..e5353f7ee --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TagsSelectDO; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Map; + +/** + * TD 引擎的查询 Mapper + */ +@Mapper +@DS("tdengine") +public interface TdEngineQueryMapper { + + /** + * 根据时间戳查询数据 + * + * @param selectDO 查询条件 + * @return 查询结果 + */ + List> selectByTimestamp(SelectDO selectDO); + + /** + * 根据时间戳获取数据条数 + * + * @param selectDO 查询条件 + * @return 数据条数 + */ + Map getCountByTimestamp(SelectDO selectDO); + + /** + * 获取最新数据 + * + * @param selectDO 查询条件 + * @return 最新数据 + */ + Map getLastData(SelectDO selectDO); + + /** + * 获取历史数据 + * + * @param selectVisualDO 查询条件 + * @return 历史数据列表 + */ + @InterceptorIgnore(tenantLine = "true") + List> getHistoryData(SelectVisualDO selectVisualDO); + + /** + * 获取实时数据 + * + * @param selectVisualDO 查询条件 + * @return 实时数据列表 + */ + List> getRealtimeData(SelectVisualDO selectVisualDO); + + /** + * 获取聚合数据 + * + * @param selectVisualDO 查询条件 + * @return 聚合数据列表 + */ + List> getAggregateData(SelectVisualDO selectVisualDO); + + /** + * 根据标签获取最新数据 + * + * @param tagsSelectDO 查询条件 + * @return 最新数据列表 + */ + List> getLastDataByTags(TagsSelectDO tagsSelectDO); + + /** + * 获取历史数据条数 + * + * @param selectVisualDO 查询条件 + * @return 数据条数 + */ + @InterceptorIgnore(tenantLine = "true") + Long getHistoryCount(SelectVisualDO selectVisualDO); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineSuperTableMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineSuperTableMapper.java new file mode 100644 index 000000000..e688563d5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineSuperTableMapper.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Map; + +/** + * TD 引擎的超级表 Mapper + */ +@Mapper +@DS("tdengine") +public interface TdEngineSuperTableMapper { + + /** + * 创建超级表 + * SQL:CREATE STABLE [IF NOT EXISTS] stb_name (create_definition [, create_definition] ...) TAGS (create_definition [, create_definition] ...) [table_options]; + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * columns 列信息 + * tags 标签信息 + */ + @InterceptorIgnore(tenantLine = "true") + void createSuperTable(TdTableDO superTable); + + /** + * 查看超级表 - 显示当前数据库下的所有超级表信息 + * SQL:SHOW STABLES [LIKE tb_name_wildcard]; + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + */ + @InterceptorIgnore(tenantLine = "true") + List> showSuperTables(TdTableDO superTable); + + /** + * 查看超级表 - 获取超级表的结构信息 + * SQL:DESCRIBE [db_name.]stb_name; + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + */ + @InterceptorIgnore(tenantLine = "true") + List> describeSuperTable(TdTableDO superTable); + + /** + * 修改超级表 - 增加列 + * SQL:ALTER STABLE stb_name ADD COLUMN col_name column_type; + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * column 列信息 + */ + @InterceptorIgnore(tenantLine = "true") + void addColumnForSuperTable(TdTableDO superTable); + + /** + * 修改超级表 - 删除列 + * SQL:ALTER STABLE stb_name DROP COLUMN col_name; + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * column 列信息 + */ + @InterceptorIgnore(tenantLine = "true") + void dropColumnForSuperTable(TdTableDO superTable); + + /** + * 修改超级表 - 修改列宽 + * SQL:ALTER STABLE stb_name MODIFY COLUMN col_name data_type(length); + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * column 列信息 + */ + @InterceptorIgnore(tenantLine = "true") + void modifyColumnWidthForSuperTable(TdTableDO superTable); + + + /** + * 修改超级表 - 为超级表添加标签 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * tag 标签信息 + */ + @InterceptorIgnore(tenantLine = "true") + void addTagForSuperTable(TdTableDO superTable); + + /** + * 修改超级表 - 为超级表删除标签 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * tag 标签信息 + */ + @InterceptorIgnore(tenantLine = "true") + void dropTagForSuperTable(TdTableDO superTable); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineTableMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineTableMapper.java new file mode 100644 index 000000000..72517bcab --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineTableMapper.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; + +/** + * TD 引擎的表 Mapper + */ +@Mapper +@DS("tdengine") +public interface TdEngineTableMapper { + + /** + * 创建子表 - 创建子表 + * SQL:CREATE TABLE [IF NOT EXISTS] tb_name USING stb_name TAGS (tag_value1, ...); + * + * @param table 表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * tableName 子表名称 + * tags TAG 字段 + */ + @InterceptorIgnore(tenantLine = "true") + void createTable(TdTableDO table); + + /** + * 创建子表 - 创建子表并指定标签的值 + * SQL:CREATE TABLE [IF NOT EXISTS] tb_name USING stb_name (tag_name1, ...) TAGS (tag_value1, ...); + * + * @param table 表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * tableName 子表名称 + * tags TAG 字段 + */ + @InterceptorIgnore(tenantLine = "true") + void createTableWithTags(TdTableDO table); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 1b44bd5d0..4179075df 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -6,13 +6,13 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; -import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; +import cn.iocoder.yudao.module.iot.service.tdengine.TdEngineQueryService; import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import jakarta.annotation.Resource; import jakarta.validation.Valid; @@ -39,13 +39,12 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { private IotThingModelMessageService thingModelMessageService; @Resource private IotThinkModelFunctionService thinkModelFunctionService; + @Resource + private TdEngineQueryService tdEngineQueryService; @Resource private DeviceDataRedisDAO deviceDataRedisDAO; - @Resource - private TdEngineMapper tdEngineMapper; - @Override public void saveDeviceData(String productKey, String deviceName, String message) { // 1. 根据产品 key 和设备名称,获得设备信息 @@ -112,18 +111,18 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { // 1. 获取设备信息 IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); // 2. 获取设备属性历史数据 - SelectVisualDto selectVisualDto = new SelectVisualDto(); - selectVisualDto.setDataBaseName(getDatabaseName()); - selectVisualDto.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); - selectVisualDto.setFieldName(deviceDataReqVO.getIdentifier()); - selectVisualDto.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); - selectVisualDto.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); + SelectVisualDO selectVisualDO = new SelectVisualDO(); + selectVisualDO.setDataBaseName(getDatabaseName()); + selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); + selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier()); + selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); + selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); Map params = new HashMap<>(); params.put("rows", deviceDataReqVO.getPageSize()); params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); - selectVisualDto.setParams(params); - pageResult.setList(tdEngineMapper.getHistoryData(selectVisualDto)); - pageResult.setTotal(tdEngineMapper.getHistoryCount(selectVisualDto)); + selectVisualDO.setParams(params); + pageResult.setList(tdEngineQueryService.getHistoryData(selectVisualDO)); + pageResult.setTotal(tdEngineQueryService.getHistoryCount(selectVisualDO)); return pageResult; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java similarity index 50% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java index 42439e25a..7c88b83aa 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java @@ -1,26 +1,15 @@ package cn.iocoder.yudao.module.iot.service.tdengine; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import java.util.List; /** - * 数据结构接口 + * IoT 超级表服务,负责根据物模型创建和更新超级表,以及创建超级表的子表等操作。 */ -public interface IotDbStructureDataService { - - /** - * 创建物模型定义 - */ - void createSuperTable(ThingModelRespVO thingModel, Integer deviceType); - - /** - * 更新物模型定义 - */ - void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType); +public interface IotSuperTableService { /** * 创建超级表数据模型 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java similarity index 55% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java index 947178102..3be324c4e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotDbStructureDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import jakarta.annotation.Resource; @@ -17,135 +18,19 @@ import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; +/** + * IoT 超级表服务实现类,负责根据物模型创建和更新超级表,以及创建超级表的子表等操作。 + */ @Service @Slf4j -public class IotDbStructureDataServiceImpl implements IotDbStructureDataService { +public class IotSuperTableServiceImpl implements IotSuperTableService { @Resource - private IotTdEngineService iotTdEngineService; + private TdEngineSuperTableService tdEngineSuperTableService; @Value("${spring.datasource.dynamic.datasource.tdengine.url}") private String url; - @Override - public void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { - // 1. 解析物模型,获得字段列表 - List schemaFields = new ArrayList<>(); - schemaFields.add(TdFieldDO.builder() - .fieldName("time") - .dataType("TIMESTAMP") - .build()); - schemaFields.addAll(FieldParser.parse(thingModel)); - - // 3. 设置超级表的标签 - List tagsFields = Arrays.asList( - TdFieldDO.builder().fieldName("product_key").dataType("NCHAR").dataLength(64).build(), - TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build(), - TdFieldDO.builder().fieldName("device_name").dataType("NCHAR").dataLength(64).build(), - TdFieldDO.builder().fieldName("device_type").dataType("INT").build() - ); - - // 4. 获取超级表的名称 - String superTableName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); - - // 5. 创建超级表 - String dataBaseName = getDatabaseName(); - iotTdEngineService.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); - } - - @Override - public void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { - try { - String tbName = getProductPropertySTableName(deviceType, thingModel.getProductKey()); - List oldFields = getTableFields(tbName); - List newFields = FieldParser.parse(thingModel); - - updateTableFields(tbName, oldFields, newFields); - } catch (Exception e) { - log.error("更新物模型超级表失败", e); - } - } - - // 获取表字段 - private List getTableFields(String tableName) { - List fields = new ArrayList<>(); - // 获取超级表的描述信息 - List> maps = iotTdEngineService.describeSuperTable(getDatabaseName(), tableName); - if (maps != null) { - // 过滤掉 note 字段为 TAG 的记录和 time 字段 - List> filteredMaps = maps.stream() - .filter(map -> !"TAG".equals(map.get("note"))) - .filter(map -> !"time".equals(map.get("field"))) - .toList(); - // 解析字段信息 - fields = FieldParser.parse(filteredMaps.stream() - .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) - .collect(Collectors.toList())); - } - return fields; - } - - // 更新表字段 - private void updateTableFields(String tableName, List oldFields, List newFields) { - // 获取新增字段 - List addFields = getAddFields(oldFields, newFields); - // 获取修改字段 - List modifyFields = getModifyFields(oldFields, newFields); - // 获取删除字段 - List dropFields = getDropFields(oldFields, newFields); - - String dataBaseName = getDatabaseName(); - // 添加新增字段 - if (CollUtil.isNotEmpty(addFields)) { - iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, addFields); - } - // 删除旧字段 - if (CollUtil.isNotEmpty(dropFields)) { - iotTdEngineService.dropColumnForSuperTable(dataBaseName, tableName, dropFields); - } - // 修改字段(先删除再添加) - if (CollUtil.isNotEmpty(modifyFields)) { - iotTdEngineService.dropColumnForSuperTable(dataBaseName, tableName, modifyFields); - iotTdEngineService.addColumnForSuperTable(dataBaseName, tableName, modifyFields); - } - } - - // 获取新增字段 - private List getAddFields(List oldFields, List newFields) { - Set oldFieldNames = oldFields.stream() - .map(TdFieldDO::getFieldName) - .collect(Collectors.toSet()); - return newFields.stream() - .filter(f -> !oldFieldNames.contains(f.getFieldName())) - .collect(Collectors.toList()); - } - - // 获取修改字段 - private List getModifyFields(List oldFields, List newFields) { - Map oldFieldMap = oldFields.stream() - .collect(Collectors.toMap(TdFieldDO::getFieldName, f -> f)); - - return newFields.stream() - .filter(f -> { - TdFieldDO oldField = oldFieldMap.get(f.getFieldName()); - return oldField != null && - (!oldField.getDataType().equals(f.getDataType()) || - !Objects.equals(oldField.getDataLength(), f.getDataLength())); - }) - .collect(Collectors.toList()); - } - - // 获取删除字段 - private List getDropFields(List oldFields, List newFields) { - Set newFieldNames = newFields.stream() - .map(TdFieldDO::getFieldName) - .collect(Collectors.toSet()); - return oldFields.stream() - .filter(f -> !"time".equals(f.getFieldName()) && !"device_id".equals(f.getFieldName())) - .filter(f -> !newFieldNames.contains(f.getFieldName())) - .collect(Collectors.toList()); - } - @Override public void createSuperTableDataModel(IotProductDO product, List functionList) { ThingModelRespVO thingModel = buildThingModel(product, functionList); @@ -155,9 +40,9 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService return; } - String superTableName = getProductPropertySTableName(product.getDeviceType(), product.getProductKey()); - String dataBaseName = getDatabaseName(); - Integer tableExists = iotTdEngineService.checkSuperTableExists(dataBaseName, superTableName); + String superTableName = getSuperTableName(product.getDeviceType(), product.getProductKey()); + String databaseName = getDatabaseName(); + Integer tableExists = tdEngineSuperTableService.checkSuperTableExists(new TdTableDO(databaseName, superTableName)); if (tableExists != null && tableExists > 0) { updateSuperTable(thingModel, product.getDeviceType()); @@ -166,40 +51,202 @@ public class IotDbStructureDataServiceImpl implements IotDbStructureDataService } } + /** + * 创建超级表 + */ + private void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { + // 解析物模型,获取字段列表 + List schemaFields = new ArrayList<>(); + schemaFields.add(TdFieldDO.builder() + .fieldName("time") + .dataType("TIMESTAMP") + .build()); + schemaFields.addAll(FieldParser.parse(thingModel)); + + // 设置超级表的标签 + List tagsFields = List.of( + TdFieldDO.builder().fieldName("product_key").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("device_name").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("device_type").dataType("INT").build() + ); + + // 获取超级表的名称和数据库名称 + String superTableName = getSuperTableName(deviceType, thingModel.getProductKey()); + String databaseName = getDatabaseName(); + + // 创建超级表 + tdEngineSuperTableService.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); + } + + /** + * 更新超级表 + */ + private void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { + String superTableName = getSuperTableName(deviceType, thingModel.getProductKey()); + try { + List oldFields = getTableFields(superTableName); + List newFields = FieldParser.parse(thingModel); + + updateTableFields(superTableName, oldFields, newFields); + } catch (Exception e) { + log.error("更新物模型超级表失败: {}", e.getMessage(), e); + } + } + + /** + * 获取表的字段信息 + */ + private List getTableFields(String tableName) { + List> tableDescription = tdEngineSuperTableService.describeSuperTable(new TdTableDO(getDatabaseName(), tableName)); + if (CollUtil.isEmpty(tableDescription)) { + return Collections.emptyList(); + } + + return tableDescription.stream() + .filter(map -> !"TAG".equals(map.get("note"))) + .filter(map -> !"time".equals(map.get("field"))) + .map(map -> TdFieldDO.builder() + .fieldName((String) map.get("field")) + .dataType((String) map.get("type")) + .dataLength((Integer) map.get("length")) + .build()) + .collect(Collectors.toList()); + } + + /** + * 更新表的字段,包括新增、修改和删除字段 + */ + private void updateTableFields(String tableName, List oldFields, List newFields) { + String databaseName = getDatabaseName(); + + // 获取新增、修改、删除的字段 + List addFields = getAddFields(oldFields, newFields); + List modifyFields = getModifyFields(oldFields, newFields); + List dropFields = getDropFields(oldFields, newFields); + + // 添加新增字段 + if (CollUtil.isNotEmpty(addFields)) { + tdEngineSuperTableService.addColumnsForSuperTable(TdTableDO.builder() + .dataBaseName(databaseName) + .superTableName(tableName) + .columns(addFields) + .build()); + } + // 删除旧字段 + if (CollUtil.isNotEmpty(dropFields)) { + tdEngineSuperTableService.dropColumnsForSuperTable(TdTableDO.builder() + .dataBaseName(databaseName) + .superTableName(tableName) + .columns(dropFields) + .build()); + } + // 修改字段(先删除再添加) + if (CollUtil.isNotEmpty(modifyFields)) { + tdEngineSuperTableService.dropColumnsForSuperTable(TdTableDO.builder() + .dataBaseName(databaseName) + .superTableName(tableName) + .columns(modifyFields) + .build()); + tdEngineSuperTableService.addColumnsForSuperTable(TdTableDO.builder() + .dataBaseName(databaseName) + .superTableName(tableName) + .columns(addFields) + .build()); + } + } + + /** + * 获取需要新增的字段 + */ + private List getAddFields(List oldFields, List newFields) { + Set oldFieldNames = oldFields.stream() + .map(TdFieldDO::getFieldName) + .collect(Collectors.toSet()); + return newFields.stream() + .filter(f -> !oldFieldNames.contains(f.getFieldName())) + .collect(Collectors.toList()); + } + + /** + * 获取需要修改的字段 + */ + private List getModifyFields(List oldFields, List newFields) { + Map oldFieldMap = oldFields.stream() + .collect(Collectors.toMap(TdFieldDO::getFieldName, f -> f)); + + return newFields.stream() + .filter(f -> { + TdFieldDO oldField = oldFieldMap.get(f.getFieldName()); + return oldField != null && ( + !oldField.getDataType().equals(f.getDataType()) || + !Objects.equals(oldField.getDataLength(), f.getDataLength()) + ); + }) + .collect(Collectors.toList()); + } + + /** + * 获取需要删除的字段 + */ + private List getDropFields(List oldFields, List newFields) { + Set newFieldNames = newFields.stream() + .map(TdFieldDO::getFieldName) + .collect(Collectors.toSet()); + return oldFields.stream() + .filter(f -> !"time".equals(f.getFieldName())) + .filter(f -> !newFieldNames.contains(f.getFieldName())) + .collect(Collectors.toList()); + } + + /** + * 构建物模型 + */ private ThingModelRespVO buildThingModel(IotProductDO product, List functionList) { ThingModelRespVO thingModel = new ThingModelRespVO(); thingModel.setId(product.getId()); thingModel.setProductKey(product.getProductKey()); - ThingModelRespVO.Model model = new ThingModelRespVO.Model(); List properties = functionList.stream() .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals( IotProductFunctionTypeEnum.valueOfType(function.getType()))) .map(this::buildThingModelProperty) .collect(Collectors.toList()); + ThingModelRespVO.Model model = new ThingModelRespVO.Model(); model.setProperties(properties); thingModel.setModel(model); return thingModel; } + /** + * 构建物模型属性 + */ private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) { ThingModelProperty property = BeanUtil.copyProperties(function, ThingModelProperty.class); property.setDataType(function.getProperty().getDataType()); return property; } + /** + * 获取数据库名称 + */ private String getDatabaseName() { - return url.substring(url.lastIndexOf("/") + 1); + int index = url.lastIndexOf("/"); + return index != -1 ? url.substring(index + 1) : url; } - static String getProductPropertySTableName(Integer deviceType, String productKey) { - return switch (deviceType) { - case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); - case 2 -> String.format("gateway_%s", productKey).toLowerCase(); - default -> String.format("device_%s", productKey).toLowerCase(); + /** + * 获取超级表名称 + */ + private String getSuperTableName(Integer deviceType, String productKey) { + String prefix = switch (deviceType) { + case 1 -> "gateway_sub_"; + case 2 -> "gateway_"; + default -> "device_"; }; + return (prefix + productKey).toLowerCase(); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java deleted file mode 100644 index 753284aca..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineService.java +++ /dev/null @@ -1,142 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.domain.SelectDto; -import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; -import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; - -import java.util.List; -import java.util.Map; - -/** - * TdEngineService - */ -public interface IotTdEngineService { - - /** - * 创建数据库 - * - * @param dataBaseName 数据库名称 - * @throws Exception 异常 - */ - void createDateBase(String dataBaseName) throws Exception; - - /** - * 创建超级表 - * - * @param schemaFields schema字段 - * @param tagsFields tags字段 - * @param superTableName 超级表名称 - */ - void createSuperTable(List schemaFields, List tagsFields, String dataBaseName, String superTableName); - - /** - * 检查超级表是否存在 - */ - Integer checkSuperTableExists(String dataBaseName, String superTableName); - - - /** - * 获取超级表的结构信息 - */ - List> describeSuperTable(String dataBaseName, String superTableName); - - /** - * 为超级表添加列 - * - * @param dataBaseName 数据库名称 - * @param superTableName 超级表名称 - * @param fieldsVo 字段信息 - */ - void addColumnForSuperTable(String dataBaseName, String superTableName, List fieldsVo); - - /** - * 为超级表删除列 - * - * @param dataBaseName 数据库名称 - * @param superTableName 超级表名称 - * @param fieldsVo 字段信息 - */ - void dropColumnForSuperTable(String dataBaseName, String superTableName, List fieldsVo); - - /** - * 为超级表添加tag - */ - Long getCountByTimesTamp(SelectDto selectDto) throws Exception; - - - /** - * 创建表 - * - * @param tableDto 表信息 - */ - void createTable(TableDO tableDto); - - /** - * 插入数据 - * - * @param tableDto 表信息 - */ - void insertData(TableDO tableDto); - - /** - * 根据时间戳查询数据 - * - * @param selectDto 查询条件 - * @return 数据 - * @throws Exception 异常 - */ - List> selectByTimesTamp(SelectDto selectDto) throws Exception; - - /** - * 初始化超级表 - * - * @param msg 消息 - * @throws Exception 异常 - */ - void initSTableFrame(String msg) throws Exception; - - /** - * 获取最新数据 - * - * @param selectDto 查询条件 - * @return 数据 - * @throws Exception 异常 - */ - Map getLastData(SelectDto selectDto) throws Exception; - - /** - * 根据tag查询最新数据 - * - * @param tagsSelectDao 查询条件 - * @return 数据 - */ - Map> getLastDataByTags(TagsSelectDao tagsSelectDao); - - /** - * 获取历史数据 - * - * @param selectVisualDto 查询条件 - * @return 数据 - */ - List> getHistoryData(SelectVisualDto selectVisualDto); - - /** - * 获取实时数据 - * - * @param selectVisualDto 查询条件 - * @return 数据 - */ - List> getRealtimeData(SelectVisualDto selectVisualDto); - - /** - * 获取聚合数据 - * - * @param selectVisualDto 查询条件 - * @return 数据 - */ - List> getAggregateData(SelectVisualDto selectVisualDto); - - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java deleted file mode 100644 index c7f7e7309..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotTdEngineServiceImpl.java +++ /dev/null @@ -1,107 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineMapper; -import cn.iocoder.yudao.module.iot.domain.SelectDto; -import cn.iocoder.yudao.module.iot.domain.TagsSelectDao; -import cn.iocoder.yudao.module.iot.domain.visual.SelectVisualDto; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Map; - -@Service -@Slf4j -public class IotTdEngineServiceImpl implements IotTdEngineService { - - @Resource - private TdEngineMapper tdEngineMapper; - - @Override - public void createDateBase(String dataBaseName) { - tdEngineMapper.createDatabase(dataBaseName); - } - - @Override - public void createSuperTable(List schemaFields, List tagsFields, String dataBaseName, String superTableName) { - tdEngineMapper.createSuperTable(schemaFields, tagsFields, dataBaseName, superTableName); - } - - @Override - public void createTable(TableDO tableDto) { - tdEngineMapper.createTable(tableDto); - } - - @Override - public void insertData(TableDO tableDto) { - tdEngineMapper.insertData(tableDto); - } - - @Override - public List> selectByTimesTamp(SelectDto selectDto) { - return List.of(); - } - - @Override - public void addColumnForSuperTable(String dataBaseName,String superTableName, List fields) { - for (TdFieldDO field : fields) { - tdEngineMapper.addColumnForSuperTable(dataBaseName,superTableName, field); - } - } - - @Override - public void dropColumnForSuperTable(String dataBaseName,String superTableName, List fields) { - for (TdFieldDO field : fields) { - tdEngineMapper.dropColumnForSuperTable(dataBaseName,superTableName, field); - } - } - - @Override - public Long getCountByTimesTamp(SelectDto selectDto) { - return 0L; - } - - @Override - public void initSTableFrame(String msg) { - - } - - @Override - public Map getLastData(SelectDto selectDto) { - return Map.of(); - } - - @Override - public Map> getLastDataByTags(TagsSelectDao tagsSelectDao) { - return Map.of(); - } - - @Override - public List> getHistoryData(SelectVisualDto selectVisualDto) { - return List.of(); - } - - @Override - public List> getRealtimeData(SelectVisualDto selectVisualDto) { - return List.of(); - } - - @Override - public List> getAggregateData(SelectVisualDto selectVisualDto) { - return List.of(); - } - - @Override - public Integer checkSuperTableExists(String dataBaseName, String superTableName) { - List> results = tdEngineMapper.showSuperTables(dataBaseName, superTableName); - return results == null || results.isEmpty() ? 0 : results.size(); - } - - @Override - public List> describeSuperTable(String dataBaseName, String superTableName) { - return tdEngineMapper.describeSuperTable(dataBaseName, superTableName); - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java index b2f51a7f8..ffcb3063c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java @@ -11,8 +11,8 @@ public interface IotThingModelMessageService { /** * 保存物模型消息 * - * @param device 设备 + * @param device 设备 * @param thingModelMessage 物模型消息 */ - void saveThingModelMessage(IotDeviceDO device,ThingModelMessage thingModelMessage); + void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 9bad7613e..69c417839 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -6,8 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSt import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; @@ -23,6 +23,9 @@ import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; +/** + * 物模型消息 Service 实现类 + */ @Slf4j @Service public class IotThingModelMessageServiceImpl implements IotThingModelMessageService { @@ -35,7 +38,11 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Resource private IotDeviceService iotDeviceService; @Resource - private IotTdEngineService iotTdEngineService; + private TdEngineTableService tdEngineTableService; + @Resource + private TdEngineSuperTableService tdEngineSuperTableService; + @Resource + private TdEngineDataWriterService tdEngineDataWriterService; @Resource private DeviceDataRedisDAO deviceDataRedisDAO; @@ -90,14 +97,11 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ return; } - // 构建并保存设备属性 - TableDO tableData = new TableDO(); - tableData.setDataBaseName(getDatabaseName()); - tableData.setSuperTableName(getProductPropertySTableName(device.getDeviceType(), device.getProductKey())); - tableData.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); - tableData.setSchemaFieldValues(schemaFieldValues); - - iotTdEngineService.insertData(tableData); + // 构建并保存设备属性数据 + tdEngineDataWriterService.insertData(TdTableDO.builder().build() + .setDataBaseName(getDatabaseName()) + .setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())) + .setColumns(schemaFieldValues)); } /** @@ -135,7 +139,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ String superTableName = getProductPropertySTableName(deviceType, productKey); String dataBaseName = getDatabaseName(); - List> maps = iotTdEngineService.describeSuperTable(dataBaseName, superTableName); + List> maps = tdEngineSuperTableService.describeSuperTable(new TdTableDO(dataBaseName, superTableName)); List tagsFieldValues = new ArrayList<>(); if (maps != null) { @@ -159,13 +163,11 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 创建设备数据表 String tableName = getDeviceTableName(productKey, deviceName); - TableDO tableDto = new TableDO(); - tableDto.setDataBaseName(dataBaseName); - tableDto.setSuperTableName(superTableName); - tableDto.setTableName(tableName); - tableDto.setTagsFieldValues(tagsFieldValues); - - iotTdEngineService.createTable(tableDto); + tdEngineTableService.createTable(TdTableDO.builder().build() + .setDataBaseName(dataBaseName) + .setSuperTableName(superTableName) + .setTableName(tableName) + .setTags(tagsFieldValues)); } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterService.java new file mode 100644 index 000000000..0995b0797 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterService.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; + +/** + * TD 引擎的数据写入 Service 接口 + */ +public interface TdEngineDataWriterService { + + /** + * 插入数据 - 指定列插入数据 + * + * @param table 数据 + * dataBaseName 数据库名 + * tableName 表名 + * columns 列 + */ + void insertData(TdTableDO table); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterServiceImpl.java new file mode 100644 index 000000000..f4dd2c8fd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterServiceImpl.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDataWriterMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +/** + * TD 引擎的数据写入 Service 实现类 + */ +@Service +public class TdEngineDataWriterServiceImpl implements TdEngineDataWriterService { + + @Resource + private TdEngineDataWriterMapper tdEngineDataWriterMapper; + + @Override + public void insertData(TdTableDO table) { + tdEngineDataWriterMapper.insertData(table); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseService.java new file mode 100644 index 000000000..d895262cc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseService.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +/** + * TD 引擎的数据库 Service 接口 + */ +public interface TdEngineDatabaseService { + + /** + * 创建数据库 + * + * @param dataBaseName 数据库名称 + */ + void createDatabase(String dataBaseName); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseServiceImpl.java new file mode 100644 index 000000000..c880db8a9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseServiceImpl.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDatabaseMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * TD 引擎的数据库 Service 实现类 + */ +@Service +@Slf4j +public class TdEngineDatabaseServiceImpl implements TdEngineDatabaseService { + + @Resource + private TdEngineDatabaseMapper tdEngineDatabaseMapper; + + @Override + public void createDatabase(String dataBaseName) { + tdEngineDatabaseMapper.createDatabase(dataBaseName); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryService.java new file mode 100644 index 000000000..8d07b4334 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryService.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; + +import java.util.List; +import java.util.Map; + +/** + * TD 引擎的查询 Service 接口 + */ +public interface TdEngineQueryService { + + /** + * 获取历史数据 + * + * @param selectVisualDO 查询条件 + * @return 历史数据列表 + */ + List> getHistoryData(SelectVisualDO selectVisualDO); + + /** + * 获取历史数据条数 + * + * @param selectVisualDO 查询条件 + * @return 数据条数 + */ + Long getHistoryCount(SelectVisualDO selectVisualDO); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryServiceImpl.java new file mode 100644 index 000000000..672a58640 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryServiceImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineQueryMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class TdEngineQueryServiceImpl implements TdEngineQueryService { + + @Resource + private TdEngineQueryMapper tdEngineQueryMapper; + + @Override + public List> getHistoryData(SelectVisualDO selectVisualDO) { + return tdEngineQueryMapper.getHistoryData(selectVisualDO); + } + + @Override + public Long getHistoryCount(SelectVisualDO selectVisualDO) { + return tdEngineQueryMapper.getHistoryCount(selectVisualDO); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableService.java new file mode 100644 index 000000000..df6290a98 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableService.java @@ -0,0 +1,123 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; + +import java.util.List; +import java.util.Map; + +/** + * TD 引擎的超级表 Service 接口 + */ +public interface TdEngineSuperTableService { + + /** + * 创建超级表 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * columns 列信息 + * tags 标签信息 + */ + void createSuperTable(TdTableDO superTable); + + /** + * 查看超级表 - 显示当前数据库下的所有超级表信息 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + */ + + List> showSuperTables(TdTableDO superTable); + + /** + * 查看超级表 - 获取超级表的结构信息 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + */ + List> describeSuperTable(TdTableDO superTable); + + /** + * 修改超级表 - 增加列 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * column 列信息 + */ + void addColumnForSuperTable(TdTableDO superTable); + + /** + * 修改超级表 - 删除列 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * column 列信息 + */ + void dropColumnForSuperTable(TdTableDO superTable); + + /** + * 修改超级表 - 修改列宽 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * column 列信息 + */ + void modifyColumnWidthForSuperTable(TdTableDO superTable); + + + /** + * 修改超级表 - 为超级表添加标签 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * tag 标签信息 + */ + void addTagForSuperTable(TdTableDO superTable); + + /** + * 修改超级表 - 为超级表删除标签 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * tag 标签信息 + */ + void dropTagForSuperTable(TdTableDO superTable); + + /** + * 检查超级表是否存在 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * @return 超级表数量 + */ + Integer checkSuperTableExists(TdTableDO superTable); + + /** + * 为超级表添加列 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * columns 列信息 + */ + void addColumnsForSuperTable(TdTableDO superTable); + + /** + * 为超级表删除列 + * + * @param superTable 超级表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * columns 列信息 + */ + void dropColumnsForSuperTable(TdTableDO superTable); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableServiceImpl.java new file mode 100644 index 000000000..60436e7bd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableServiceImpl.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineSuperTableMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * TD 引擎的超级表 Service 实现类 + */ +@Slf4j +@Service +public class TdEngineSuperTableServiceImpl implements TdEngineSuperTableService { + + @Resource + private TdEngineSuperTableMapper tdEngineSuperTableMapper; + + @Override + public void createSuperTable(TdTableDO superTable) { + tdEngineSuperTableMapper.createSuperTable(superTable); + } + + @Override + public List> showSuperTables(TdTableDO superTable) { + return tdEngineSuperTableMapper.showSuperTables(superTable); + } + + @Override + public List> describeSuperTable(TdTableDO superTable) { + return tdEngineSuperTableMapper.describeSuperTable(superTable); + } + + @Override + public void addColumnForSuperTable(TdTableDO superTable) { + tdEngineSuperTableMapper.addColumnForSuperTable(superTable); + } + + @Override + public void dropColumnForSuperTable(TdTableDO superTable) { + tdEngineSuperTableMapper.dropColumnForSuperTable(superTable); + } + + @Override + public void modifyColumnWidthForSuperTable(TdTableDO superTable) { + tdEngineSuperTableMapper.modifyColumnWidthForSuperTable(superTable); + } + + @Override + public void addTagForSuperTable(TdTableDO superTable) { + tdEngineSuperTableMapper.addTagForSuperTable(superTable); + } + + @Override + public void dropTagForSuperTable(TdTableDO superTable) { + tdEngineSuperTableMapper.dropTagForSuperTable(superTable); + } + + @Override + public Integer checkSuperTableExists(TdTableDO superTable) { + List> results = tdEngineSuperTableMapper.showSuperTables(superTable); + return results == null || results.isEmpty() ? 0 : results.size(); + } + + @Override + public void addColumnsForSuperTable(TdTableDO superTable) { + for (TdFieldDO column : superTable.getColumns()) { + tdEngineSuperTableMapper.addColumnForSuperTable(TdTableDO.builder() + .dataBaseName(superTable.getDataBaseName()) + .superTableName(superTable.getSuperTableName()) + .column(column) + .build()); + } + } + + @Override + public void dropColumnsForSuperTable(TdTableDO superTable) { + for (TdFieldDO column : superTable.getColumns()) { + tdEngineSuperTableMapper.dropColumnForSuperTable(TdTableDO.builder() + .dataBaseName(superTable.getDataBaseName()) + .superTableName(superTable.getSuperTableName()) + .column(column) + .build()); + } + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableService.java new file mode 100644 index 000000000..078159784 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableService.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; + +/** + * TD 引擎的表 Service 接口 + */ +public interface TdEngineTableService { + + /** + * 创建表 - 创建超级表的子表 + * + * @param table 表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * tableName 子表名称 + * tags TAG 字段 + */ + void createTable(TdTableDO table); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableServiceImpl.java new file mode 100644 index 000000000..cdca47888 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableServiceImpl.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.iot.service.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineTableMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * TD 引擎的表 Service 实现类 + */ +@Slf4j +@Service +public class TdEngineTableServiceImpl implements TdEngineTableService { + + @Resource + private TdEngineTableMapper tdEngineTableMapper; + + @Override + public void createTable(TdTableDO table) { + tdEngineTableMapper.createTable(table); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java index a6bf7b458..f60610faf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java @@ -75,5 +75,5 @@ public interface IotThinkModelFunctionService { * @param productKey 产品 Key * @return 产品物模型列表 */ - List getThinkModelFunctionListByProductKey(String productKey); + List getThinkModelFunctionListByProductKey(String productKey); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 25cfe7b46..404a2aaa0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -22,7 +22,7 @@ import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; -import cn.iocoder.yudao.module.iot.service.tdengine.IotDbStructureDataService; +import cn.iocoder.yudao.module.iot.service.tdengine.IotSuperTableService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -52,7 +52,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Resource private IotProductService productService; @Resource - private IotDbStructureDataService dbStructureDataService; + private IotSuperTableService dbStructureDataService; @Override @Transactional(rollbackFor = Exception.class) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml new file mode 100644 index 000000000..b5f044614 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + INSERT INTO ${dataBaseName}.${tableName} + + ${item.fieldName} + + VALUES + + #{item.fieldValue} + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml new file mode 100644 index 000000000..4d9a125db --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml @@ -0,0 +1,13 @@ + + + + + + + + CREATE DATABASE IF NOT EXISTS ${dataBaseName} + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml deleted file mode 100644 index 4e127e44b..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineMapper.xml +++ /dev/null @@ -1,327 +0,0 @@ - - - - - - - - CREATE DATABASE IF NOT EXISTS ${dataBaseName} - - - - CREATE STABLE IF NOT EXISTS ${dataBaseName}.${superTableName} - - - ${item.fieldName} - - - - - TIMESTAMP - - - TINYINT - - - SMALLINT - - - INT - - - BIGINT - - - FLOAT - - - DOUBLE - - - BINARY - - - NCHAR - - - BOOL - - - JSON - - - - - ( - ${item.dataLength} - ) - - - TAGS - - - - ${item.fieldName} - - - - - TIMESTAMP - - - TINYINT - - - SMALLINT - - - INT - - - BIGINT - - - FLOAT - - - DOUBLE - - - BINARY - - - NCHAR - - - BOOL - - - JSON - - - - - ( - ${item.dataLength} - ) - - - - - - - CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} - USING ${dataBaseName}.${superTableName} - - ${item.fieldName} - - TAGS - - #{item.fieldValue} - - - - - - INSERT INTO ${dataBaseName}.${tableName} - - ${item.fieldName} - - VALUES - - #{item.fieldValue} - - - - - - - ALTER STABLE ${dataBaseName}.${superTableName} ADD COLUMN - - #{field.fieldName} - - - - - TIMESTAMP - - - TINYINT - - - SMALLINT - - - INT - - - BIGINT - - - FLOAT - - - DOUBLE - - - BINARY - - - NCHAR - - - BOOL - - - JSON - - - - - ( - #{field.dataLength} - ) - - - - - ALTER STABLE ${dataBaseName}.${superTableName} DROP COLUMN - - #{field.fieldName} - - - - - ALTER - STABLE - #{superTableName} - ADD - TAG - - #{fieldDO.fieldName} - - - - - timestamp - - - tinyint - - - smallint - - - int - - - bigint - - - float - - - double - - - binary - - - nchar - - - bool - - - json - - - - - ( - #{fieldDO.dataLength} - ) - - - - - ALTER - STABLE - #{superTableName} - DROP - TAG - - #{fieldsVo.fieldName} - - - - - - - - - - - - - - - - - - - - - diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml new file mode 100644 index 000000000..9407b371d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml new file mode 100644 index 000000000..1ddbe3b97 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml @@ -0,0 +1,72 @@ + + + + + + + + CREATE STABLE IF NOT EXISTS ${dataBaseName}.${superTableName} + + ${item.fieldName} ${item.dataType} + + (${item.dataLength}) + + + TAGS + + ${item.fieldName} ${item.dataType} + + (${item.dataLength}) + + + + + + + + + + + + + ALTER STABLE ${dataBaseName}.${superTableName} ADD COLUMN ${column.fieldName} ${column.dataType} + + (${column.dataLength}) + + + + + + ALTER STABLE ${dataBaseName}.${superTableName} DROP COLUMN ${column.fieldName} + + + + + ALTER STABLE ${dataBaseName}.${superTableName} MODIFY COLUMN ${column.fieldName} ${column.dataType} + + (${column.dataLength}) + + + + + + ALTER STABLE ${dataBaseName}.${superTableName} ADD TAG ${tag.fieldName} ${tag.dataType} + + (${tag.dataLength}) + + + + + + ALTER STABLE ${dataBaseName}.${superTableName} DROP TAG ${tag.fieldName} + + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml new file mode 100644 index 000000000..2d469a390 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml @@ -0,0 +1,33 @@ + + + + + + + + CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} + USING ${dataBaseName}.${superTableName} + TAGS + + #{item.fieldValue} + + + + + + CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} + USING ${dataBaseName}.${superTableName} + + #{item.fieldName} + + TAGS + + #{item.fieldValue} + + + + \ No newline at end of file From 9b30d5d35572dc54646b2c3f3ad2fe04368fcd5d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 9 Nov 2024 13:39:51 +0800 Subject: [PATCH 011/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9Atdengine=20=E5=B0=81=E8=A3=85?= =?UTF-8?q?=E7=9A=84=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceDataController.java | 2 ++ .../vo/deviceData/IotDeviceDataReqVO.java | 1 + .../dataobject/device/IotDeviceDataDO.java | 1 + .../iot/dal/dataobject/tdengine/SelectDO.java | 4 ++++ .../dataobject/tdengine/SelectVisualDO.java | 1 + .../dal/dataobject/tdengine/TableManager.java | 1 + .../dal/dataobject/tdengine/TdRestApi.java | 1 + .../dal/dataobject/tdengine/TdTableDO.java | 1 + .../iot/dal/mysql/device/IotDeviceMapper.java | 1 + .../IotThinkModelFunctionMapper.java | 5 +++-- .../dal/tdengine/TdEngineDatabaseMapper.java | 1 + .../iot/dal/tdengine/TdEngineQueryMapper.java | 1 + .../iot/emq/service/EmqxServiceImpl.java | 2 ++ .../device/IotDeviceDataServiceImpl.java | 1 + .../service/device/IotDeviceServiceImpl.java | 21 +++++++++---------- .../IotThingModelMessageServiceImpl.java | 13 +++++++++++- .../tdengine/TdEngineDataWriterMapper.xml | 1 - .../tdengine/TdEngineDatabaseMapper.xml | 1 - .../mapper/tdengine/TdEngineQueryMapper.xml | 1 - .../tdengine/TdEngineSuperTableMapper.xml | 1 - .../mapper/tdengine/TdEngineTableMapper.xml | 1 - 21 files changed, 43 insertions(+), 19 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index e710d0ea8..ac2ec5cf7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -31,6 +31,7 @@ public class IotDeviceDataController { @Resource private IotDeviceDataService deviceDataService; + // TODO @haohao:是不是叫 get-latest 就好了。因为 data 已经在 url 里了哈 @GetMapping("/latest-data") @Operation(summary = "获取设备属性最新数据") public CommonResult> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) { @@ -38,6 +39,7 @@ public class IotDeviceDataController { return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); } + // TODO @haohao:是不是叫 /history-data => page @GetMapping("/history-data") @Operation(summary = "获取设备属性历史数据") public CommonResult> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java index 5f87a1cb8..21e53aff8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java @@ -10,6 +10,7 @@ import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +// TODO @haohao:IotDeviceDataPageReqVO @Schema(description = "管理后台 - IoT 设备数据 Request VO") @Data public class IotDeviceDataReqVO extends PageParam { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java index 5d8051172..68370d731 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java @@ -23,6 +23,7 @@ import java.time.LocalDateTime; @AllArgsConstructor public class IotDeviceDataDO { + // TODO @haohao:每个字段的关联关系,可以 @ 下哈。 /** * 设备编号 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java index 503b26310..652c3aee6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java @@ -3,12 +3,15 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; import lombok.Data; import java.util.Set; + +// TODO @haohao:类似这个,其实可以参考 mybatis plus,querywrapper,搞个 TdEngineQueryWrapper。这样看起来会更好懂。 /** * 查询DO */ @Data public class SelectDO { + // TODO @haoha:database 是个单词 /** * 数据库名称 */ @@ -39,6 +42,7 @@ public class SelectDO { */ private String type; + // TODO @haohao:这个字段,是啥哈? /** * 查询条件 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java index d5faf45a9..d4c35d66d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java @@ -4,6 +4,7 @@ import lombok.Data; import java.util.Map; +// TODO @haohao:类似 SelectDO 的想法,只是它是返回。ps:貌似可以在 tdengine 里面,创建一个 query 包,放这种比较特殊的查询和结果对象。dataobject 更多还是实际存储的结构化的 do @Data public class SelectVisualDO { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java index 65663d805..e11db58e7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; import java.util.List; +// TODO @haohao:这个还有用哇? /** * TableManager 类用于管理 TDengine 表的创建、删除和结构信息获取 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java index 6653ece40..b2d1ac029 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +// TODO @haohao:有部分非实体的部分,是不是可以搞到 iot 的 framework 包下,搞个 tdengine 包,作为框架级的封装,放在 dataobject,感觉不是很合理哈。【可以微信讨论下】 /** * TdRestApi 类用于处理 TDengine 的 REST API 请求 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java index 314c51de3..3b30352e4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java @@ -21,6 +21,7 @@ public class TdTableDO { */ private String dataBaseName; + // TODO @haohao:superTableName 和 tableName 是不是合并。因为每个 mapper 操作的时候,有且只会使用到其中一个。 /** * 超级表名称 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 3129f400c..4d8315eb3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -15,6 +15,7 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface IotDeviceMapper extends BaseMapperX { + // TODO @haohao:可能多余的查询条件,要去掉哈 default PageResult selectPage(IotDevicePageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(IotDeviceDO::getDeviceKey, reqVO.getDeviceKey()) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index 2883abe4e..c8745aab6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -43,7 +43,7 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX selectListByProductIdAndIdentifiersAndTypes(Long productId, List identifiers, - List types){ + List types) { return selectList(new LambdaQueryWrapperX() .eq(IotThinkModelFunctionDO::getProductId, productId) .in(IotThinkModelFunctionDO::getIdentifier, identifiers) @@ -55,7 +55,8 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX selectListByProductKey(String productKey){ + default List selectListByProductKey(String productKey) { return selectList(IotThinkModelFunctionDO::getProductKey, productKey); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java index bc562ccca..cd3eaa8b9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +// TODO @haohao:InterceptorIgnore 忽略租户,可以在每个方法上,添加 @TenantIgnore 哈。 /** * TD 引擎的数据库 Mapper */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java index e5353f7ee..a2408e335 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java @@ -25,6 +25,7 @@ public interface TdEngineQueryMapper { */ List> selectByTimestamp(SelectDO selectDO); + // TODO @haohao:最好方法的命名,和数据库操作的保持一直。get => select。然后 selectList or selectOne /** * 根据时间戳获取数据条数 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index f338d6249..343f9ba21 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -31,6 +31,7 @@ public class EmqxServiceImpl implements EmqxService { // 根据不同的主题,处理不同的业务逻辑 if (topic.contains("/property/post")) { // 设备上报数据 topic /sys/f13f57c63e9/dianbiao1/thing/event/property/post + // TODO @hao:这块未来可能,搞个 IotTopicUrls 之类?把拼接和解析的逻辑,收敛 String productKey = topic.split("/")[2]; String deviceName = topic.split("/")[3]; String message = new String(mqttMessage.getPayload()); @@ -48,4 +49,5 @@ public class EmqxServiceImpl implements EmqxService { log.error("订阅默认主题失败", e); } } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 4179075df..8f68989c9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -133,4 +133,5 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { private static String getDeviceTableName(String productKey, String deviceName) { return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase()); } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 60743f671..0ec737a30 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -213,31 +213,30 @@ public class IotDeviceServiceImpl implements IotDeviceService { @Override public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) { - // 校验存在 + // 1. 校验存在 + // TODO @haohao:这里的 iotDeviceDO => device。一个是去掉 iot,一个是去掉 DO 后缀。这样,简洁一点。 IotDeviceDO iotDeviceDO = validateDeviceExists(updateReqVO.getId()); - // 更新状态和更新时间 + // 2.1 更新状态和更新时间 IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); - - // 以前是未激活,现在是上线,设置设备激活时间 + // TODO @haohao:下面几个状态的处理,可以考虑 if else if。这样,看起来会有层次感哈 + // 2.2.1 以前是未激活,现在是上线,设置设备激活时间 + // TODO @haohao:这里可以使用 ObjectUtils.equalsAny 类似这种哈。 if (Objects.equals(iotDeviceDO.getStatus(), IotDeviceStatusEnum.INACTIVE.getStatus()) && Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { updateObj.setActiveTime(LocalDateTime.now()); } - - // 如果是上线,设置上线时间 + // 2.2.2 如果是上线,设置上线时间 if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { updateObj.setLastOnlineTime(LocalDateTime.now()); } - - // 如果是离线,设置离线时间 + // 2.2.3 如果是离线,设置离线时间 if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.OFFLINE.getStatus())) { updateObj.setLastOfflineTime(LocalDateTime.now()); } - - // 设置状态更新时间 + // 2.3 设置状态更新时间 updateObj.setStatusLastUpdateTime(LocalDateTime.now()); - + // 2.4 更新到数据库 deviceMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 69c417839..280b32d9a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -47,6 +47,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Resource private DeviceDataRedisDAO deviceDataRedisDAO; + // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 @Override @TenantIgnore public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) { @@ -55,12 +56,14 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 创建设备数据表 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); // 更新设备状态 + // TODO @haohao:下面可以考虑,链式调用。iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO().setid().setstatus()) IotDeviceStatusUpdateReqVO updateReqVO = new IotDeviceStatusUpdateReqVO(); updateReqVO.setId(device.getId()); updateReqVO.setStatus(IotDeviceStatusEnum.ONLINE.getStatus()); iotDeviceService.updateDeviceStatus(updateReqVO); } + // TODO @haohao:这个变量,可以和 “过滤并收集有效的属性字段” 那块,因为关联度高一点。 // 获取设备属性 Map params = thingModelMessage.dataToMap(); @@ -70,12 +73,12 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ .stream() .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType().equals(function.getType())) .toList(); - if (functionList.isEmpty()) { return; } // 获取属性标识符集合 + // TODO @haohao:这个变量,可以和 “过滤并收集有效的属性字段” 那块,因为关联度高一点。另外,可以使用 CollectionUtils。convertSet Set propertyIdentifiers = functionList.stream() .map(IotThinkModelFunctionDO::getIdentifier) .collect(Collectors.toSet()); @@ -90,9 +93,11 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ if (propertyIdentifiers.contains(key)) { schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val)); // 缓存设备属性 + // TODO @haohao:这个缓存的写入,可以使用的时候 cache 么?被动读 setDeviceDataCache(device, functionMap.get(key), val, thingModelMessage.getTime()); } }); + // TODO @haohao:疑问,为什么 1 不继续哈? if (schemaFieldValues.size() == 1) { return; } @@ -127,6 +132,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ deviceDataRedisDAO.set(deviceData); } + // TODO @haohao:实现没问题哈。这个方法的空行有点多,逻辑分块上没这么明显。看看能不能改下。 /** * 创建设备数据表 * @@ -143,6 +149,8 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ List tagsFieldValues = new ArrayList<>(); if (maps != null) { + // TODO @haohao:一些字符串,是不是可以枚举起来哈。 + // TODO @haohao:这种过滤的,常用的,可以考虑用 CollectionUtils.filterList。一些常用的 stream 操作,适合封装哈 List> taggedNotesList = maps.stream() .filter(map -> "TAG".equals(map.get("note"))) .toList(); @@ -176,6 +184,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * @return 数据库名称 */ private String getDatabaseName() { + // TODO @haohao:可以使用 StrUtil.subAftetLast 这种方法 return url.substring(url.lastIndexOf("/") + 1); } @@ -187,6 +196,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * @return 产品属性表名 */ private static String getProductPropertySTableName(Integer deviceType, String productKey) { + // TODO @haohao:枚举下,会好点哈。 return switch (deviceType) { case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); case 2 -> String.format("gateway_%s", productKey).toLowerCase(); @@ -204,4 +214,5 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ private static String getDeviceTableName(String productKey, String deviceName) { return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase()); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml index b5f044614..dd38cd08e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml @@ -2,7 +2,6 @@ - diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml index 4d9a125db..919c301f7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml @@ -2,7 +2,6 @@ - diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml index 9407b371d..f4361bc67 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml @@ -2,7 +2,6 @@ - diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml index 1ddbe3b97..37cf71910 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml @@ -2,7 +2,6 @@ - diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml index 2d469a390..867ef8f43 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml @@ -2,7 +2,6 @@ - From 89fb71e8573d1f6552d70a699e3a8b1ec8612f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 9 Nov 2024 23:44:05 +0800 Subject: [PATCH 012/228] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91=20=E4=BC=98=E5=8C=96=20tdengine=20=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=95=B0=E6=8D=AE=E5=BA=93=E7=9B=B8=E5=85=B3=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/enums/IotConstants.java | 38 +++++ .../admin/device/IotDeviceDataController.java | 16 +- ...ReqVO.java => IotDeviceDataPageReqVO.java} | 3 +- .../vo/deviceData/IotDeviceDataRespVO.java | 3 - .../dataobject/device/IotDeviceDataDO.java | 20 ++- .../iot/dal/dataobject/tdengine/SelectDO.java | 6 - .../dataobject/tdengine/SelectVisualDO.java | 3 + .../dal/dataobject/tdengine/TableManager.java | 159 ------------------ ...ableMapper.java => TdEngineDDLMapper.java} | 60 +++++-- .../iot/dal/tdengine/TdEngineDMLMapper.java | 103 ++++++++++++ .../tdengine/TdEngineDataWriterMapper.java | 25 --- .../dal/tdengine/TdEngineDatabaseMapper.java | 24 --- .../iot/dal/tdengine/TdEngineQueryMapper.java | 86 ---------- .../iot/dal/tdengine/TdEngineTableMapper.java | 41 ----- .../service/device/IotDeviceDataService.java | 6 +- .../device/IotDeviceDataServiceImpl.java | 22 +-- .../service/device/IotDeviceServiceImpl.java | 45 ++--- .../tdengine/IotSuperTableService.java | 2 +- .../tdengine/IotSuperTableServiceImpl.java | 59 ++++--- .../IotThingModelMessageServiceImpl.java | 130 +++++++------- .../tdengine/TdEngineDataWriterService.java | 19 --- .../TdEngineDataWriterServiceImpl.java | 21 --- .../tdengine/TdEngineDatabaseService.java | 14 -- .../tdengine/TdEngineDatabaseServiceImpl.java | 22 --- .../tdengine/TdEngineQueryService.java | 28 --- .../tdengine/TdEngineQueryServiceImpl.java | 26 --- .../tdengine/TdEngineSuperTableService.java | 123 -------------- .../TdEngineSuperTableServiceImpl.java | 90 ---------- .../tdengine/TdEngineTableService.java | 21 --- .../tdengine/TdEngineTableServiceImpl.java | 23 --- ...rTableMapper.xml => TdEngineDDLMapper.xml} | 34 +++- ...eQueryMapper.xml => TdEngineDMLMapper.xml} | 32 +++- .../tdengine/TdEngineDataWriterMapper.xml | 21 --- .../tdengine/TdEngineDatabaseMapper.xml | 12 -- .../mapper/tdengine/TdEngineTableMapper.xml | 32 ---- 35 files changed, 416 insertions(+), 953 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/{IotDeviceDataReqVO.java => IotDeviceDataPageReqVO.java} (92%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/{TdEngineSuperTableMapper.java => TdEngineDDLMapper.java} (68%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDMLMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDataWriterMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineTableMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterServiceImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseServiceImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryServiceImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableServiceImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableServiceImpl.java rename yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/{TdEngineSuperTableMapper.xml => TdEngineDDLMapper.xml} (70%) rename yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/{TdEngineQueryMapper.xml => TdEngineDMLMapper.xml} (68%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java new file mode 100644 index 000000000..5927f44b9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.enums; + +/** + * Iot 常量 + * + * @author 芋道源码 + */ +public interface IotConstants { + + /** + * 获取设备表名 + *

+ * 格式为 device_{productKey}_{deviceName} + */ + String DEVICE_TABLE_NAME_FORMAT = "device_%s_%s"; + + /** + * 获取产品属性超级表名 - 网关子设备 + *

+ * 格式为 gateway_sub_{productKey} + */ + String GATEWAY_SUB_STABLE_NAME_FORMAT = "gateway_sub_%s"; + + /** + * 获取产品属性超级表名 - 网关 + *

+ * 格式为 gateway_{productKey} + */ + String GATEWAY_STABLE_NAME_FORMAT = "gateway_%s"; + + /** + * 获取产品属性超级表名 - 设备 + *

+ * 格式为 device_{productKey} + */ + String DEVICE_STABLE_NAME_FORMAT = "device_%s"; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index ac2ec5cf7..72fdda8c8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotTimeDataRespVO; @@ -31,19 +31,17 @@ public class IotDeviceDataController { @Resource private IotDeviceDataService deviceDataService; - // TODO @haohao:是不是叫 get-latest 就好了。因为 data 已经在 url 里了哈 - @GetMapping("/latest-data") + @GetMapping("/latest") @Operation(summary = "获取设备属性最新数据") - public CommonResult> getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) { - List list = deviceDataService.getDevicePropertiesLatestData(deviceDataReqVO); + public CommonResult> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { + List list = deviceDataService.getLatestDeviceProperties(deviceDataReqVO); return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); } - // TODO @haohao:是不是叫 /history-data => page - @GetMapping("/history-data") + @GetMapping("/history") @Operation(summary = "获取设备属性历史数据") - public CommonResult> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO) { - PageResult> list = deviceDataService.getDevicePropertiesHistoryData(deviceDataReqVO); + public CommonResult> getHistoryDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { + PageResult> list = deviceDataService.getHistoryDeviceProperties(deviceDataReqVO); return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataPageReqVO.java similarity index 92% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataPageReqVO.java index 21e53aff8..da41299d8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataPageReqVO.java @@ -10,10 +10,9 @@ import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -// TODO @haohao:IotDeviceDataPageReqVO @Schema(description = "管理后台 - IoT 设备数据 Request VO") @Data -public class IotDeviceDataReqVO extends PageParam { +public class IotDeviceDataPageReqVO extends PageParam { @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") private Long deviceId; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java index 256bf84fa..ad32fb5f9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java @@ -1,9 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; import lombok.Data; import java.time.LocalDateTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java index 68370d731..892a6b8b7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java @@ -1,15 +1,12 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; -import com.baomidou.mybatisplus.annotation.TableId; -import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.math.BigDecimal; import java.time.LocalDateTime; /** @@ -23,39 +20,52 @@ import java.time.LocalDateTime; @AllArgsConstructor public class IotDeviceDataDO { - // TODO @haohao:每个字段的关联关系,可以 @ 下哈。 /** * 设备编号 + *

+ * 关联 {@link IotDeviceDO#getId()} */ private Long deviceId; /** * 物模型编号 + *

+ * 关联 {@link IotThinkModelFunctionDO#getId()} */ private Long thinkModelFunctionId; /** * 产品标识 + *

+ * 关联 {@link IotProductDO#getProductKey()} */ private String productKey; /** * 设备名称 + *

+ * 冗余 {@link IotDeviceDO#getDeviceName()} */ private String deviceName; /** * 属性标识符 + *

+ * 关联 {@link IotThinkModelFunctionDO#getIdentifier()} */ private String identifier; /** * 属性名称 + *

+ * 关联 {@link IotThinkModelFunctionDO#getName()} */ private String name; /** * 数据类型 + *

+ * 关联 {@link IotThinkModelFunctionDO#getProperty()#getDataType()} */ private String dataType; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java index 652c3aee6..542dd1e7b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java @@ -42,12 +42,6 @@ public class SelectDO { */ private String type; - // TODO @haohao:这个字段,是啥哈? - /** - * 查询条件 - */ - private Set orgIds; - /** * 设备ID */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java index d4c35d66d..44acc3ac5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java @@ -27,14 +27,17 @@ public class SelectVisualDO { * 查询类型,0历史数据,1实时数据,2聚合数据 */ private int type; + /** * 查询的数据量 */ private int num; + /** * 聚合函数 */ private String aggregate; + /** * 统计间隔数字+s/m/h/d * 比如1s,1m,1h,1d代表1秒,1分钟,1小时,1天 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java deleted file mode 100644 index e11db58e7..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TableManager.java +++ /dev/null @@ -1,159 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import java.util.List; - -// TODO @haohao:这个还有用哇? -/** - * TableManager 类用于管理 TDengine 表的创建、删除和结构信息获取 - */ -public class TableManager { - - /** - * 创建超级表模板(含存在判断) - */ - private static final String CREATE_STABLE_INE_TPL = "CREATE STABLE IF NOT EXISTS %s (%s) TAGS (%s);"; - - /** - * 删除超级表 - */ - private static final String DROP_STABLE_TPL = "DROP STABLE IF EXISTS %s;"; - - /** - * 获取表的结构信息 - */ - private static final String DESC_TB_TPL = "DESCRIBE %s;"; - - /** - * 超级表增加列 - */ - private static final String ALTER_STABLE_ADD_COL_TPL = "ALTER STABLE %s ADD COLUMN %s;"; - - /** - * 超级表修改列 - */ - private static final String ALTER_STABLE_MODIFY_COL_TPL = "ALTER STABLE %s MODIFY COLUMN %s;"; - - /** - * 超级表删除列 - */ - private static final String ALTER_STABLE_DROP_COL_TPL = "ALTER STABLE %s DROP COLUMN %s;"; - - /** - * 创建普通表模板(含存在判断) - */ - private static final String CREATE_CTABLE_INE_TPL = "CREATE TABLE IF NOT EXISTS %s (%s)"; - - /** - * 获取创建表sql - */ - public static String getCreateSTableSql(String tbName, List fields, TdFieldDO... tags) { - if (fields.isEmpty()) { - return null; - } - - // 生成字段片段 - StringBuilder sbField = new StringBuilder("time TIMESTAMP,"); - - for (TdFieldDO field : fields) { - sbField.append(FieldParser.getFieldDefine(field)); - sbField.append(","); - } - sbField.deleteCharAt(sbField.length() - 1); - - String fieldFrag = sbField.toString(); - - // 生成tag - StringBuilder sbTag = new StringBuilder(); - for (TdFieldDO tag : tags) { - sbTag.append(FieldParser.getFieldDefine(tag)) - .append(","); - } - sbTag.deleteCharAt(sbTag.length() - 1); - - return String.format(CREATE_STABLE_INE_TPL, tbName, fieldFrag, sbTag); - - } - - /** - * 获取创建普通表sql - */ - public static String getCreateCTableSql(String tbName, List fields) { - if (fields.size() == 0) { - return null; - } - - //生成字段片段 - StringBuilder sbField = new StringBuilder("time timestamp,"); - - for (TdFieldDO field : fields) { - sbField.append(FieldParser.getFieldDefine(field)); - sbField.append(","); - } - sbField.deleteCharAt(sbField.length() - 1); - - String fieldFrag = sbField.toString(); - - return String.format(CREATE_CTABLE_INE_TPL, tbName, fieldFrag); - - } - - - /** - * 取正确的表名 - * - * @param name 表象 - */ - public static String rightTbName(String name) { - return name.toLowerCase().replace("-" , "_"); - } - - /** - * 获取表详情的sql - */ - public static String getDescTableSql(String tbName) { - return String.format(DESC_TB_TPL, tbName); - } - - /** - * 获取添加字段sql - */ - public static String getAddSTableColumnSql(String tbName, List fields) { - StringBuilder sbAdd = new StringBuilder(); - for (TdFieldDO field : fields) { - sbAdd.append(String.format(ALTER_STABLE_ADD_COL_TPL, - tbName, - FieldParser.getFieldDefine(field) - )); - } - return sbAdd.toString(); - } - - /** - * 获取修改字段sql - */ - public static String getModifySTableColumnSql(String tbName, List fields) { - StringBuilder sbModify = new StringBuilder(); - for (TdFieldDO field : fields) { - sbModify.append(String.format(ALTER_STABLE_MODIFY_COL_TPL, - tbName, - FieldParser.getFieldDefine(field) - )); - } - return sbModify.toString(); - } - - /** - * 获取删除字段sql - */ - public static String getDropSTableColumnSql(String tbName, List fields) { - StringBuilder sbDrop = new StringBuilder(); - for (TdFieldDO field : fields) { - sbDrop.append(String.format(ALTER_STABLE_DROP_COL_TPL, - tbName, - field.getFieldName() - )); - } - return sbDrop.toString(); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineSuperTableMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java similarity index 68% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineSuperTableMapper.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java index e688563d5..640255940 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineSuperTableMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java @@ -1,19 +1,30 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; /** - * TD 引擎的超级表 Mapper + * 专门处理 DDL(数据定义语言)操作,包含所有的数据库和表的定义操作,例如创建数据库、创建超级表、创建子表等 */ @Mapper @DS("tdengine") -public interface TdEngineSuperTableMapper { +public interface TdEngineDDLMapper { + + /** + * 创建数据库 + * SQL:CREATE DATABASE [IF NOT EXISTS] db_name [database_options]; + * + * @param dataBaseName 数据库名称 + */ + @TenantIgnore + void createDatabase(@Param("dataBaseName") String dataBaseName); /** * 创建超级表 @@ -25,7 +36,7 @@ public interface TdEngineSuperTableMapper { * columns 列信息 * tags 标签信息 */ - @InterceptorIgnore(tenantLine = "true") + @TenantIgnore void createSuperTable(TdTableDO superTable); /** @@ -36,7 +47,7 @@ public interface TdEngineSuperTableMapper { * dataBaseName 数据库名称 * superTableName 超级表名称 */ - @InterceptorIgnore(tenantLine = "true") + @TenantIgnore List> showSuperTables(TdTableDO superTable); /** @@ -47,7 +58,7 @@ public interface TdEngineSuperTableMapper { * dataBaseName 数据库名称 * superTableName 超级表名称 */ - @InterceptorIgnore(tenantLine = "true") + @TenantIgnore List> describeSuperTable(TdTableDO superTable); /** @@ -59,7 +70,7 @@ public interface TdEngineSuperTableMapper { * superTableName 超级表名称 * column 列信息 */ - @InterceptorIgnore(tenantLine = "true") + @TenantIgnore void addColumnForSuperTable(TdTableDO superTable); /** @@ -71,7 +82,7 @@ public interface TdEngineSuperTableMapper { * superTableName 超级表名称 * column 列信息 */ - @InterceptorIgnore(tenantLine = "true") + @TenantIgnore void dropColumnForSuperTable(TdTableDO superTable); /** @@ -83,7 +94,7 @@ public interface TdEngineSuperTableMapper { * superTableName 超级表名称 * column 列信息 */ - @InterceptorIgnore(tenantLine = "true") + @TenantIgnore void modifyColumnWidthForSuperTable(TdTableDO superTable); @@ -95,7 +106,7 @@ public interface TdEngineSuperTableMapper { * superTableName 超级表名称 * tag 标签信息 */ - @InterceptorIgnore(tenantLine = "true") + @TenantIgnore void addTagForSuperTable(TdTableDO superTable); /** @@ -106,6 +117,33 @@ public interface TdEngineSuperTableMapper { * superTableName 超级表名称 * tag 标签信息 */ - @InterceptorIgnore(tenantLine = "true") + @TenantIgnore void dropTagForSuperTable(TdTableDO superTable); -} \ No newline at end of file + + /** + * 创建子表 - 创建子表 + * SQL:CREATE TABLE [IF NOT EXISTS] tb_name USING stb_name TAGS (tag_value1, ...); + * + * @param table 表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * tableName 子表名称 + * tags TAG 字段 + */ + @TenantIgnore + void createTable(TdTableDO table); + + /** + * 创建子表 - 创建子表并指定标签的值 + * SQL:CREATE TABLE [IF NOT EXISTS] tb_name USING stb_name (tag_name1, ...) TAGS (tag_value1, ...); + * + * @param table 表信息 + * dataBaseName 数据库名称 + * superTableName 超级表名称 + * tableName 子表名称 + * tags TAG 字段 + */ + @TenantIgnore + void createTableWithTags(TdTableDO table); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDMLMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDMLMapper.java new file mode 100644 index 000000000..12b2c232c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDMLMapper.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TagsSelectDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import com.baomidou.dynamic.datasource.annotation.DS; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Map; + +/** + * 专门处理 TD Engine 的 DML(数据操作语言)操作,处理所有的数据查询和写入操作,如插入数据、查询数据等 + */ +@Mapper +@DS("tdengine") +public interface TdEngineDMLMapper { + + /** + * 插入数据 - 指定列插入数据 + * + * @param table 数据 + * dataBaseName 数据库名 + * tableName 表名 + * columns 列 + */ + @TenantIgnore + void insertData(TdTableDO table); + + /** + * 根据时间戳查询数据 + * + * @param selectDO 查询条件 + * @return 查询结果列表 + */ + @TenantIgnore + List> selectByTimestamp(SelectDO selectDO); + + /** + * 根据时间戳获取数据条数 + * + * @param selectDO 查询条件 + * @return 数据条数 + */ + @TenantIgnore + Map selectCountByTimestamp(SelectDO selectDO); + + /** + * 获取最新数据 + * + * @param selectDO 查询条件 + * @return 最新数据 + */ + @TenantIgnore + Map selectOneLastData(SelectDO selectDO); + + /** + * 获取历史数据列表 + * + * @param selectVisualDO 查询条件 + * @return 历史数据列表 + */ + @TenantIgnore + List> selectHistoryDataList(SelectVisualDO selectVisualDO); + + /** + * 获取实时数据列表 + * + * @param selectVisualDO 查询条件 + * @return 实时数据列表 + */ + @TenantIgnore + List> selectRealtimeDataList(SelectVisualDO selectVisualDO); + + /** + * 获取聚合数据列表 + * + * @param selectVisualDO 查询条件 + * @return 聚合数据列表 + */ + @TenantIgnore + List> selectAggregateDataList(SelectVisualDO selectVisualDO); + + /** + * 根据标签获取最新数据列表 + * + * @param tagsSelectDO 查询条件 + * @return 最新数据列表 + */ + @TenantIgnore + List> selectLastDataListByTags(TagsSelectDO tagsSelectDO); + + /** + * 获取历史数据条数 + * + * @param selectVisualDO 查询条件 + * @return 数据条数 + */ + @TenantIgnore + Long selectHistoryCount(SelectVisualDO selectVisualDO); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDataWriterMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDataWriterMapper.java deleted file mode 100644 index 51f4229a0..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDataWriterMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import com.baomidou.dynamic.datasource.annotation.DS; -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import org.apache.ibatis.annotations.Mapper; - -/** - * TD 引擎的数据写入 Mapper - */ -@Mapper -@DS("tdengine") -public interface TdEngineDataWriterMapper { - - /** - * 插入数据 - 指定列插入数据 - * - * @param table 数据 - * dataBaseName 数据库名 - * tableName 表名 - * columns 列 - */ - @InterceptorIgnore(tenantLine = "true") - void insertData(TdTableDO table); -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java deleted file mode 100644 index cd3eaa8b9..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDatabaseMapper.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.tdengine; - -import com.baomidou.dynamic.datasource.annotation.DS; -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -// TODO @haohao:InterceptorIgnore 忽略租户,可以在每个方法上,添加 @TenantIgnore 哈。 -/** - * TD 引擎的数据库 Mapper - */ -@Mapper -@DS("tdengine") -public interface TdEngineDatabaseMapper { - - /** - * 创建数据库 - * SQL:CREATE DATABASE [IF NOT EXISTS] db_name [database_options]; - * - * @param dataBaseName 数据库名称 - */ - @InterceptorIgnore(tenantLine = "true") - void createDatabase(@Param("dataBaseName") String dataBaseName); -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java deleted file mode 100644 index a2408e335..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineQueryMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TagsSelectDO; -import com.baomidou.dynamic.datasource.annotation.DS; -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; -import java.util.Map; - -/** - * TD 引擎的查询 Mapper - */ -@Mapper -@DS("tdengine") -public interface TdEngineQueryMapper { - - /** - * 根据时间戳查询数据 - * - * @param selectDO 查询条件 - * @return 查询结果 - */ - List> selectByTimestamp(SelectDO selectDO); - - // TODO @haohao:最好方法的命名,和数据库操作的保持一直。get => select。然后 selectList or selectOne - /** - * 根据时间戳获取数据条数 - * - * @param selectDO 查询条件 - * @return 数据条数 - */ - Map getCountByTimestamp(SelectDO selectDO); - - /** - * 获取最新数据 - * - * @param selectDO 查询条件 - * @return 最新数据 - */ - Map getLastData(SelectDO selectDO); - - /** - * 获取历史数据 - * - * @param selectVisualDO 查询条件 - * @return 历史数据列表 - */ - @InterceptorIgnore(tenantLine = "true") - List> getHistoryData(SelectVisualDO selectVisualDO); - - /** - * 获取实时数据 - * - * @param selectVisualDO 查询条件 - * @return 实时数据列表 - */ - List> getRealtimeData(SelectVisualDO selectVisualDO); - - /** - * 获取聚合数据 - * - * @param selectVisualDO 查询条件 - * @return 聚合数据列表 - */ - List> getAggregateData(SelectVisualDO selectVisualDO); - - /** - * 根据标签获取最新数据 - * - * @param tagsSelectDO 查询条件 - * @return 最新数据列表 - */ - List> getLastDataByTags(TagsSelectDO tagsSelectDO); - - /** - * 获取历史数据条数 - * - * @param selectVisualDO 查询条件 - * @return 数据条数 - */ - @InterceptorIgnore(tenantLine = "true") - Long getHistoryCount(SelectVisualDO selectVisualDO); -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineTableMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineTableMapper.java deleted file mode 100644 index 72517bcab..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineTableMapper.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import com.baomidou.dynamic.datasource.annotation.DS; -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import org.apache.ibatis.annotations.Mapper; - -/** - * TD 引擎的表 Mapper - */ -@Mapper -@DS("tdengine") -public interface TdEngineTableMapper { - - /** - * 创建子表 - 创建子表 - * SQL:CREATE TABLE [IF NOT EXISTS] tb_name USING stb_name TAGS (tag_value1, ...); - * - * @param table 表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * tableName 子表名称 - * tags TAG 字段 - */ - @InterceptorIgnore(tenantLine = "true") - void createTable(TdTableDO table); - - /** - * 创建子表 - 创建子表并指定标签的值 - * SQL:CREATE TABLE [IF NOT EXISTS] tb_name USING stb_name (tag_name1, ...) TAGS (tag_value1, ...); - * - * @param table 表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * tableName 子表名称 - * tags TAG 字段 - */ - @InterceptorIgnore(tenantLine = "true") - void createTableWithTags(TdTableDO table); - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index 96181fd26..4f390ca3b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import jakarta.validation.Valid; @@ -31,7 +31,7 @@ public interface IotDeviceDataService { * @param deviceId 设备编号 * @return 设备属性最新数据 */ - List getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceId); + List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceId); /** * 获得设备属性历史数据 @@ -39,5 +39,5 @@ public interface IotDeviceDataService { * @param deviceDataReqVO 设备属性历史数据 Request VO * @return 设备属性历史数据 */ - PageResult> getDevicePropertiesHistoryData(@Valid IotDeviceDataReqVO deviceDataReqVO); + PageResult> getHistoryDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 8f68989c9..7d10977f9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -1,18 +1,20 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; +import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; -import cn.iocoder.yudao.module.iot.service.tdengine.TdEngineQueryService; import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import jakarta.annotation.Resource; import jakarta.validation.Valid; @@ -40,7 +42,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { @Resource private IotThinkModelFunctionService thinkModelFunctionService; @Resource - private TdEngineQueryService tdEngineQueryService; + private TdEngineDMLMapper tdEngineDMLMapper; @Resource private DeviceDataRedisDAO deviceDataRedisDAO; @@ -66,7 +68,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { } @Override - public List getDevicePropertiesLatestData(@Valid IotDeviceDataReqVO deviceDataReqVO) { + public List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { List list = new ArrayList<>(); // 1. 获取设备信息 IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); @@ -106,7 +108,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { } @Override - public PageResult> getDevicePropertiesHistoryData(IotDeviceDataReqVO deviceDataReqVO) { + public PageResult> getHistoryDeviceProperties(IotDeviceDataPageReqVO deviceDataReqVO) { PageResult> pageResult = new PageResult<>(); // 1. 获取设备信息 IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); @@ -121,17 +123,17 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { params.put("rows", deviceDataReqVO.getPageSize()); params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); selectVisualDO.setParams(params); - pageResult.setList(tdEngineQueryService.getHistoryData(selectVisualDO)); - pageResult.setTotal(tdEngineQueryService.getHistoryCount(selectVisualDO)); + pageResult.setList(tdEngineDMLMapper.selectHistoryDataList(selectVisualDO)); + pageResult.setTotal(tdEngineDMLMapper.selectHistoryCount(selectVisualDO)); return pageResult; } private String getDatabaseName() { - return url.substring(url.lastIndexOf("/") + 1); + return StrUtil.subAfter(url, "/", true); } private static String getDeviceTableName(String productKey, String deviceName) { - return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase()); + return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey, deviceName); } -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 0ec737a30..58918c130 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -19,7 +19,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.security.SecureRandom; import java.time.LocalDateTime; +import java.util.Base64; import java.util.Objects; import java.util.UUID; @@ -137,10 +139,13 @@ public class IotDeviceServiceImpl implements IotDeviceService { * @return 生成的 MQTT Password */ private String generateMqttPassword() { - // TODO @haohao:【后续优化】在实际应用中,建议使用更安全的方法生成 MQTT Password,如加密或哈希 - return UUID.randomUUID().toString(); + SecureRandom secureRandom = new SecureRandom(); + byte[] passwordBytes = new byte[32]; // 256 位的随机数 + secureRandom.nextBytes(passwordBytes); + return Base64.getUrlEncoder().withoutPadding().encodeToString(passwordBytes); } + /** * 生成唯一的 DeviceName * @@ -214,30 +219,28 @@ public class IotDeviceServiceImpl implements IotDeviceService { @Override public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) { // 1. 校验存在 - // TODO @haohao:这里的 iotDeviceDO => device。一个是去掉 iot,一个是去掉 DO 后缀。这样,简洁一点。 - IotDeviceDO iotDeviceDO = validateDeviceExists(updateReqVO.getId()); + IotDeviceDO device = validateDeviceExists(updateReqVO.getId()); // 2.1 更新状态和更新时间 - IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); - // TODO @haohao:下面几个状态的处理,可以考虑 if else if。这样,看起来会有层次感哈 - // 2.2.1 以前是未激活,现在是上线,设置设备激活时间 - // TODO @haohao:这里可以使用 ObjectUtils.equalsAny 类似这种哈。 - if (Objects.equals(iotDeviceDO.getStatus(), IotDeviceStatusEnum.INACTIVE.getStatus()) - && Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { - updateObj.setActiveTime(LocalDateTime.now()); - } - // 2.2.2 如果是上线,设置上线时间 - if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { - updateObj.setLastOnlineTime(LocalDateTime.now()); - } - // 2.2.3 如果是离线,设置离线时间 - if (Objects.equals(updateObj.getStatus(), IotDeviceStatusEnum.OFFLINE.getStatus())) { - updateObj.setLastOfflineTime(LocalDateTime.now()); + IotDeviceDO updateDevice = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); + // 2.2 更新状态相关时间 + if (Objects.equals(device.getStatus(), IotDeviceStatusEnum.INACTIVE.getStatus()) + && Objects.equals(updateDevice.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { + // 从未激活到在线,设置激活时间和最后上线时间 + updateDevice.setActiveTime(LocalDateTime.now()); + updateDevice.setLastOnlineTime(LocalDateTime.now()); + } else if (Objects.equals(updateDevice.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { + // 如果是上线,设置最后上线时间 + updateDevice.setLastOnlineTime(LocalDateTime.now()); + } else if (Objects.equals(updateDevice.getStatus(), IotDeviceStatusEnum.OFFLINE.getStatus())) { + // 如果是离线,设置最后离线时间 + updateDevice.setLastOfflineTime(LocalDateTime.now()); } + // 2.3 设置状态更新时间 - updateObj.setStatusLastUpdateTime(LocalDateTime.now()); + updateDevice.setStatusLastUpdateTime(LocalDateTime.now()); // 2.4 更新到数据库 - deviceMapper.updateById(updateObj); + deviceMapper.updateById(updateDevice); } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java index 7c88b83aa..8aec32f32 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java @@ -15,4 +15,4 @@ public interface IotSuperTableService { * 创建超级表数据模型 */ void createSuperTableDataModel(IotProductDO product, List functionList); -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java index 3be324c4e..20989181e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java @@ -9,6 +9,8 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -26,7 +28,7 @@ import java.util.stream.Collectors; public class IotSuperTableServiceImpl implements IotSuperTableService { @Resource - private TdEngineSuperTableService tdEngineSuperTableService; + private TdEngineDDLMapper tdEngineDDLMapper; @Value("${spring.datasource.dynamic.datasource.tdengine.url}") private String url; @@ -42,9 +44,10 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { String superTableName = getSuperTableName(product.getDeviceType(), product.getProductKey()); String databaseName = getDatabaseName(); - Integer tableExists = tdEngineSuperTableService.checkSuperTableExists(new TdTableDO(databaseName, superTableName)); - if (tableExists != null && tableExists > 0) { + List> results = tdEngineDDLMapper.showSuperTables(new TdTableDO(databaseName, superTableName)); + int tableExists = results == null || results.isEmpty() ? 0 : results.size(); + if (tableExists > 0) { updateSuperTable(thingModel, product.getDeviceType()); } else { createSuperTable(thingModel, product.getDeviceType()); @@ -76,7 +79,7 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { String databaseName = getDatabaseName(); // 创建超级表 - tdEngineSuperTableService.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); + tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); } /** @@ -98,7 +101,7 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { * 获取表的字段信息 */ private List getTableFields(String tableName) { - List> tableDescription = tdEngineSuperTableService.describeSuperTable(new TdTableDO(getDatabaseName(), tableName)); + List> tableDescription = tdEngineDDLMapper.describeSuperTable(new TdTableDO(getDatabaseName(), tableName)); if (CollUtil.isEmpty(tableDescription)) { return Collections.emptyList(); } @@ -127,32 +130,38 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { // 添加新增字段 if (CollUtil.isNotEmpty(addFields)) { - tdEngineSuperTableService.addColumnsForSuperTable(TdTableDO.builder() - .dataBaseName(databaseName) - .superTableName(tableName) - .columns(addFields) - .build()); + for (TdFieldDO addField : addFields) { + tdEngineDDLMapper.addColumnForSuperTable(TdTableDO.builder() + .dataBaseName(databaseName) + .superTableName(tableName) + .column(addField) + .build()); + } } // 删除旧字段 if (CollUtil.isNotEmpty(dropFields)) { - tdEngineSuperTableService.dropColumnsForSuperTable(TdTableDO.builder() - .dataBaseName(databaseName) - .superTableName(tableName) - .columns(dropFields) - .build()); + for (TdFieldDO dropField : dropFields) { + tdEngineDDLMapper.dropColumnForSuperTable(TdTableDO.builder() + .dataBaseName(databaseName) + .superTableName(tableName) + .column(dropField) + .build()); + } } // 修改字段(先删除再添加) if (CollUtil.isNotEmpty(modifyFields)) { - tdEngineSuperTableService.dropColumnsForSuperTable(TdTableDO.builder() - .dataBaseName(databaseName) - .superTableName(tableName) - .columns(modifyFields) - .build()); - tdEngineSuperTableService.addColumnsForSuperTable(TdTableDO.builder() - .dataBaseName(databaseName) - .superTableName(tableName) - .columns(addFields) - .build()); + for (TdFieldDO modifyField : modifyFields) { + tdEngineDDLMapper.dropColumnForSuperTable(TdTableDO.builder() + .dataBaseName(databaseName) + .superTableName(tableName) + .column(modifyField) + .build()); + tdEngineDDLMapper.addColumnForSuperTable(TdTableDO.builder() + .dataBaseName(databaseName) + .superTableName(tableName) + .column(modifyField) + .build()); + } } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 280b32d9a..92a30ebb0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -11,6 +13,9 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; +import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; @@ -30,6 +35,14 @@ import java.util.stream.Collectors; @Service public class IotThingModelMessageServiceImpl implements IotThingModelMessageService { + private static final String TAG_NOTE = "TAG"; + private static final String NOTE = "note"; + private static final String TIME = "time"; + private static final String DEVICE_KEY = "device_key"; + private static final String DEVICE_NAME = "device_name"; + private static final String PRODUCT_KEY = "product_key"; + private static final String DEVICE_TYPE = "device_type"; + @Value("${spring.datasource.dynamic.datasource.tdengine.url}") private String url; @@ -38,11 +51,9 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Resource private IotDeviceService iotDeviceService; @Resource - private TdEngineTableService tdEngineTableService; + private TdEngineDDLMapper tdEngineDDLMapper; @Resource - private TdEngineSuperTableService tdEngineSuperTableService; - @Resource - private TdEngineDataWriterService tdEngineDataWriterService; + private TdEngineDMLMapper tdEngineDMLMapper; @Resource private DeviceDataRedisDAO deviceDataRedisDAO; @@ -51,62 +62,64 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Override @TenantIgnore public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) { - // 判断设备状态,如果为未激活状态,创建数据表 + // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { - // 创建设备数据表 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); - // 更新设备状态 - // TODO @haohao:下面可以考虑,链式调用。iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO().setid().setstatus()) - IotDeviceStatusUpdateReqVO updateReqVO = new IotDeviceStatusUpdateReqVO(); - updateReqVO.setId(device.getId()); - updateReqVO.setStatus(IotDeviceStatusEnum.ONLINE.getStatus()); - iotDeviceService.updateDeviceStatus(updateReqVO); + iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() + .setId(device.getId()) + .setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); } - // TODO @haohao:这个变量,可以和 “过滤并收集有效的属性字段” 那块,因为关联度高一点。 - // 获取设备属性 + // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 Map params = thingModelMessage.dataToMap(); - - // 物模型校验,过滤非物模型属性 - List functionList = iotThinkModelFunctionService - .getThinkModelFunctionListByProductKey(thingModelMessage.getProductKey()) - .stream() - .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType().equals(function.getType())) - .toList(); + List functionList = getValidFunctionList(thingModelMessage.getProductKey()); if (functionList.isEmpty()) { return; } - // 获取属性标识符集合 - // TODO @haohao:这个变量,可以和 “过滤并收集有效的属性字段” 那块,因为关联度高一点。另外,可以使用 CollectionUtils。convertSet - Set propertyIdentifiers = functionList.stream() - .map(IotThinkModelFunctionDO::getIdentifier) - .collect(Collectors.toSet()); + // 3. 过滤并收集有效的属性字段,缓存设备属性 + List schemaFieldValues = filterAndCollectValidFields(params, functionList, device, thingModelMessage.getTime()); + if (schemaFieldValues.size() == 1) { // 仅有时间字段,无需保存 + return; + } + + // 4. 构建并保存设备属性数据 + tdEngineDMLMapper.insertData(TdTableDO.builder() + .dataBaseName(getDatabaseName()) + .tableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())) + .columns(schemaFieldValues) + .build()); + } + + private List getValidFunctionList(String productKey) { + return iotThinkModelFunctionService + .getThinkModelFunctionListByProductKey(productKey) + .stream() + .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType().equals(function.getType())) + .toList(); + } + + private List filterAndCollectValidFields(Map params, List functionList, IotDeviceDO device, Long time) { + // 1. 获取属性标识符集合 + Set propertyIdentifiers = CollectionUtils.convertSet(functionList, IotThinkModelFunctionDO::getIdentifier); + + // 2. 构建属性标识符和属性的映射 Map functionMap = functionList.stream() .collect(Collectors.toMap(IotThinkModelFunctionDO::getIdentifier, function -> function)); - // 过滤并收集有效的属性字段 + // 3. 过滤并收集有效的属性字段 List schemaFieldValues = new ArrayList<>(); - schemaFieldValues.add(new TdFieldDO("time", thingModelMessage.getTime())); + schemaFieldValues.add(new TdFieldDO(TIME, time)); params.forEach((key, val) -> { if (propertyIdentifiers.contains(key)) { schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val)); // 缓存设备属性 // TODO @haohao:这个缓存的写入,可以使用的时候 cache 么?被动读 - setDeviceDataCache(device, functionMap.get(key), val, thingModelMessage.getTime()); + setDeviceDataCache(device, functionMap.get(key), val, time); } }); - // TODO @haohao:疑问,为什么 1 不继续哈? - if (schemaFieldValues.size() == 1) { - return; - } - - // 构建并保存设备属性数据 - tdEngineDataWriterService.insertData(TdTableDO.builder().build() - .setDataBaseName(getDatabaseName()) - .setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())) - .setColumns(schemaFieldValues)); + return schemaFieldValues; } /** @@ -132,7 +145,6 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ deviceDataRedisDAO.set(deviceData); } - // TODO @haohao:实现没问题哈。这个方法的空行有点多,逻辑分块上没这么明显。看看能不能改下。 /** * 创建设备数据表 * @@ -142,36 +154,37 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * @param deviceKey 设备 Key */ private void createDeviceTable(Integer deviceType, String productKey, String deviceName, String deviceKey) { + // 1. 获取超级表名和数据库名 String superTableName = getProductPropertySTableName(deviceType, productKey); String dataBaseName = getDatabaseName(); - List> maps = tdEngineSuperTableService.describeSuperTable(new TdTableDO(dataBaseName, superTableName)); + // 2. 获取超级表的结构信息 + List> maps = tdEngineDDLMapper.describeSuperTable(new TdTableDO(dataBaseName, superTableName)); List tagsFieldValues = new ArrayList<>(); - if (maps != null) { - // TODO @haohao:一些字符串,是不是可以枚举起来哈。 - // TODO @haohao:这种过滤的,常用的,可以考虑用 CollectionUtils.filterList。一些常用的 stream 操作,适合封装哈 - List> taggedNotesList = maps.stream() - .filter(map -> "TAG".equals(map.get("note"))) - .toList(); + // 2.1 过滤出 TAG 类型的字段 + List> taggedNotesList = CollectionUtils.filterList(maps, map -> TAG_NOTE.equals(map.get(NOTE))); + + // 2.2 解析字段信息 tagsFieldValues = FieldParser.parse(taggedNotesList.stream() .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) .collect(Collectors.toList())); + // 2.3 设置 TAG 字段的值 for (TdFieldDO tagsFieldValue : tagsFieldValues) { switch (tagsFieldValue.getFieldName()) { - case "product_key" -> tagsFieldValue.setFieldValue(productKey); - case "device_key" -> tagsFieldValue.setFieldValue(deviceKey); - case "device_name" -> tagsFieldValue.setFieldValue(deviceName); - case "device_type" -> tagsFieldValue.setFieldValue(deviceType); + case PRODUCT_KEY -> tagsFieldValue.setFieldValue(productKey); + case DEVICE_KEY -> tagsFieldValue.setFieldValue(deviceKey); + case DEVICE_NAME -> tagsFieldValue.setFieldValue(deviceName); + case DEVICE_TYPE -> tagsFieldValue.setFieldValue(deviceType); } } } - // 创建设备数据表 + // 3. 创建设备数据表 String tableName = getDeviceTableName(productKey, deviceName); - tdEngineTableService.createTable(TdTableDO.builder().build() + tdEngineDDLMapper.createTable(TdTableDO.builder().build() .setDataBaseName(dataBaseName) .setSuperTableName(superTableName) .setTableName(tableName) @@ -184,8 +197,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * @return 数据库名称 */ private String getDatabaseName() { - // TODO @haohao:可以使用 StrUtil.subAftetLast 这种方法 - return url.substring(url.lastIndexOf("/") + 1); + return StrUtil.subAfter(url, "/", true); } /** @@ -198,9 +210,9 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ private static String getProductPropertySTableName(Integer deviceType, String productKey) { // TODO @haohao:枚举下,会好点哈。 return switch (deviceType) { - case 1 -> String.format("gateway_sub_%s", productKey).toLowerCase(); - case 2 -> String.format("gateway_%s", productKey).toLowerCase(); - default -> String.format("device_%s", productKey).toLowerCase(); + case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); + case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); + default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); }; } @@ -212,7 +224,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * @return 设备表名 */ private static String getDeviceTableName(String productKey, String deviceName) { - return String.format("device_%s_%s", productKey.toLowerCase(), deviceName.toLowerCase()); + return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterService.java deleted file mode 100644 index 0995b0797..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterService.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; - -/** - * TD 引擎的数据写入 Service 接口 - */ -public interface TdEngineDataWriterService { - - /** - * 插入数据 - 指定列插入数据 - * - * @param table 数据 - * dataBaseName 数据库名 - * tableName 表名 - * columns 列 - */ - void insertData(TdTableDO table); -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterServiceImpl.java deleted file mode 100644 index f4dd2c8fd..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDataWriterServiceImpl.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDataWriterMapper; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; - -/** - * TD 引擎的数据写入 Service 实现类 - */ -@Service -public class TdEngineDataWriterServiceImpl implements TdEngineDataWriterService { - - @Resource - private TdEngineDataWriterMapper tdEngineDataWriterMapper; - - @Override - public void insertData(TdTableDO table) { - tdEngineDataWriterMapper.insertData(table); - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseService.java deleted file mode 100644 index d895262cc..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseService.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -/** - * TD 引擎的数据库 Service 接口 - */ -public interface TdEngineDatabaseService { - - /** - * 创建数据库 - * - * @param dataBaseName 数据库名称 - */ - void createDatabase(String dataBaseName); -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseServiceImpl.java deleted file mode 100644 index c880db8a9..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineDatabaseServiceImpl.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDatabaseMapper; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -/** - * TD 引擎的数据库 Service 实现类 - */ -@Service -@Slf4j -public class TdEngineDatabaseServiceImpl implements TdEngineDatabaseService { - - @Resource - private TdEngineDatabaseMapper tdEngineDatabaseMapper; - - @Override - public void createDatabase(String dataBaseName) { - tdEngineDatabaseMapper.createDatabase(dataBaseName); - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryService.java deleted file mode 100644 index 8d07b4334..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryService.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; - -import java.util.List; -import java.util.Map; - -/** - * TD 引擎的查询 Service 接口 - */ -public interface TdEngineQueryService { - - /** - * 获取历史数据 - * - * @param selectVisualDO 查询条件 - * @return 历史数据列表 - */ - List> getHistoryData(SelectVisualDO selectVisualDO); - - /** - * 获取历史数据条数 - * - * @param selectVisualDO 查询条件 - * @return 数据条数 - */ - Long getHistoryCount(SelectVisualDO selectVisualDO); -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryServiceImpl.java deleted file mode 100644 index 672a58640..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineQueryServiceImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineQueryMapper; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Map; - -@Service -public class TdEngineQueryServiceImpl implements TdEngineQueryService { - - @Resource - private TdEngineQueryMapper tdEngineQueryMapper; - - @Override - public List> getHistoryData(SelectVisualDO selectVisualDO) { - return tdEngineQueryMapper.getHistoryData(selectVisualDO); - } - - @Override - public Long getHistoryCount(SelectVisualDO selectVisualDO) { - return tdEngineQueryMapper.getHistoryCount(selectVisualDO); - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableService.java deleted file mode 100644 index df6290a98..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableService.java +++ /dev/null @@ -1,123 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; - -import java.util.List; -import java.util.Map; - -/** - * TD 引擎的超级表 Service 接口 - */ -public interface TdEngineSuperTableService { - - /** - * 创建超级表 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * columns 列信息 - * tags 标签信息 - */ - void createSuperTable(TdTableDO superTable); - - /** - * 查看超级表 - 显示当前数据库下的所有超级表信息 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - */ - - List> showSuperTables(TdTableDO superTable); - - /** - * 查看超级表 - 获取超级表的结构信息 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - */ - List> describeSuperTable(TdTableDO superTable); - - /** - * 修改超级表 - 增加列 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * column 列信息 - */ - void addColumnForSuperTable(TdTableDO superTable); - - /** - * 修改超级表 - 删除列 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * column 列信息 - */ - void dropColumnForSuperTable(TdTableDO superTable); - - /** - * 修改超级表 - 修改列宽 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * column 列信息 - */ - void modifyColumnWidthForSuperTable(TdTableDO superTable); - - - /** - * 修改超级表 - 为超级表添加标签 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * tag 标签信息 - */ - void addTagForSuperTable(TdTableDO superTable); - - /** - * 修改超级表 - 为超级表删除标签 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * tag 标签信息 - */ - void dropTagForSuperTable(TdTableDO superTable); - - /** - * 检查超级表是否存在 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * @return 超级表数量 - */ - Integer checkSuperTableExists(TdTableDO superTable); - - /** - * 为超级表添加列 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * columns 列信息 - */ - void addColumnsForSuperTable(TdTableDO superTable); - - /** - * 为超级表删除列 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * columns 列信息 - */ - void dropColumnsForSuperTable(TdTableDO superTable); -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableServiceImpl.java deleted file mode 100644 index 60436e7bd..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineSuperTableServiceImpl.java +++ /dev/null @@ -1,90 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineSuperTableMapper; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Map; - -/** - * TD 引擎的超级表 Service 实现类 - */ -@Slf4j -@Service -public class TdEngineSuperTableServiceImpl implements TdEngineSuperTableService { - - @Resource - private TdEngineSuperTableMapper tdEngineSuperTableMapper; - - @Override - public void createSuperTable(TdTableDO superTable) { - tdEngineSuperTableMapper.createSuperTable(superTable); - } - - @Override - public List> showSuperTables(TdTableDO superTable) { - return tdEngineSuperTableMapper.showSuperTables(superTable); - } - - @Override - public List> describeSuperTable(TdTableDO superTable) { - return tdEngineSuperTableMapper.describeSuperTable(superTable); - } - - @Override - public void addColumnForSuperTable(TdTableDO superTable) { - tdEngineSuperTableMapper.addColumnForSuperTable(superTable); - } - - @Override - public void dropColumnForSuperTable(TdTableDO superTable) { - tdEngineSuperTableMapper.dropColumnForSuperTable(superTable); - } - - @Override - public void modifyColumnWidthForSuperTable(TdTableDO superTable) { - tdEngineSuperTableMapper.modifyColumnWidthForSuperTable(superTable); - } - - @Override - public void addTagForSuperTable(TdTableDO superTable) { - tdEngineSuperTableMapper.addTagForSuperTable(superTable); - } - - @Override - public void dropTagForSuperTable(TdTableDO superTable) { - tdEngineSuperTableMapper.dropTagForSuperTable(superTable); - } - - @Override - public Integer checkSuperTableExists(TdTableDO superTable) { - List> results = tdEngineSuperTableMapper.showSuperTables(superTable); - return results == null || results.isEmpty() ? 0 : results.size(); - } - - @Override - public void addColumnsForSuperTable(TdTableDO superTable) { - for (TdFieldDO column : superTable.getColumns()) { - tdEngineSuperTableMapper.addColumnForSuperTable(TdTableDO.builder() - .dataBaseName(superTable.getDataBaseName()) - .superTableName(superTable.getSuperTableName()) - .column(column) - .build()); - } - } - - @Override - public void dropColumnsForSuperTable(TdTableDO superTable) { - for (TdFieldDO column : superTable.getColumns()) { - tdEngineSuperTableMapper.dropColumnForSuperTable(TdTableDO.builder() - .dataBaseName(superTable.getDataBaseName()) - .superTableName(superTable.getSuperTableName()) - .column(column) - .build()); - } - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableService.java deleted file mode 100644 index 078159784..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableService.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; - -/** - * TD 引擎的表 Service 接口 - */ -public interface TdEngineTableService { - - /** - * 创建表 - 创建超级表的子表 - * - * @param table 表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * tableName 子表名称 - * tags TAG 字段 - */ - void createTable(TdTableDO table); - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableServiceImpl.java deleted file mode 100644 index cdca47888..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/TdEngineTableServiceImpl.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineTableMapper; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -/** - * TD 引擎的表 Service 实现类 - */ -@Slf4j -@Service -public class TdEngineTableServiceImpl implements TdEngineTableService { - - @Resource - private TdEngineTableMapper tdEngineTableMapper; - - @Override - public void createTable(TdTableDO table) { - tdEngineTableMapper.createTable(table); - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDDLMapper.xml similarity index 70% rename from yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml rename to yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDDLMapper.xml index 37cf71910..091b77f64 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineSuperTableMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDDLMapper.xml @@ -2,7 +2,12 @@ - + + + + + CREATE DATABASE IF NOT EXISTS ${dataBaseName} + @@ -68,4 +73,29 @@ ALTER STABLE ${dataBaseName}.${superTableName} DROP TAG ${tag.fieldName} - + + + CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} + USING ${dataBaseName}.${superTableName} + TAGS + + #{item.fieldValue} + + + + + + CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} + USING ${dataBaseName}.${superTableName} + + #{item.fieldName} + + TAGS + + #{item.fieldValue} + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml similarity index 68% rename from yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml rename to yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml index f4361bc67..0443a826b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineQueryMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml @@ -2,7 +2,21 @@ - + + + + + INSERT INTO ${dataBaseName}.${tableName} + + ${item.fieldName} + + VALUES + + #{item.fieldValue} + + SELECT COUNT(0) AS count FROM ${dataBaseName}.${tableName} @@ -20,14 +34,14 @@ - SELECT LAST(time), * FROM ${tableName} WHERE device_id = #{deviceId} - - - - - SELECT COUNT(time) FROM ${dataBaseName}.${tableName} WHERE time BETWEEN #{startTime} AND #{endTime} AND ${fieldName} IS NOT NULL - + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml deleted file mode 100644 index dd38cd08e..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDataWriterMapper.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - INSERT INTO ${dataBaseName}.${tableName} - - ${item.fieldName} - - VALUES - - #{item.fieldValue} - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml deleted file mode 100644 index 919c301f7..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDatabaseMapper.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - CREATE DATABASE IF NOT EXISTS ${dataBaseName} - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml deleted file mode 100644 index 867ef8f43..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineTableMapper.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} - USING ${dataBaseName}.${superTableName} - TAGS - - #{item.fieldValue} - - - - - - CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} - USING ${dataBaseName}.${superTableName} - - #{item.fieldName} - - TAGS - - #{item.fieldValue} - - - - \ No newline at end of file From ce919d12d1b079ace85c70004bd6553053b76667 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 5 Dec 2024 21:45:48 +0800 Subject: [PATCH 013/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9Atdengine=20=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/controller/admin/device/IotDeviceDataController.java | 2 ++ .../yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java | 1 - .../module/iot/service/device/IotDeviceDataServiceImpl.java | 2 +- .../module/iot/service/device/IotDeviceServiceImpl.java | 2 +- .../service/tdengine/IotThingModelMessageServiceImpl.java | 5 +---- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 72fdda8c8..77bc78c66 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -31,6 +31,7 @@ public class IotDeviceDataController { @Resource private IotDeviceDataService deviceDataService; + // TODO @浩浩:这里的 /latest-list,包括方法名。 @GetMapping("/latest") @Operation(summary = "获取设备属性最新数据") public CommonResult> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { @@ -38,6 +39,7 @@ public class IotDeviceDataController { return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); } + // TODO @浩浩:这里的 /history-page 包括方法名。 @GetMapping("/history") @Operation(summary = "获取设备属性历史数据") public CommonResult> getHistoryDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java index 640255940..3d7aa84dd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import com.baomidou.dynamic.datasource.annotation.DS; -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 7d10977f9..d68287cd4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -133,7 +133,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { } private static String getDeviceTableName(String productKey, String deviceName) { - return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey, deviceName); + return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey, deviceName); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 58918c130..bb302a22f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -139,13 +139,13 @@ public class IotDeviceServiceImpl implements IotDeviceService { * @return 生成的 MQTT Password */ private String generateMqttPassword() { + // TODO @浩浩:这里的 StrUtil 随机字符串? SecureRandom secureRandom = new SecureRandom(); byte[] passwordBytes = new byte[32]; // 256 位的随机数 secureRandom.nextBytes(passwordBytes); return Base64.getUrlEncoder().withoutPadding().encodeToString(passwordBytes); } - /** * 生成唯一的 DeviceName * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 92a30ebb0..9ffb47715 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -66,8 +66,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() - .setId(device.getId()) - .setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); + .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); } // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 @@ -77,7 +76,6 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ return; } - // 3. 过滤并收集有效的属性字段,缓存设备属性 List schemaFieldValues = filterAndCollectValidFields(params, functionList, device, thingModelMessage.getTime()); if (schemaFieldValues.size() == 1) { // 仅有时间字段,无需保存 @@ -165,7 +163,6 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 2.1 过滤出 TAG 类型的字段 List> taggedNotesList = CollectionUtils.filterList(maps, map -> TAG_NOTE.equals(map.get(NOTE))); - // 2.2 解析字段信息 tagsFieldValues = FieldParser.parse(taggedNotesList.stream() .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) From 3a2c691af085c4e649373961e827627b8fcfaf9a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 7 Dec 2024 16:42:56 +0800 Subject: [PATCH 014/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E4=BA=A7=E5=93=81=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E7=9A=84=E7=BB=B4=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 9 ++- .../product/IotProductCategoryController.java | 72 +++++++++++++++++++ .../admin/product/vo/IotProductSaveReqVO.java | 6 +- .../category/IotProductCategoryPageReqVO.java | 27 +++++++ .../vo/category/IotProductCategoryRespVO.java | 33 +++++++++ .../category/IotProductCategorySaveReqVO.java | 29 ++++++++ .../product/IotProductCategoryDO.java | 48 +++++++++++++ .../product/IotProductCategoryMapper.java | 25 +++++++ .../product/IotProductCategoryService.java | 54 ++++++++++++++ .../IotProductCategoryServiceImpl.java | 70 ++++++++++++++++++ 10 files changed, 369 insertions(+), 4 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductCategoryController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryPageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategorySaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductCategoryDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index be9d28ecb..1e947e633 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -9,20 +9,20 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; */ public interface ErrorCodeConstants { - // ========== IoT 产品相关 1-050-001-000 ============ + // ========== 产品相关 1-050-001-000 ============ ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在"); ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); ErrorCode PRODUCT_STATUS_NOT_ALLOW_FUNCTION = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); - // ========== IoT 产品物模型 1-050-002-000 ============ + // ========== 产品物模型 1-050-002-000 ============ ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在"); ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。"); ErrorCode THINK_MODEL_FUNCTION_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。"); ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效"); - // ========== IoT 设备 1-050-003-000 ============ + // ========== 设备 1-050-003-000 ============ ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在"); ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一"); ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除"); @@ -30,4 +30,7 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_PRODUCT_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_004, "产品不能修改"); ErrorCode DEVICE_INVALID_DEVICE_STATUS = new ErrorCode(1_050_003_005, "无效的设备状态"); + // ========== 产品分类 1-050-004-000 ========== + ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在"); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductCategoryController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductCategoryController.java new file mode 100644 index 000000000..b365ddea1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductCategoryController.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; +import cn.iocoder.yudao.module.iot.service.product.IotProductCategoryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 产品分类") +@RestController +@RequestMapping("/iot/product-category") +@Validated +public class IotProductCategoryController { + + @Resource + private IotProductCategoryService productCategoryService; + + @PostMapping("/create") + @Operation(summary = "创建IoT 产品分类") + @PreAuthorize("@ss.hasPermission('iot:product-category:create')") + public CommonResult createProductCategory(@Valid @RequestBody IotProductCategorySaveReqVO createReqVO) { + return success(productCategoryService.createProductCategory(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新IoT 产品分类") + @PreAuthorize("@ss.hasPermission('iot:product-category:update')") + public CommonResult updateProductCategory(@Valid @RequestBody IotProductCategorySaveReqVO updateReqVO) { + productCategoryService.updateProductCategory(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除IoT 产品分类") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:product-category:delete')") + public CommonResult deleteProductCategory(@RequestParam("id") Long id) { + productCategoryService.deleteProductCategory(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得IoT 产品分类") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:product-category:query')") + public CommonResult getProductCategory(@RequestParam("id") Long id) { + IotProductCategoryDO productCategory = productCategoryService.getProductCategory(id); + return success(BeanUtils.toBean(productCategory, IotProductCategoryRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得IoT 产品分类分页") + @PreAuthorize("@ss.hasPermission('iot:product-category:query')") + public CommonResult> getProductCategoryPage(@Valid IotProductCategoryPageReqVO pageReqVO) { + PageResult pageResult = productCategoryService.getProductCategoryPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotProductCategoryRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java index 254b6b9da..757750544 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java @@ -14,9 +14,13 @@ public class IotProductSaveReqVO { @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.AUTO, example = "1") private Long id; - @Schema(description = "产品Key", requiredMode = Schema.RequiredMode.AUTO, example = "12345abc") + @Schema(description = "产品 Key", requiredMode = Schema.RequiredMode.AUTO, example = "12345abc") private String productKey; + // TODO 芋艿:品类 + + // TODO 芋艿:【待确定】保活时长、产品图标、产品图片 + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温湿度") @NotEmpty(message = "产品名称不能为空") private String name; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryPageReqVO.java new file mode 100644 index 000000000..90d338a89 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product.vo.category; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 产品分类分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class IotProductCategoryPageReqVO extends PageParam { + + @Schema(description = "分类名字", example = "王五") + private String name; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryRespVO.java new file mode 100644 index 000000000..d684b0215 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryRespVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product.vo.category; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.module.system.enums.DictTypeConstants; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 产品分类 Response VO") +@Data +public class IotProductCategoryRespVO { + + @Schema(description = "分类 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25284") + private Long id; + + @Schema(description = "分类名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String name; + + @Schema(description = "分类排序") + private Integer sort; + + @Schema(description = "分类状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @DictFormat(DictTypeConstants.COMMON_STATUS) + private Integer status; + + @Schema(description = "分类描述", example = "随便") + private String description; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategorySaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategorySaveReqVO.java new file mode 100644 index 000000000..a7b2fe427 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategorySaveReqVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product.vo.category; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 产品分类新增/修改 Request VO") +@Data +public class IotProductCategorySaveReqVO { + + @Schema(description = "分类 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25284") + private Long id; + + @Schema(description = "分类名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotEmpty(message = "分类名字不能为空") + private String name; + + @Schema(description = "分类排序") + private Integer sort; + + @Schema(description = "分类状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "分类状态不能为空") + private Integer status; + + @Schema(description = "分类描述", example = "随便") + private String description; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductCategoryDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductCategoryDO.java new file mode 100644 index 000000000..a6510488c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductCategoryDO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.product; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * IoT 产品分类 DO + * + * @author 芋道源码 + */ +@TableName("iot_product_category") +@KeySequence("iot_product_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotProductCategoryDO extends BaseDO { + + /** + * 分类 ID + */ + @TableId + private Long id; + /** + * 分类名字 + */ + private String name; + /** + * 分类排序 + */ + private Integer sort; + /** + * 分类状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 分类描述 + */ + private String description; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java new file mode 100644 index 000000000..845eded14 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * IoT 产品分类 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotProductCategoryMapper extends BaseMapperX { + + default PageResult selectPage(IotProductCategoryPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotProductCategoryDO::getName, reqVO.getName()) + .betweenIfPresent(IotProductCategoryDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotProductCategoryDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java new file mode 100644 index 000000000..9830ec8b9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.service.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; +import jakarta.validation.Valid; + +/** + * IoT 产品分类 Service 接口 + * + * @author 芋道源码 + */ +public interface IotProductCategoryService { + + /** + * 创建IoT 产品分类 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductCategory(@Valid IotProductCategorySaveReqVO createReqVO); + + /** + * 更新IoT 产品分类 + * + * @param updateReqVO 更新信息 + */ + void updateProductCategory(@Valid IotProductCategorySaveReqVO updateReqVO); + + /** + * 删除IoT 产品分类 + * + * @param id 编号 + */ + void deleteProductCategory(Long id); + + /** + * 获得IoT 产品分类 + * + * @param id 编号 + * @return IoT 产品分类 + */ + IotProductCategoryDO getProductCategory(Long id); + + /** + * 获得IoT 产品分类分页 + * + * @param pageReqVO 分页查询 + * @return IoT 产品分类分页 + */ + PageResult getProductCategoryPage(IotProductCategoryPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java new file mode 100644 index 000000000..579d27cfb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.iot.service.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; +import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductCategoryMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS; + +/** + * IoT 产品分类 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class IotProductCategoryServiceImpl implements IotProductCategoryService { + + @Resource + private IotProductCategoryMapper productCategoryMapper; + + @Override + public Long createProductCategory(IotProductCategorySaveReqVO createReqVO) { + // 插入 + IotProductCategoryDO productCategory = BeanUtils.toBean(createReqVO, IotProductCategoryDO.class); + productCategoryMapper.insert(productCategory); + // 返回 + return productCategory.getId(); + } + + @Override + public void updateProductCategory(IotProductCategorySaveReqVO updateReqVO) { + // 校验存在 + validateProductCategoryExists(updateReqVO.getId()); + // 更新 + IotProductCategoryDO updateObj = BeanUtils.toBean(updateReqVO, IotProductCategoryDO.class); + productCategoryMapper.updateById(updateObj); + } + + @Override + public void deleteProductCategory(Long id) { + // 校验存在 + validateProductCategoryExists(id); + // 删除 + productCategoryMapper.deleteById(id); + } + + private void validateProductCategoryExists(Long id) { + if (productCategoryMapper.selectById(id) == null) { + throw exception(PRODUCT_CATEGORY_NOT_EXISTS); + } + } + + @Override + public IotProductCategoryDO getProductCategory(Long id) { + return productCategoryMapper.selectById(id); + } + + @Override + public PageResult getProductCategoryPage(IotProductCategoryPageReqVO pageReqVO) { + return productCategoryMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file From 9b9fd30c90bfb88d1ad61ef314ffab73e18264ea Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 7 Dec 2024 18:50:31 +0800 Subject: [PATCH 015/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E3=80=91IoT=EF=BC=9A=E4=BA=A7=E5=93=81=E6=94=BE?= =?UTF-8?q?=E5=88=B0=20product=20=E5=AD=90=E7=9B=AE=E5=BD=95=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/product/IotProductController.java | 13 +++--- .../product/vo/IotProductSimpleRespVO.java | 16 ------- .../vo/{ => product}/IotProductPageReqVO.java | 2 +- .../vo/{ => product}/IotProductRespVO.java | 43 +++++++++++-------- .../vo/{ => product}/IotProductSaveReqVO.java | 28 +++++++----- .../dal/dataobject/product/IotProductDO.java | 15 +++++-- .../dal/mysql/product/IotProductMapper.java | 2 +- .../service/product/IotProductService.java | 4 +- .../product/IotProductServiceImpl.java | 5 +-- .../dal/dataobject/notify/PayNotifyLogDO.java | 2 +- .../dataobject/notify/PayNotifyTaskDO.java | 4 +- 11 files changed, 68 insertions(+), 66 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/{ => product}/IotProductPageReqVO.java (88%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/{ => product}/IotProductRespVO.java (85%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/{ => product}/IotProductSaveReqVO.java (82%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index e7f41d91d..a4d111a99 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -3,10 +3,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.product; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSimpleRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import io.swagger.v3.oas.annotations.Operation; @@ -21,6 +20,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @Tag(name = "管理后台 - IoT 产品") @RestController @@ -86,9 +86,10 @@ public class IotProductController { @GetMapping("/simple-list") @Operation(summary = "获得所有产品列表") @PreAuthorize("@ss.hasPermission('iot:product:query')") - public CommonResult> getSimpleProductList() { + public CommonResult> getSimpleProductList() { List list = productService.getProductList(); - return success(BeanUtils.toBean(list, IotProductSimpleRespVO.class)); + return success(convertList(list, product -> // 只返回 id、name 字段 + new IotProductRespVO().setId(product.getId()).setName(product.getName()))); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java deleted file mode 100644 index 83855eaaf..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.product.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Schema(description = "管理后台 - IoT 产品 Response VO") -@Data -public class IotProductSimpleRespVO { - - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") - private Long id; - - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - private String name; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductPageReqVO.java similarity index 88% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductPageReqVO.java index 3437f563f..d54adec48 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductPageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.product.vo; +package cn.iocoder.yudao.module.iot.controller.admin.product.vo.product; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java index 0958b3e84..65d26ff5b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.product.vo; +package cn.iocoder.yudao.module.iot.controller.admin.product.vo.product; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; @@ -20,34 +20,23 @@ public class IotProductRespVO { @ExcelProperty("产品名称") private String name; - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("产品标识") private String productKey; - @Schema(description = "接入网关协议", example = "2") - @ExcelProperty("接入网关协议") - private Integer protocolType; - - @Schema(description = "协议编号(脚本解析 id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "13177") - @ExcelProperty("协议编号(脚本解析 id)") - private Long protocolId; - - @Schema(description = "产品所属品类标识符", example = "14237") - @ExcelProperty("产品所属品类标识符") + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long categoryId; + @Schema(description = "产品图标", example = "https://iocoder.cn/1.svg") + private String icon; + + @Schema(description = "产品图标", example = "https://iocoder.cn/1.png") + private String picUrl; + @Schema(description = "产品描述", example = "你猜") @ExcelProperty("产品描述") private String description; - @Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("数据校验级别") - private Integer validateType; - @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelProperty("产品状态") private Integer status; @@ -60,8 +49,24 @@ public class IotProductRespVO { @ExcelProperty("联网方式") private Integer netType; + @Schema(description = "接入网关协议", example = "2") + @ExcelProperty("接入网关协议") + private Integer protocolType; + + @Schema(description = "协议编号(脚本解析 id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "13177") + @ExcelProperty("协议编号(脚本解析 id)") + private Long protocolId; + @Schema(description = "数据格式") @ExcelProperty("数据格式") private Integer dataFormat; + @Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("数据校验级别") + private Integer validateType; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductSaveReqVO.java similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductSaveReqVO.java index 757750544..31890beb7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductSaveReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.product.vo; +package cn.iocoder.yudao.module.iot.controller.admin.product.vo.product; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.product.*; @@ -14,17 +14,26 @@ public class IotProductSaveReqVO { @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.AUTO, example = "1") private Long id; - @Schema(description = "产品 Key", requiredMode = Schema.RequiredMode.AUTO, example = "12345abc") - private String productKey; - - // TODO 芋艿:品类 - - // TODO 芋艿:【待确定】保活时长、产品图标、产品图片 - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温湿度") @NotEmpty(message = "产品名称不能为空") private String name; + @Schema(description = "产品 Key", requiredMode = Schema.RequiredMode.AUTO, example = "12345abc") + private String productKey; + + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "产品分类编号不能为空") + private Long categoryId; + + @Schema(description = "产品图标", example = "https://iocoder.cn/1.svg") + private String icon; + + @Schema(description = "产品图标", example = "https://iocoder.cn/1.png") + private String picUrl; + + @Schema(description = "产品描述", example = "描述") + private String description; + @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @InEnum(value = IotProductDeviceTypeEnum.class, message = "设备类型必须是 {value}") @NotNull(message = "设备类型不能为空") @@ -48,7 +57,4 @@ public class IotProductSaveReqVO { @NotNull(message = "数据校验级别不能为空") private Integer validateType; - @Schema(description = "产品描述", example = "描述") - private String description; - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java index eef466eda..34fd35706 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java @@ -22,7 +22,7 @@ import lombok.*; public class IotProductDO extends BaseDO { /** - * 产品ID + * 产品 ID */ @TableId private Long id; @@ -30,17 +30,24 @@ public class IotProductDO extends BaseDO { * 产品名称 */ private String name; - // TODO @haohao:这个字段,要不改成 identifier,和阿里云更统一些 /** * 产品标识 */ private String productKey; /** - * 产品所属品类编号 + * 产品分类编号 *

- * TODO 外键:后续加 + * 关联 {@link IotProductCategoryDO#getId()} */ private Long categoryId; + /** + * 产品图标 + */ + private String icon; + /** + * 产品图片 + */ + private String picUrl; /** * 产品描述 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index 0341e2492..eac1d29e8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.mysql.product; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import org.apache.ibatis.annotations.Mapper; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 3fff94fd9..bcbf13ef4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.service.product; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import jakarta.validation.Valid; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index d0ca09288..259bcaa1f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.iot.service.product; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; @@ -14,7 +14,6 @@ import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.List; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyLogDO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyLogDO.java index a482605d5..384628370 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyLogDO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyLogDO.java @@ -44,7 +44,7 @@ public class PayNotifyLogDO extends BaseDO { /** * 支付通知状态 * - * 外键 {@link PayNotifyStatusEnum} + * 枚举 {@link PayNotifyStatusEnum} */ private Integer status; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java index 7bfabad3f..9f9ee7fef 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java @@ -52,7 +52,7 @@ public class PayNotifyTaskDO extends TenantBaseDO { /** * 通知类型 * - * 外键 {@link PayNotifyTypeEnum} + * 枚举 {@link PayNotifyTypeEnum} */ private Integer type; /** @@ -73,7 +73,7 @@ public class PayNotifyTaskDO extends TenantBaseDO { /** * 通知状态 * - * 外键 {@link PayNotifyStatusEnum} + * 枚举 {@link PayNotifyStatusEnum} */ private Integer status; /** From a8c87d168accd14f5b266be9815046b1b45ff9db Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 7 Dec 2024 19:50:07 +0800 Subject: [PATCH 016/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E4=BA=A7=E5=93=81=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=97=B6=EF=BC=8CproductKey=20=E7=94=B1=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E7=94=9F=E6=88=90=EF=BC=9B=E5=90=8C=E6=97=B6=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20icon=E3=80=81picUrl=20=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 2 +- .../enums/product/IotProductStatusEnum.java | 4 +-- .../product/IotProductCategoryController.java | 24 +++++++++++--- .../product/IotProductCategoryMapper.java | 6 ++++ .../product/IotProductCategoryService.java | 24 ++++++++++---- .../IotProductCategoryServiceImpl.java | 7 ++++ .../product/IotProductServiceImpl.java | 32 ++++--------------- .../IotThinkModelFunctionServiceImpl.java | 2 +- 8 files changed, 60 insertions(+), 41 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 1e947e633..d1d350d5e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -11,7 +11,7 @@ public interface ErrorCodeConstants { // ========== 产品相关 1-050-001-000 ============ ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在"); - ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); + ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); ErrorCode PRODUCT_STATUS_NOT_ALLOW_FUNCTION = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java index e64a3d678..7b4d90a5a 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java @@ -18,12 +18,12 @@ public enum IotProductStatusEnum implements IntArrayValuable { UNPUBLISHED(0, "开发中"), PUBLISHED(1, "已发布"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductStatusEnum::getType).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductStatusEnum::getStatus).toArray(); /** * 类型 */ - private final Integer type; + private final Integer status; /** * 描述 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductCategoryController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductCategoryController.java index b365ddea1..bc1c1fbf2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductCategoryController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductCategoryController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.product; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -17,7 +18,10 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @Tag(name = "管理后台 - IoT 产品分类") @RestController @@ -29,14 +33,14 @@ public class IotProductCategoryController { private IotProductCategoryService productCategoryService; @PostMapping("/create") - @Operation(summary = "创建IoT 产品分类") + @Operation(summary = "创建产品分类") @PreAuthorize("@ss.hasPermission('iot:product-category:create')") public CommonResult createProductCategory(@Valid @RequestBody IotProductCategorySaveReqVO createReqVO) { return success(productCategoryService.createProductCategory(createReqVO)); } @PutMapping("/update") - @Operation(summary = "更新IoT 产品分类") + @Operation(summary = "更新产品分类") @PreAuthorize("@ss.hasPermission('iot:product-category:update')") public CommonResult updateProductCategory(@Valid @RequestBody IotProductCategorySaveReqVO updateReqVO) { productCategoryService.updateProductCategory(updateReqVO); @@ -44,7 +48,7 @@ public class IotProductCategoryController { } @DeleteMapping("/delete") - @Operation(summary = "删除IoT 产品分类") + @Operation(summary = "删除产品分类") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('iot:product-category:delete')") public CommonResult deleteProductCategory(@RequestParam("id") Long id) { @@ -53,7 +57,7 @@ public class IotProductCategoryController { } @GetMapping("/get") - @Operation(summary = "获得IoT 产品分类") + @Operation(summary = "获得产品分类") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:product-category:query')") public CommonResult getProductCategory(@RequestParam("id") Long id) { @@ -62,11 +66,21 @@ public class IotProductCategoryController { } @GetMapping("/page") - @Operation(summary = "获得IoT 产品分类分页") + @Operation(summary = "获得产品分类分页") @PreAuthorize("@ss.hasPermission('iot:product-category:query')") public CommonResult> getProductCategoryPage(@Valid IotProductCategoryPageReqVO pageReqVO) { PageResult pageResult = productCategoryService.getProductCategoryPage(pageReqVO); return success(BeanUtils.toBean(pageResult, IotProductCategoryRespVO.class)); } + @GetMapping("/simple-list") + @Operation(summary = "获得所有产品分类列表") + @PreAuthorize("@ss.hasPermission('iot:product-category:query')") + public CommonResult> getSimpleProductCategoryList() { + List list = productCategoryService.getProductCategoryListByStatus( + CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, category -> + new IotProductCategoryRespVO().setId(category.getId()).setName(category.getName()))); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java index 845eded14..8b1744af0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProdu import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * IoT 产品分类 Mapper * @@ -22,4 +24,8 @@ public interface IotProductCategoryMapper extends BaseMapperX selectListByStatus(Integer status) { + return selectList(IotProductCategoryDO::getStatus, status); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java index 9830ec8b9..72bdefd8f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProdu import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import jakarta.validation.Valid; +import java.util.List; + /** * IoT 产品分类 Service 接口 * @@ -14,7 +16,7 @@ import jakarta.validation.Valid; public interface IotProductCategoryService { /** - * 创建IoT 产品分类 + * 创建产品分类 * * @param createReqVO 创建信息 * @return 编号 @@ -22,33 +24,41 @@ public interface IotProductCategoryService { Long createProductCategory(@Valid IotProductCategorySaveReqVO createReqVO); /** - * 更新IoT 产品分类 + * 更新产品分类 * * @param updateReqVO 更新信息 */ void updateProductCategory(@Valid IotProductCategorySaveReqVO updateReqVO); /** - * 删除IoT 产品分类 + * 删除产品分类 * * @param id 编号 */ void deleteProductCategory(Long id); /** - * 获得IoT 产品分类 + * 获得产品分类 * * @param id 编号 - * @return IoT 产品分类 + * @return 产品分类 */ IotProductCategoryDO getProductCategory(Long id); /** - * 获得IoT 产品分类分页 + * 获得产品分类分页 * * @param pageReqVO 分页查询 - * @return IoT 产品分类分页 + * @return 产品分类分页 */ PageResult getProductCategoryPage(IotProductCategoryPageReqVO pageReqVO); + /** + * 获得产品分类列表,根据状态 + * + * @param status 状态 + * @return 产品分类列表 + */ + List getProductCategoryListByStatus(Integer status); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java index 579d27cfb..fa23c0fe7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java @@ -10,6 +10,8 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.List; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS; @@ -67,4 +69,9 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService return productCategoryMapper.selectPage(pageReqVO); } + @Override + public List getProductCategoryListByStatus(Integer status) { + return productCategoryMapper.selectListByStatus(status); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 259bcaa1f..b1d2d666b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.service.product; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; @@ -11,14 +10,12 @@ import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; - import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.util.List; import java.util.Objects; -import java.util.UUID; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @@ -42,31 +39,16 @@ public class IotProductServiceImpl implements IotProductService { @Override public Long createProduct(IotProductSaveReqVO createReqVO) { // 1. 生成 ProductKey - createProductKey(createReqVO); + if (productMapper.selectByProductKey(createReqVO.getProductKey()) != null) { + throw exception(PRODUCT_KEY_EXISTS); + } // 2. 插入 - IotProductDO product = BeanUtils.toBean(createReqVO, IotProductDO.class); + IotProductDO product = BeanUtils.toBean(createReqVO, IotProductDO.class) + .setStatus(IotProductStatusEnum.UNPUBLISHED.getStatus()); productMapper.insert(product); return product.getId(); } - /** - * 创建 ProductKey - * - * @param createReqVO 创建信息 - */ - private void createProductKey(IotProductSaveReqVO createReqVO) { - String productKey = createReqVO.getProductKey(); - // 1. productKey为空,生成随机的 11 位字符串 - if (StrUtil.isEmpty(productKey)) { - productKey = UUID.randomUUID().toString().replace("-", "").substring(0, 11); - } - // 2. 校验唯一性 - if (productMapper.selectByProductKey(productKey) != null) { - throw exception(PRODUCT_IDENTIFICATION_EXISTS); - } - createReqVO.setProductKey(productKey); - } - @Override public void updateProduct(IotProductSaveReqVO updateReqVO) { updateReqVO.setProductKey(null); // 不更新产品标识 @@ -98,7 +80,7 @@ public class IotProductServiceImpl implements IotProductService { } private void validateProductStatus(IotProductDO iotProductDO) { - if (Objects.equals(iotProductDO.getStatus(), IotProductStatusEnum.PUBLISHED.getType())) { + if (Objects.equals(iotProductDO.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) { throw exception(PRODUCT_STATUS_NOT_DELETE); } } @@ -121,7 +103,7 @@ public class IotProductServiceImpl implements IotProductService { // 2. 更新 IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); // 3. 产品是发布状态 - if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getType())) { + if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { // 3.1 创建超级表数据模型 thinkModelFunctionService.createSuperTableDataModel(id); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 404a2aaa0..bfccfb45a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -82,7 +82,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe private void validateProductStatus(Long createReqVO) { IotProductDO product = productService.getProduct(createReqVO); - if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getType())) { + if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) { throw exception(PRODUCT_STATUS_NOT_ALLOW_FUNCTION); } } From 9841c869a2ef457eab3be7ff3224c32f7ac78126 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 7 Dec 2024 20:17:11 +0800 Subject: [PATCH 017/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E4=BA=A7=E5=93=81=E8=AF=A6?= =?UTF-8?q?=E6=83=85=EF=BC=8C=E4=BC=98=E5=8C=96=E7=9B=B8=E5=85=B3=E5=B1=95?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/product/IotProductController.java | 22 +++++++++++++++++-- .../product/vo/product/IotProductRespVO.java | 3 +++ .../product/IotProductCategoryService.java | 22 +++++++++++++++++++ .../IotProductCategoryServiceImpl.java | 10 +++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index a4d111a99..50ee44faf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -2,11 +2,14 @@ package cn.iocoder.yudao.module.iot.controller.admin.product; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductRespVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.service.product.IotProductCategoryService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -18,6 +21,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -30,6 +34,8 @@ public class IotProductController { @Resource private IotProductService productService; + @Resource + private IotProductCategoryService categoryService; @PostMapping("/create") @Operation(summary = "创建产品") @@ -72,7 +78,13 @@ public class IotProductController { @PreAuthorize("@ss.hasPermission('iot:product:query')") public CommonResult getProduct(@RequestParam("id") Long id) { IotProductDO product = productService.getProduct(id); - return success(BeanUtils.toBean(product, IotProductRespVO.class)); + // 拼接数据 + IotProductCategoryDO category = categoryService.getProductCategory(product.getCategoryId()); + return success(BeanUtils.toBean(product, IotProductRespVO.class, bean -> { + if (category != null) { + bean.setCategoryName(category.getName()); + } + })); } @GetMapping("/page") @@ -80,7 +92,13 @@ public class IotProductController { @PreAuthorize("@ss.hasPermission('iot:product:query')") public CommonResult> getProductPage(@Valid IotProductPageReqVO pageReqVO) { PageResult pageResult = productService.getProductPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotProductRespVO.class)); + // 拼接数据 + Map categoryMap = categoryService.getProductCategoryMap( + convertList(pageResult.getList(), IotProductDO::getCategoryId)); + return success(BeanUtils.toBean(pageResult, IotProductRespVO.class, bean -> { + MapUtils.findAndThen(categoryMap, bean.getCategoryId(), + category -> bean.setCategoryName(category.getName())); + })); } @GetMapping("/simple-list") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java index 65d26ff5b..814b548f1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java @@ -27,6 +27,9 @@ public class IotProductRespVO { @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long categoryId; + @Schema(description = "产品分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String categoryName; + @Schema(description = "产品图标", example = "https://iocoder.cn/1.svg") private String icon; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java index 72bdefd8f..e44b6d487 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java @@ -6,7 +6,11 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProdu import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import jakarta.validation.Valid; +import java.util.Collection; import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * IoT 产品分类 Service 接口 @@ -45,6 +49,24 @@ public interface IotProductCategoryService { */ IotProductCategoryDO getProductCategory(Long id); + /** + * 获得产品分类列表 + * + * @param ids 编号 + * @return 产品分类列表 + */ + List getProductCategoryList(Collection ids); + + /** + * 获得产品分类 Map + * + * @param ids 编号 + * @return 产品分类 Map + */ + default Map getProductCategoryMap(Collection ids) { + return convertMap(getProductCategoryList(ids), IotProductCategoryDO::getId); + } + /** * 获得产品分类分页 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java index fa23c0fe7..c531b1450 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.product; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; @@ -10,6 +11,7 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Collection; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -64,6 +66,14 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService return productCategoryMapper.selectById(id); } + @Override + public List getProductCategoryList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return CollUtil.newArrayList(); + } + return productCategoryMapper.selectBatchIds(ids); + } + @Override public PageResult getProductCategoryPage(IotProductCategoryPageReqVO pageReqVO) { return productCategoryMapper.selectPage(pageReqVO); From db9c485285d99fef822557582fcf00fd9f26bd7e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 7 Dec 2024 20:48:19 +0800 Subject: [PATCH 018/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E4=BA=A7=E5=93=81=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/DictTypeConstants.java | 16 +++++++++++++ .../admin/product/IotProductController.java | 19 +++++++++++++++ .../product/vo/product/IotProductRespVO.java | 24 ++++++++++++++----- 3 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java new file mode 100644 index 000000000..b5c34f14b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.enums; + +/** + * IoT 字典类型的枚举类 + * + * @author 芋道源码 + */ +public class DictTypeConstants { + + public static final String PRODUCT_STATUS = "iot_product_status"; + public static final String PRODUCT_DEVICE_TYPE = "iot_product_device_type"; + public static final String NET_TYPE = "iot_net_type"; + public static final String PROTOCOL_TYPE = "iot_protocol_type"; + public static final String DATA_FORMAT = "iot_data_format"; + public static final String VALIDATE_TYPE = "iot_validate_type"; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index 50ee44faf..c34571471 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -1,9 +1,12 @@ package cn.iocoder.yudao.module.iot.controller.admin.product; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductRespVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductSaveReqVO; @@ -15,14 +18,17 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.io.IOException; import java.util.List; import java.util.Map; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -101,6 +107,19 @@ public class IotProductController { })); } + @GetMapping("/export-excel") + @Operation(summary = "导出产品 Excel") + @PreAuthorize("@ss.hasPermission('iot:product:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportProductExcel(@Valid IotProductPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + CommonResult> result = getProductPage(exportReqVO); + // 导出 Excel + ExcelUtils.write(response, "产品.xls", "数据", IotProductRespVO.class, + result.getData().getList()); + } + @GetMapping("/simple-list") @Operation(summary = "获得所有产品列表") @PreAuthorize("@ss.hasPermission('iot:product:query')") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java index 814b548f1..6637a67ff 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.product.vo.product; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.iot.enums.DictTypeConstants; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -28,12 +31,15 @@ public class IotProductRespVO { private Long categoryId; @Schema(description = "产品分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("产品分类") private String categoryName; @Schema(description = "产品图标", example = "https://iocoder.cn/1.svg") + @ExcelProperty("产品图标") private String icon; @Schema(description = "产品图标", example = "https://iocoder.cn/1.png") + @ExcelProperty("产品图标") private String picUrl; @Schema(description = "产品描述", example = "你猜") @@ -41,19 +47,23 @@ public class IotProductRespVO { private String description; @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("产品状态") + @ExcelProperty(value = "产品状态", converter = DictConvert.class) + @DictFormat(DictTypeConstants.PRODUCT_STATUS) private Integer status; @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @ExcelProperty("设备类型") + @ExcelProperty(value = "设备类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.PRODUCT_DEVICE_TYPE) private Integer deviceType; @Schema(description = "联网方式", example = "2") - @ExcelProperty("联网方式") + @ExcelProperty(value = "联网方式", converter = DictConvert.class) + @DictFormat(DictTypeConstants.NET_TYPE) private Integer netType; @Schema(description = "接入网关协议", example = "2") - @ExcelProperty("接入网关协议") + @ExcelProperty(value = "接入网关协议", converter = DictConvert.class) + @DictFormat(DictTypeConstants.PROTOCOL_TYPE) private Integer protocolType; @Schema(description = "协议编号(脚本解析 id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "13177") @@ -61,11 +71,13 @@ public class IotProductRespVO { private Long protocolId; @Schema(description = "数据格式") - @ExcelProperty("数据格式") + @ExcelProperty(value = "数据格式", converter = DictConvert.class) + @DictFormat(DictTypeConstants.DATA_FORMAT) private Integer dataFormat; @Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("数据校验级别") + @ExcelProperty(value = "数据校验级别", converter = DictConvert.class) + @DictFormat(DictTypeConstants.VALIDATE_TYPE) private Integer validateType; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) From afaf98c44f76daa8a18fafa7410991a0b2485889 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Dec 2024 16:12:24 +0800 Subject: [PATCH 019/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=81=E4=BF=AE=E6=94=B9=E6=94=AF=E6=8C=81=E6=9B=B4?= =?UTF-8?q?=E5=A4=9A=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatis/core/type/LongSetTypeHandler.java | 58 +++++ .../module/iot/enums/ErrorCodeConstants.java | 6 +- .../product/IotProductDeviceTypeEnum.java | 10 + .../admin/device/IotDeviceController.java | 13 + .../device/vo/device/IotDeviceSaveReqVO.java | 12 + .../admin/product/IotProductController.java | 6 +- .../product/vo/product/IotProductRespVO.java | 4 +- .../vo/product/IotProductSaveReqVO.java | 2 +- .../dal/dataobject/device/IotDeviceDO.java | 30 ++- .../iot/dal/mysql/device/IotDeviceMapper.java | 11 + .../product/IotProductCategoryMapper.java | 2 +- .../iot/service/device/IotDeviceService.java | 16 +- .../service/device/IotDeviceServiceImpl.java | 226 ++++++++---------- 13 files changed, 249 insertions(+), 147 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongSetTypeHandler.java diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongSetTypeHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongSetTypeHandler.java new file mode 100644 index 000000000..58d82ecf3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongSetTypeHandler.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.framework.mybatis.core.type; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; +import org.apache.ibatis.type.TypeHandler; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Set; + +/** + * Set 的类型转换器实现类,对应数据库的 varchar 类型 + * + * @author 芋道源码 + */ +@MappedJdbcTypes(JdbcType.VARCHAR) +@MappedTypes(List.class) +public class LongSetTypeHandler implements TypeHandler> { + + private static final String COMMA = ","; + + @Override + public void setParameter(PreparedStatement ps, int i, Set strings, JdbcType jdbcType) throws SQLException { + // 设置占位符 + ps.setString(i, CollUtil.join(strings, COMMA)); + } + + @Override + public Set getResult(ResultSet rs, String columnName) throws SQLException { + String value = rs.getString(columnName); + return getResult(value); + } + + @Override + public Set getResult(ResultSet rs, int columnIndex) throws SQLException { + String value = rs.getString(columnIndex); + return getResult(value); + } + + @Override + public Set getResult(CallableStatement cs, int columnIndex) throws SQLException { + String value = cs.getString(columnIndex); + return getResult(value); + } + + private Set getResult(String value) { + if (value == null) { + return null; + } + return StrUtils.splitToLongSet(value, COMMA); + } +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index d1d350d5e..0d8b7d8bc 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -26,9 +26,9 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在"); ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一"); ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除"); - ErrorCode DEVICE_NAME_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_003, "设备名称不能修改"); - ErrorCode DEVICE_PRODUCT_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_004, "产品不能修改"); - ErrorCode DEVICE_INVALID_DEVICE_STATUS = new ErrorCode(1_050_003_005, "无效的设备状态"); + ErrorCode DEVICE_KEY_EXISTS = new ErrorCode(1_050_003_003, "设备标识已经存在"); + ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在"); + ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备"); // ========== 产品分类 1-050-004-000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在"); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java index 99b75f3fb..ef1432804 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java @@ -36,4 +36,14 @@ public enum IotProductDeviceTypeEnum implements IntArrayValuable { return ARRAYS; } + /** + * 判断是否是网关 + * + * @param type 类型 + * @return 是否是网关 + */ + public static boolean isGateway(Integer type) { + return GATEWAY.getType().equals(type); + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index ba68e0232..2dee57d6d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -18,7 +18,10 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @Tag(name = "管理后台 - IoT 设备") @RestController @@ -86,4 +89,14 @@ public class IotDeviceController { return success(deviceService.getDeviceCountByProductId(productId)); } + @GetMapping("/simple-list") + @Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项") + @Parameter(name = "deviceType", description = "设备类型", example = "1") + public CommonResult> getSimpleDeviceList( + @RequestParam(value = "deviceType", required = false) Integer deviceType) { + List list = deviceService.getDeviceList(deviceType); + return success(convertList(list, device -> // 只返回 id、name 字段 + new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName()))); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java index 85fde9d3d..e4f23d97e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java @@ -10,13 +10,25 @@ public class IotDeviceSaveReqVO { @Schema(description = "设备编号", example = "177") private Long id; + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.AUTO, example = "177") + private String deviceKey; + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") private String deviceName; @Schema(description = "备注名称", example = "张三") private String nickname; + @Schema(description = "设备序列号", example = "123456") + private String serialNumber; + + @Schema(description = "设备图片", example = "https://iocoder.cn/1.png") + private String picUrl; + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") private Long productId; + @Schema(description = "网关设备 ID", example = "16380") + private Long gatewayId; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index c34571471..2d8c85640 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -121,12 +121,12 @@ public class IotProductController { } @GetMapping("/simple-list") - @Operation(summary = "获得所有产品列表") - @PreAuthorize("@ss.hasPermission('iot:product:query')") + @Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项") public CommonResult> getSimpleProductList() { List list = productService.getProductList(); return success(convertList(list, product -> // 只返回 id、name 字段 - new IotProductRespVO().setId(product.getId()).setName(product.getName()))); + new IotProductRespVO().setId(product.getId()).setName(product.getName()) + .setDeviceType(product.getDeviceType()))); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java index 6637a67ff..f674651d5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java @@ -38,8 +38,8 @@ public class IotProductRespVO { @ExcelProperty("产品图标") private String icon; - @Schema(description = "产品图标", example = "https://iocoder.cn/1.png") - @ExcelProperty("产品图标") + @Schema(description = "产品图片", example = "https://iocoder.cn/1.png") + @ExcelProperty("产品图片") private String picUrl; @Schema(description = "产品描述", example = "你猜") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductSaveReqVO.java index 31890beb7..268ab7c6f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductSaveReqVO.java @@ -28,7 +28,7 @@ public class IotProductSaveReqVO { @Schema(description = "产品图标", example = "https://iocoder.cn/1.svg") private String icon; - @Schema(description = "产品图标", example = "https://iocoder.cn/1.png") + @Schema(description = "产品图片", example = "https://iocoder.cn/1.png") private String picUrl; @Schema(description = "产品描述", example = "描述") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index d3f6547a1..6028c25fe 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -1,22 +1,25 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongSetTypeHandler; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.Set; /** * IoT 设备 DO * * @author haohao */ -@TableName("iot_device") +@TableName(value = "iot_device", autoResultMap = true) @KeySequence("iot_device_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @@ -47,6 +50,17 @@ public class IotDeviceDO extends BaseDO { * 设备序列号 */ private String serialNumber; + /** + * 设备图片 + */ + private String picUrl; + /** + * 设备分组编号集合 + * + * 关联 TODO 芋艿: + */ + @TableField(typeHandler = LongSetTypeHandler.class) + private Set groupIds; /** * 产品编号 @@ -66,13 +80,6 @@ public class IotDeviceDO extends BaseDO { * 冗余 {@link IotProductDO#getDeviceType()} */ private Integer deviceType; - - /** - * 设备状态 - *

- * 枚举 {@link IotDeviceStatusEnum} - */ - private Integer status; /** * 网关设备编号 *

@@ -82,6 +89,13 @@ public class IotDeviceDO extends BaseDO { */ private Long gatewayId; + /** + * 设备状态 + *

+ * 枚举 {@link IotDeviceStatusEnum} + */ + private Integer status; + /** * 设备状态最后更新时间 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 4d8315eb3..65af1f17a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePa import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * IoT 设备 Mapper * @@ -51,4 +53,13 @@ public interface IotDeviceMapper extends BaseMapperX { default Long selectCountByProductId(Long productId) { return selectCount(IotDeviceDO::getProductId, productId); } + + default IotDeviceDO selectByDeviceKey(String deviceKey) { + return selectOne(IotDeviceDO::getDeviceKey, deviceKey); + } + + default List selectList(Integer deviceType) { + return selectList(IotDeviceDO::getDeviceType, deviceType); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java index 8b1744af0..70ad56da8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java @@ -21,7 +21,7 @@ public interface IotProductCategoryMapper extends BaseMapperX() .likeIfPresent(IotProductCategoryDO::getName, reqVO.getName()) .betweenIfPresent(IotProductCategoryDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(IotProductCategoryDO::getId)); + .orderByAsc(IotProductCategoryDO::getSort)); } default List selectListByStatus(Integer status) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index ed4c6a60c..3569c7597 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -1,11 +1,14 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; -import jakarta.validation.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; +import jakarta.validation.Valid; + +import javax.annotation.Nullable; +import java.util.List; /** * IoT 设备 Service 接口 @@ -52,6 +55,14 @@ public interface IotDeviceService { */ PageResult getDevicePage(IotDevicePageReqVO pageReqVO); + /** + * 获得设备列表 + * + * @param deviceType 设备类型 + * @return 设备列表 + */ + List getDeviceList(@Nullable Integer deviceType); + /** * 更新设备状态 * @@ -75,4 +86,5 @@ public interface IotDeviceService { * @return 设备信息 */ IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index bb302a22f..c882b7420 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.RandomUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; @@ -12,18 +12,17 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import java.security.SecureRandom; +import javax.annotation.Nullable; import java.time.LocalDateTime; -import java.util.Base64; +import java.util.List; import java.util.Objects; -import java.util.UUID; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @@ -40,142 +39,64 @@ public class IotDeviceServiceImpl implements IotDeviceService { @Resource private IotDeviceMapper deviceMapper; + @Resource private IotProductService productService; - /** - * 创建 IoT 设备 - * - * @param createReqVO 创建请求 VO - * @return 设备 ID - */ @Override - @Transactional(rollbackFor = Exception.class) public Long createDevice(IotDeviceSaveReqVO createReqVO) { // 1.1 校验产品是否存在 IotProductDO product = productService.getProduct(createReqVO.getProductId()); if (product == null) { throw exception(PRODUCT_NOT_EXISTS); } - // 1.2 校验设备名称在同一产品下是否唯一 - if (StrUtil.isBlank(createReqVO.getDeviceName())) { - createReqVO.setDeviceName(generateUniqueDeviceName(product.getProductKey())); - } else { - validateDeviceNameUnique(product.getProductKey(), createReqVO.getDeviceName()); + // 1.2 校验设备标识是否唯一 + if (deviceMapper.selectByDeviceKey(createReqVO.getDeviceKey()) != null) { + throw exception(DEVICE_KEY_EXISTS); + } + // 1.3 校验设备名称在同一产品下是否唯一 + if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), createReqVO.getDeviceKey()) != null) { + throw exception(DEVICE_NAME_EXISTS); + } + // 1.4 校验父设备是否为合法网关 + if (IotProductDeviceTypeEnum.isGateway(product.getDeviceType()) + && createReqVO.getGatewayId() != null) { + validateGatewayDeviceExists(createReqVO.getGatewayId()); } // 2.1 转换 VO 为 DO - IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class) - .setProductKey(product.getProductKey()) - .setDeviceType(product.getDeviceType()); - // 2.2 生成并设置必要的字段 - device.setDeviceKey(generateUniqueDeviceKey()); - device.setDeviceSecret(generateDeviceSecret()); - device.setMqttClientId(generateMqttClientId()); - device.setMqttUsername(generateMqttUsername(device.getDeviceName(), device.getProductKey())); - device.setMqttPassword(generateMqttPassword()); - // 2.3 设置设备状态为未激活 - device.setStatus(IotDeviceStatusEnum.INACTIVE.getStatus()); - device.setStatusLastUpdateTime(LocalDateTime.now()); - // 2.4 插入到数据库 + IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class, o -> { + o.setProductKey(product.getProductKey()).setDeviceType(product.getDeviceType()); + // 生成并设置必要的字段 + o.setDeviceSecret(generateDeviceSecret()) + .setMqttClientId(generateMqttClientId()) + .setMqttUsername(generateMqttUsername(o.getDeviceName(), o.getProductKey())) + .setMqttPassword(generateMqttPassword()); + // 设置设备状态为未激活 + o.setStatus(IotDeviceStatusEnum.INACTIVE.getStatus()).setStatusLastUpdateTime(LocalDateTime.now()); + }); + // 2.2 插入到数据库 deviceMapper.insert(device); return device.getId(); } - /** - * 校验设备名称在同一产品下是否唯一 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - */ - private void validateDeviceNameUnique(String productKey, String deviceName) { - IotDeviceDO existingDevice = deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); - if (existingDevice != null) { - throw exception(DEVICE_NAME_EXISTS); - } - } - - /** - * 生成唯一的 deviceKey - * - * @return 生成的 deviceKey - */ - private String generateUniqueDeviceKey() { - return UUID.randomUUID().toString(); - } - - /** - * 生成 deviceSecret - * - * @return 生成的 deviceSecret - */ - private String generateDeviceSecret() { - return IdUtil.fastSimpleUUID(); - } - - /** - * 生成 MQTT Client ID - * - * @return 生成的 MQTT Client ID - */ - private String generateMqttClientId() { - return UUID.randomUUID().toString(); - } - - /** - * 生成 MQTT Username - * - * @param deviceName 设备名称 - * @param productKey 产品 Key - * @return 生成的 MQTT Username - */ - private String generateMqttUsername(String deviceName, String productKey) { - return deviceName + "&" + productKey; - } - - /** - * 生成 MQTT Password - * - * @return 生成的 MQTT Password - */ - private String generateMqttPassword() { - // TODO @浩浩:这里的 StrUtil 随机字符串? - SecureRandom secureRandom = new SecureRandom(); - byte[] passwordBytes = new byte[32]; // 256 位的随机数 - secureRandom.nextBytes(passwordBytes); - return Base64.getUrlEncoder().withoutPadding().encodeToString(passwordBytes); - } - - /** - * 生成唯一的 DeviceName - * - * @param productKey 产品标识 - * @return 生成的唯一 DeviceName - */ - private String generateUniqueDeviceName(String productKey) { - for (int i = 0; i < Short.MAX_VALUE; i++) { - String deviceName = IdUtil.fastSimpleUUID().substring(0, 20); - if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) { - return deviceName; - } - } - throw new IllegalArgumentException("生成 DeviceName 失败"); - } - @Override - @Transactional(rollbackFor = Exception.class) public void updateDevice(IotDeviceSaveReqVO updateReqVO) { - // 1. 校验存在 - validateDeviceExists(updateReqVO.getId()); + updateReqVO.setDeviceKey(null).setDeviceName(null).setProductId(null); // 不允许更新 + // 1.1 校验存在 + IotDeviceDO device = validateDeviceExists(updateReqVO.getId()); + // 1.2 校验父设备是否为合法网关 + if (IotProductDeviceTypeEnum.isGateway(device.getDeviceType()) + && updateReqVO.getGatewayId() != null) { + validateGatewayDeviceExists(updateReqVO.getGatewayId()); + } // 2. 更新到数据库 - IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class) - .setDeviceName(null).setProductId(null); // 设备名称 和 产品 ID 不能修改 + IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); deviceMapper.updateById(updateObj); } @Override - @Transactional(rollbackFor = Exception.class) public void deleteDevice(Long id) { // 1.1 校验存在 IotDeviceDO device = validateDeviceExists(id); @@ -202,13 +123,24 @@ public class IotDeviceServiceImpl implements IotDeviceService { return device; } - @Override - public IotDeviceDO getDevice(Long id) { + /** + * 校验网关设备是否存在 + * + * @param id 设备 ID + */ + private void validateGatewayDeviceExists(Long id) { IotDeviceDO device = deviceMapper.selectById(id); if (device == null) { - throw exception(DEVICE_NOT_EXISTS); + throw exception(DEVICE_GATEWAY_NOT_EXISTS); } - return device; + if (!IotProductDeviceTypeEnum.isGateway(device.getDeviceType())) { + throw exception(DEVICE_NOT_GATEWAY); + } + } + + @Override + public IotDeviceDO getDevice(Long id) { + return deviceMapper.selectById(id); } @Override @@ -216,19 +148,24 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectPage(pageReqVO); } + @Override + public List getDeviceList(@Nullable Integer deviceType) { + return deviceMapper.selectList(deviceType); + } + @Override public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) { // 1. 校验存在 IotDeviceDO device = validateDeviceExists(updateReqVO.getId()); // 2.1 更新状态和更新时间 - IotDeviceDO updateDevice = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); + IotDeviceDO updateDevice = BeanUtils.toBean(updateReqVO, IotDeviceDO.class) + .setStatusLastUpdateTime(LocalDateTime.now()); // 2.2 更新状态相关时间 if (Objects.equals(device.getStatus(), IotDeviceStatusEnum.INACTIVE.getStatus()) && Objects.equals(updateDevice.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { // 从未激活到在线,设置激活时间和最后上线时间 - updateDevice.setActiveTime(LocalDateTime.now()); - updateDevice.setLastOnlineTime(LocalDateTime.now()); + updateDevice.setActiveTime(LocalDateTime.now()).setLastOnlineTime(LocalDateTime.now()); } else if (Objects.equals(updateDevice.getStatus(), IotDeviceStatusEnum.ONLINE.getStatus())) { // 如果是上线,设置最后上线时间 updateDevice.setLastOnlineTime(LocalDateTime.now()); @@ -236,10 +173,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 如果是离线,设置最后离线时间 updateDevice.setLastOfflineTime(LocalDateTime.now()); } - - // 2.3 设置状态更新时间 - updateDevice.setStatusLastUpdateTime(LocalDateTime.now()); - // 2.4 更新到数据库 + // 2.3 更新到数据库 deviceMapper.updateById(updateDevice); } @@ -254,4 +188,42 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); } + /** + * 生成 deviceSecret + * + * @return 生成的 deviceSecret + */ + private String generateDeviceSecret() { + return IdUtil.fastSimpleUUID(); + } + + /** + * 生成 MQTT Client ID + * + * @return 生成的 MQTT Client ID + */ + private String generateMqttClientId() { + return IdUtil.fastSimpleUUID(); + } + + /** + * 生成 MQTT Username + * + * @param deviceName 设备名称 + * @param productKey 产品 Key + * @return 生成的 MQTT Username + */ + private String generateMqttUsername(String deviceName, String productKey) { + return deviceName + "&" + productKey; + } + + /** + * 生成 MQTT Password + * + * @return 生成的 MQTT Password + */ + private String generateMqttPassword() { + return RandomUtil.randomString(32); + } + } \ No newline at end of file From 9041de2da57bd7fac4af894d5f44f82e20e58cf3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Dec 2024 16:34:26 +0800 Subject: [PATCH 020/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E7=AD=9B=E9=80=89=E5=8E=BB=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../device/vo/device/IotDevicePageReqVO.java | 52 +------------------ .../iot/dal/mysql/device/IotDeviceMapper.java | 16 +----- 2 files changed, 4 insertions(+), 64 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java index 90ded8089..791ee34b6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java @@ -8,11 +8,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @Schema(description = "管理后台 - IoT 设备分页 Request VO") @Data @@ -20,11 +15,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @ToString(callSuper = true) public class IotDevicePageReqVO extends PageParam { - // TODO @芋艿:需要去掉一些多余的字段; - - @Schema(description = "设备唯一标识符", example = "24602") - private String deviceKey; - @Schema(description = "设备名称", example = "王五") private String deviceName; @@ -34,53 +24,15 @@ public class IotDevicePageReqVO extends PageParam { @Schema(description = "产品编号", example = "26202") private Long productId; - @Schema(description = "产品标识") - private String productKey; - @Schema(description = "设备类型", example = "1") @InEnum(IotProductDeviceTypeEnum.class) private Integer deviceType; - @Schema(description = "网关设备 ID", example = "16380") - private Long gatewayId; - @Schema(description = "设备状态", example = "1") @InEnum(IotDeviceStatusEnum.class) private Integer status; - @Schema(description = "设备状态最后更新时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] statusLastUpdateTime; - - @Schema(description = "最后上线时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] lastOnlineTime; - - @Schema(description = "最后离线时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] lastOfflineTime; - - @Schema(description = "设备激活时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] activeTime; - - @Schema(description = "设备密钥,用于设备认证,需安全存储") - private String deviceSecret; - - @Schema(description = "MQTT 客户端 ID", example = "24602") - private String mqttClientId; - - @Schema(description = "MQTT 用户名", example = "芋艿") - private String mqttUsername; - - @Schema(description = "MQTT 密码") - private String mqttPassword; - - @Schema(description = "认证类型(如一机一密、动态注册)", example = "2") - private String authType; - - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; + @Schema(description = "设备分组编号", example = "1024") + private Long groupId; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 65af1f17a..0459c964d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.mysql.device; +import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; @@ -17,27 +18,14 @@ import java.util.List; @Mapper public interface IotDeviceMapper extends BaseMapperX { - // TODO @haohao:可能多余的查询条件,要去掉哈 default PageResult selectPage(IotDevicePageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(IotDeviceDO::getDeviceKey, reqVO.getDeviceKey()) .likeIfPresent(IotDeviceDO::getDeviceName, reqVO.getDeviceName()) .eqIfPresent(IotDeviceDO::getProductId, reqVO.getProductId()) - .eqIfPresent(IotDeviceDO::getProductKey, reqVO.getProductKey()) .eqIfPresent(IotDeviceDO::getDeviceType, reqVO.getDeviceType()) .likeIfPresent(IotDeviceDO::getNickname, reqVO.getNickname()) - .eqIfPresent(IotDeviceDO::getGatewayId, reqVO.getGatewayId()) .eqIfPresent(IotDeviceDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(IotDeviceDO::getStatusLastUpdateTime, reqVO.getStatusLastUpdateTime()) - .betweenIfPresent(IotDeviceDO::getLastOnlineTime, reqVO.getLastOnlineTime()) - .betweenIfPresent(IotDeviceDO::getLastOfflineTime, reqVO.getLastOfflineTime()) - .betweenIfPresent(IotDeviceDO::getActiveTime, reqVO.getActiveTime()) - .eqIfPresent(IotDeviceDO::getDeviceSecret, reqVO.getDeviceSecret()) - .eqIfPresent(IotDeviceDO::getMqttClientId, reqVO.getMqttClientId()) - .likeIfPresent(IotDeviceDO::getMqttUsername, reqVO.getMqttUsername()) - .eqIfPresent(IotDeviceDO::getMqttPassword, reqVO.getMqttPassword()) - .eqIfPresent(IotDeviceDO::getAuthType, reqVO.getAuthType()) - .betweenIfPresent(IotDeviceDO::getCreateTime, reqVO.getCreateTime()) + .apply(ObjectUtil.isNotNull(reqVO.getGroupId()), "FIND_IN_SET(" + reqVO.getGroupId() + ",group_ids) > 0") .orderByDesc(IotDeviceDO::getId)); } From b143bc177f8fccb778eb60a2f470cc99f33a77a2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Dec 2024 17:00:58 +0800 Subject: [PATCH 021/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E5=88=86?= =?UTF-8?q?=E7=BB=84=E7=9A=84=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 3 + .../vo/group/IotDeviceGroupPageReqVO.java | 27 +++++++ .../device/vo/group/IotDeviceGroupRespVO.java | 27 +++++++ .../vo/group/IotDeviceGroupSaveReqVO.java | 26 +++++++ .../dataobject/device/IotDeviceGroupDO.java | 44 ++++++++++++ .../mysql/device/IotDeviceGroupMapper.java | 25 +++++++ .../service/device/IotDeviceGroupService.java | 54 ++++++++++++++ .../device/IotDeviceGroupServiceImpl.java | 70 +++++++++++++++++++ 8 files changed, 276 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceGroupDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 0d8b7d8bc..55e560757 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -33,4 +33,7 @@ public interface ErrorCodeConstants { // ========== 产品分类 1-050-004-000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在"); + // ========== 设备分组 1-050-005-000 ========== + ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在"); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java new file mode 100644 index 000000000..1490f2894 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.group; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 设备分组分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class IotDeviceGroupPageReqVO extends PageParam { + + @Schema(description = "分组名字", example = "李四") + private String name; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java new file mode 100644 index 000000000..50306cb76 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.group; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 设备分组 Response VO") +@Data +public class IotDeviceGroupRespVO { + + @Schema(description = "分组 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "3583") + private Long id; + + @Schema(description = "分组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String name; + + @Schema(description = "分组状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "分组描述", example = "你说的对") + private String description; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupSaveReqVO.java new file mode 100644 index 000000000..491cd9366 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupSaveReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.group; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 设备分组新增/修改 Request VO") +@Data +public class IotDeviceGroupSaveReqVO { + + @Schema(description = "分组 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "3583") + private Long id; + + @Schema(description = "分组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "分组名字不能为空") + private String name; + + @Schema(description = "分组状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "分组状态不能为空") + private Integer status; + + @Schema(description = "分组描述", example = "你说的对") + private String description; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceGroupDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceGroupDO.java new file mode 100644 index 000000000..44c471216 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceGroupDO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.device; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * IoT 设备分组 DO + * + * @author 芋道源码 + */ +@TableName("iot_device_group") +@KeySequence("iot_device_group_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotDeviceGroupDO extends BaseDO { + + /** + * 分组 ID + */ + @TableId + private Long id; + /** + * 分组名字 + */ + private String name; + /** + * 分组状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 分组描述 + */ + private String description; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java new file mode 100644 index 000000000..492f7ee3f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.device; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * IoT 设备分组 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotDeviceGroupMapper extends BaseMapperX { + + default PageResult selectPage(IotDeviceGroupPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotDeviceGroupDO::getName, reqVO.getName()) + .betweenIfPresent(IotDeviceGroupDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotDeviceGroupDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java new file mode 100644 index 000000000..f4966b18f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; +import jakarta.validation.Valid; + +/** + * IoT 设备分组 Service 接口 + * + * @author 芋道源码 + */ +public interface IotDeviceGroupService { + + /** + * 创建IoT 设备分组 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDeviceGroup(@Valid IotDeviceGroupSaveReqVO createReqVO); + + /** + * 更新IoT 设备分组 + * + * @param updateReqVO 更新信息 + */ + void updateDeviceGroup(@Valid IotDeviceGroupSaveReqVO updateReqVO); + + /** + * 删除IoT 设备分组 + * + * @param id 编号 + */ + void deleteDeviceGroup(Long id); + + /** + * 获得IoT 设备分组 + * + * @param id 编号 + * @return IoT 设备分组 + */ + IotDeviceGroupDO getDeviceGroup(Long id); + + /** + * 获得IoT 设备分组分页 + * + * @param pageReqVO 分页查询 + * @return IoT 设备分组分页 + */ + PageResult getDeviceGroupPage(IotDeviceGroupPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java new file mode 100644 index 000000000..957775c5e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; +import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceGroupMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_GROUP_NOT_EXISTS; + +/** + * IoT 设备分组 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class IotDeviceGroupServiceImpl implements IotDeviceGroupService { + + @Resource + private IotDeviceGroupMapper deviceGroupMapper; + + @Override + public Long createDeviceGroup(IotDeviceGroupSaveReqVO createReqVO) { + // 插入 + IotDeviceGroupDO deviceGroup = BeanUtils.toBean(createReqVO, IotDeviceGroupDO.class); + deviceGroupMapper.insert(deviceGroup); + // 返回 + return deviceGroup.getId(); + } + + @Override + public void updateDeviceGroup(IotDeviceGroupSaveReqVO updateReqVO) { + // 校验存在 + validateDeviceGroupExists(updateReqVO.getId()); + // 更新 + IotDeviceGroupDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceGroupDO.class); + deviceGroupMapper.updateById(updateObj); + } + + @Override + public void deleteDeviceGroup(Long id) { + // 校验存在 + validateDeviceGroupExists(id); + // 删除 + deviceGroupMapper.deleteById(id); + } + + private void validateDeviceGroupExists(Long id) { + if (deviceGroupMapper.selectById(id) == null) { + throw exception(DEVICE_GROUP_NOT_EXISTS); + } + } + + @Override + public IotDeviceGroupDO getDeviceGroup(Long id) { + return deviceGroupMapper.selectById(id); + } + + @Override + public PageResult getDeviceGroupPage(IotDeviceGroupPageReqVO pageReqVO) { + return deviceGroupMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file From b5ac5261394db19b535fdbe18ee1aac2a892baae Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Dec 2024 18:41:46 +0800 Subject: [PATCH 022/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=95=8C=E9=9D=A2=E5=A2=9E=E5=8A=A0=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=88=86=E7=BB=84=E9=80=89=E6=8B=A9=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 2 +- .../device/IotDeviceGroupController.java | 88 +++++++++++++++++++ .../device/vo/device/IotDeviceRespVO.java | 4 + .../device/vo/device/IotDeviceSaveReqVO.java | 5 ++ .../device/vo/group/IotDeviceGroupRespVO.java | 3 + .../dal/dataobject/device/IotDeviceDO.java | 2 +- .../mysql/device/IotDeviceGroupMapper.java | 6 ++ .../iot/dal/mysql/device/IotDeviceMapper.java | 6 ++ .../service/device/IotDeviceGroupService.java | 48 ++++++++-- .../device/IotDeviceGroupServiceImpl.java | 25 +++++- .../iot/service/device/IotDeviceService.java | 8 ++ .../service/device/IotDeviceServiceImpl.java | 13 +++ 12 files changed, 198 insertions(+), 12 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceGroupController.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 55e560757..b75effb10 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -35,5 +35,5 @@ public interface ErrorCodeConstants { // ========== 设备分组 1-050-005-000 ========== ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在"); - + ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除"); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceGroupController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceGroupController.java new file mode 100644 index 000000000..d19cf7fc9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceGroupController.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceGroupService; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - IoT 设备分组") +@RestController +@RequestMapping("/iot/device-group") +@Validated +public class IotDeviceGroupController { + + @Resource + private IotDeviceGroupService deviceGroupService; + @Resource + private IotDeviceService deviceService; + + @PostMapping("/create") + @Operation(summary = "创建设备分组") + @PreAuthorize("@ss.hasPermission('iot:device-group:create')") + public CommonResult createDeviceGroup(@Valid @RequestBody IotDeviceGroupSaveReqVO createReqVO) { + return success(deviceGroupService.createDeviceGroup(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新设备分组") + @PreAuthorize("@ss.hasPermission('iot:device-group:update')") + public CommonResult updateDeviceGroup(@Valid @RequestBody IotDeviceGroupSaveReqVO updateReqVO) { + deviceGroupService.updateDeviceGroup(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除设备分组") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:device-group:delete')") + public CommonResult deleteDeviceGroup(@RequestParam("id") Long id) { + deviceGroupService.deleteDeviceGroup(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得设备分组") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:device-group:query')") + public CommonResult getDeviceGroup(@RequestParam("id") Long id) { + IotDeviceGroupDO deviceGroup = deviceGroupService.getDeviceGroup(id); + return success(BeanUtils.toBean(deviceGroup, IotDeviceGroupRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得设备分组分页") + @PreAuthorize("@ss.hasPermission('iot:device-group:query')") + public CommonResult> getDeviceGroupPage(@Valid IotDeviceGroupPageReqVO pageReqVO) { + PageResult pageResult = deviceGroupService.getDeviceGroupPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotDeviceGroupRespVO.class, + group -> group.setDeviceCount(deviceService.getDeviceCountByGroupId(group.getId())))); + } + + @GetMapping("/simple-list") + @Operation(summary = "获取设备分组的精简信息列表", description = "只包含被开启的分组,主要用于前端的下拉选项") + public CommonResult> getSimpleDeviceGroupList() { + List list = deviceGroupService.getDeviceGroupListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, group -> // 只返回 id、name 字段 + new IotDeviceGroupRespVO().setId(group.getId()).setName(group.getName()))); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java index fd2fbaa68..9214adaf2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java @@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; +import java.util.Set; @Schema(description = "管理后台 - IoT 设备 Response VO") @Data @@ -23,6 +24,9 @@ public class IotDeviceRespVO { @ExcelProperty("设备名称备") private String deviceName; + @Schema(description = "设备分组编号数组", example = "1,2") + private Set groupIds; + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") @ExcelProperty("产品编号") private Long productId; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java index e4f23d97e..97220d57a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import java.util.Set; + @Schema(description = "管理后台 - IoT 设备新增/修改 Request VO") @Data public class IotDeviceSaveReqVO { @@ -25,6 +27,9 @@ public class IotDeviceSaveReqVO { @Schema(description = "设备图片", example = "https://iocoder.cn/1.png") private String picUrl; + @Schema(description = "设备分组编号数组", example = "1,2") + private Set groupIds; + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") private Long productId; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java index 50306cb76..4fd541502 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java @@ -24,4 +24,7 @@ public class IotDeviceGroupRespVO { @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; + @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long deviceCount; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index 6028c25fe..f396855f1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -57,7 +57,7 @@ public class IotDeviceDO extends BaseDO { /** * 设备分组编号集合 * - * 关联 TODO 芋艿: + * 关联 {@link IotDeviceGroupDO#getId()} */ @TableField(typeHandler = LongSetTypeHandler.class) private Set groupIds; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java index 492f7ee3f..605ce5270 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGro import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * IoT 设备分组 Mapper * @@ -22,4 +24,8 @@ public interface IotDeviceGroupMapper extends BaseMapperX { .orderByDesc(IotDeviceGroupDO::getId)); } + default List selectListByStatus(Integer status) { + return selectList(IotDeviceGroupDO::getStatus, status); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 0459c964d..59794c4ed 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -50,4 +50,10 @@ public interface IotDeviceMapper extends BaseMapperX { return selectList(IotDeviceDO::getDeviceType, deviceType); } + default Long selectCountByGroupId(Long groupId) { + return selectCount(new LambdaQueryWrapperX() + .apply("FIND_IN_SET(" + groupId + ",group_ids) > 0") + .orderByDesc(IotDeviceDO::getId)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java index f4966b18f..5219f2d4b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java @@ -1,11 +1,17 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; import jakarta.validation.Valid; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + /** * IoT 设备分组 Service 接口 * @@ -14,7 +20,7 @@ import jakarta.validation.Valid; public interface IotDeviceGroupService { /** - * 创建IoT 设备分组 + * 创建设备分组 * * @param createReqVO 创建信息 * @return 编号 @@ -22,33 +28,61 @@ public interface IotDeviceGroupService { Long createDeviceGroup(@Valid IotDeviceGroupSaveReqVO createReqVO); /** - * 更新IoT 设备分组 + * 更新设备分组 * * @param updateReqVO 更新信息 */ void updateDeviceGroup(@Valid IotDeviceGroupSaveReqVO updateReqVO); /** - * 删除IoT 设备分组 + * 删除设备分组 * * @param id 编号 */ void deleteDeviceGroup(Long id); /** - * 获得IoT 设备分组 + * 校验设备分组是否存在 + * + * @param ids 设备分组 ID 数组 + */ + default List validateDeviceGroupExists(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return List.of(); + } + return convertList(ids, this::validateDeviceGroupExists); + } + + /** + * 校验设备分组是否存在 + * + * @param id 设备分组 ID + * @return 设备分组 + */ + IotDeviceGroupDO validateDeviceGroupExists(Long id); + + /** + * 获得设备分组 * * @param id 编号 - * @return IoT 设备分组 + * @return 设备分组 */ IotDeviceGroupDO getDeviceGroup(Long id); /** - * 获得IoT 设备分组分页 + * 获得设备分组分页 * * @param pageReqVO 分页查询 - * @return IoT 设备分组分页 + * @return 设备分组分页 */ PageResult getDeviceGroupPage(IotDeviceGroupPageReqVO pageReqVO); + /** + * 获得设备分组列表 + * + * @param status 状态 + * @return 设备分组列表 + */ + List getDeviceGroupListByStatus(Integer status); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java index 957775c5e..cfa24784b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java @@ -10,7 +10,10 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.List; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_GROUP_NOT_EXISTS; /** @@ -25,6 +28,9 @@ public class IotDeviceGroupServiceImpl implements IotDeviceGroupService { @Resource private IotDeviceGroupMapper deviceGroupMapper; + @Resource + private IotDeviceService deviceService; + @Override public Long createDeviceGroup(IotDeviceGroupSaveReqVO createReqVO) { // 插入 @@ -45,16 +51,24 @@ public class IotDeviceGroupServiceImpl implements IotDeviceGroupService { @Override public void deleteDeviceGroup(Long id) { - // 校验存在 + // 1.1 校验存在 validateDeviceGroupExists(id); + // 1.2 校验是否存在设备 + if (deviceService.getDeviceCountByGroupId(id) > 0) { + throw exception(DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS); + } + // 删除 deviceGroupMapper.deleteById(id); } - private void validateDeviceGroupExists(Long id) { - if (deviceGroupMapper.selectById(id) == null) { + @Override + public IotDeviceGroupDO validateDeviceGroupExists(Long id) { + IotDeviceGroupDO group = deviceGroupMapper.selectById(id); + if (group == null) { throw exception(DEVICE_GROUP_NOT_EXISTS); } + return group; } @Override @@ -67,4 +81,9 @@ public class IotDeviceGroupServiceImpl implements IotDeviceGroupService { return deviceGroupMapper.selectPage(pageReqVO); } + @Override + public List getDeviceGroupListByStatus(Integer status) { + return deviceGroupMapper.selectListByStatus(status); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 3569c7597..8ae81e611 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -78,6 +78,14 @@ public interface IotDeviceService { */ Long getDeviceCountByProductId(Long productId); + /** + * 获得设备数量 + * + * @param groupId 分组编号 + * @return 设备数量 + */ + Long getDeviceCountByGroupId(Long groupId); + /** * 根据产品 key 和设备名称,获得设备信息 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index c882b7420..482dc606e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -42,6 +43,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { @Resource private IotProductService productService; + @Resource + @Lazy // 延迟加载,解决循环依赖 + private IotDeviceGroupService deviceGroupService; @Override public Long createDevice(IotDeviceSaveReqVO createReqVO) { @@ -63,6 +67,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { && createReqVO.getGatewayId() != null) { validateGatewayDeviceExists(createReqVO.getGatewayId()); } + // 1.5 校验分组存在 + deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds()); // 2.1 转换 VO 为 DO IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class, o -> { @@ -90,6 +96,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { && updateReqVO.getGatewayId() != null) { validateGatewayDeviceExists(updateReqVO.getGatewayId()); } + // 1.3 校验分组存在 + deviceGroupService.validateDeviceGroupExists(updateReqVO.getGroupIds()); // 2. 更新到数据库 IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); @@ -182,6 +190,11 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectCountByProductId(productId); } + @Override + public Long getDeviceCountByGroupId(Long groupId) { + return deviceMapper.selectCountByGroupId(groupId); + } + @Override @TenantIgnore public IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName) { From 345065815945b5512a7a87bb3becd99e6229e99d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Dec 2024 18:56:51 +0800 Subject: [PATCH 023/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=95=8C=E9=9D=A2=E5=A2=9E=E5=8A=A0=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/DictTypeConstants.java | 3 +++ .../admin/device/IotDeviceController.java | 19 ++++++++++++++ .../device/vo/device/IotDeviceRespVO.java | 25 ++++++++++++++----- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java index b5c34f14b..c8e6c70c1 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java @@ -13,4 +13,7 @@ public class DictTypeConstants { public static final String PROTOCOL_TYPE = "iot_protocol_type"; public static final String DATA_FORMAT = "iot_data_format"; public static final String VALIDATE_TYPE = "iot_validate_type"; + + public static final String DEVICE_STATUS = "iot_device_status"; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 2dee57d6d..affdd0a4d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -1,8 +1,11 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceRespVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; @@ -13,13 +16,16 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.io.IOException; import java.util.List; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -81,6 +87,19 @@ public class IotDeviceController { return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class)); } + @GetMapping("/export-excel") + @Operation(summary = "导出设备 Excel") + @PreAuthorize("@ss.hasPermission('iot:device:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDeviceExcel(@Valid IotDevicePageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + CommonResult> result = getDevicePage(exportReqVO); + // 导出 Excel + ExcelUtils.write(response, "设备.xls", "数据", IotDeviceRespVO.class, + result.getData().getList()); + } + @GetMapping("/count") @Operation(summary = "获得设备数量") @Parameter(name = "productId", description = "产品编号", example = "1") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java index 9214adaf2..151663759 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -8,6 +10,8 @@ import lombok.Data; import java.time.LocalDateTime; import java.util.Set; +import static cn.iocoder.yudao.module.iot.enums.DictTypeConstants.DEVICE_STATUS; + @Schema(description = "管理后台 - IoT 设备 Response VO") @Data @ExcelIgnoreUnannotated @@ -21,9 +25,21 @@ public class IotDeviceRespVO { private String deviceKey; @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") - @ExcelProperty("设备名称备") + @ExcelProperty("设备名称") private String deviceName; + @Schema(description = "设备备注名称", example = "张三") + @ExcelProperty("设备备注名称") + private String nickname; + + @Schema(description = "设备序列号", example = "1024") + @ExcelProperty("设备序列号") + private String serialNumber; + + @Schema(description = "设备图片", example = "我是一名码农") + @ExcelProperty("设备图片") + private String picUrl; + @Schema(description = "设备分组编号数组", example = "1,2") private Set groupIds; @@ -39,15 +55,12 @@ public class IotDeviceRespVO { @ExcelProperty("设备类型") private Integer deviceType; - @Schema(description = "设备备注名称", example = "张三") - @ExcelProperty("设备备注名称") - private String nickname; - @Schema(description = "网关设备 ID", example = "16380") private Long gatewayId; @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("设备状态") + @ExcelProperty(value = "设备状态", converter = DictConvert.class) + @DictFormat(DEVICE_STATUS) private Integer status; @Schema(description = "设备状态最后更新时间") From b02e396aff2885e402f598d300ad923d559396fd Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Dec 2024 19:12:42 +0800 Subject: [PATCH 024/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=95=8C=E9=9D=A2=E5=A2=9E=E5=8A=A0=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceController.java | 12 ++++++++- .../iot/service/device/IotDeviceService.java | 10 +++++++- .../service/device/IotDeviceServiceImpl.java | 25 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index affdd0a4d..417df2984 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -23,6 +23,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.io.IOException; +import java.util.Collection; import java.util.List; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; @@ -62,7 +63,7 @@ public class IotDeviceController { } @DeleteMapping("/delete") - @Operation(summary = "删除设备") + @Operation(summary = "删除单个设备") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('iot:device:delete')") public CommonResult deleteDevice(@RequestParam("id") Long id) { @@ -70,6 +71,15 @@ public class IotDeviceController { return success(true); } + @DeleteMapping("/delete-list") + @Operation(summary = "删除多个设备") + @Parameter(name = "ids", description = "编号数组", required = true) + @PreAuthorize("@ss.hasPermission('iot:device:delete')") + public CommonResult deleteDeviceList(@RequestParam("ids") Collection ids) { + deviceService.deleteDeviceList(ids); + return success(true); + } + @GetMapping("/get") @Operation(summary = "获得设备") @Parameter(name = "id", description = "编号", required = true, example = "1024") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 8ae81e611..a76f09486 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import jakarta.validation.Valid; import javax.annotation.Nullable; +import java.util.Collection; import java.util.List; /** @@ -33,12 +34,19 @@ public interface IotDeviceService { void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO); /** - * 删除设备 + * 删除单个设备 * * @param id 编号 */ void deleteDevice(Long id); + /** + * 删除多个设备 + * + * @param ids 编号数组 + */ + void deleteDeviceList(Collection ids); + /** * 获得设备 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 482dc606e..3af71593b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -18,10 +19,12 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Nullable; import java.time.LocalDateTime; +import java.util.Collection; import java.util.List; import java.util.Objects; @@ -117,6 +120,28 @@ public class IotDeviceServiceImpl implements IotDeviceService { deviceMapper.deleteById(id); } + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteDeviceList(Collection ids) { + // 1.1 校验存在 + if (CollUtil.isEmpty(ids)) { + return; + } + List devices = deviceMapper.selectBatchIds(ids); + if (CollUtil.isEmpty(devices)) { + return; + } + // 1.2 校验网关设备是否存在 + for (IotDeviceDO device : devices) { + if (device.getGatewayId() != null && deviceMapper.selectCountByGatewayId(device.getId()) > 0) { + throw exception(DEVICE_HAS_CHILDREN); + } + } + + // 2. 删除设备 + deviceMapper.deleteByIds(ids); + } + /** * 校验设备是否存在 * From 39ba4e72da281a90715baab359a8995627747f7a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Dec 2024 19:43:22 +0800 Subject: [PATCH 025/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=95=8C=E9=9D=A2=E5=A2=9E=E5=8A=A0=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=88=86=E7=BB=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceController.java | 17 +++++++++----- .../vo/device/IotDeviceUpdateGroupReqVO.java | 21 ++++++++++++++++++ .../iot/service/device/IotDeviceService.java | 22 +++++++++++++------ .../service/device/IotDeviceServiceImpl.java | 20 ++++++++++++++++- 4 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceUpdateGroupReqVO.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 417df2984..35b4abe93 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -6,10 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import io.swagger.v3.oas.annotations.Operation; @@ -62,6 +59,14 @@ public class IotDeviceController { return success(true); } + @PutMapping("/update-group") + @Operation(summary = "更新设备分组") + @PreAuthorize("@ss.hasPermission('iot:device:update')") + public CommonResult updateDeviceGroup(@Valid @RequestBody IotDeviceUpdateGroupReqVO updateReqVO) { + deviceService.updateDeviceGroup(updateReqVO); + return success(true); + } + @DeleteMapping("/delete") @Operation(summary = "删除单个设备") @Parameter(name = "id", description = "编号", required = true) @@ -102,7 +107,7 @@ public class IotDeviceController { @PreAuthorize("@ss.hasPermission('iot:device:export')") @ApiAccessLog(operateType = EXPORT) public void exportDeviceExcel(@Valid IotDevicePageReqVO exportReqVO, - HttpServletResponse response) throws IOException { + HttpServletResponse response) throws IOException { exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); CommonResult> result = getDevicePage(exportReqVO); // 导出 Excel @@ -125,7 +130,7 @@ public class IotDeviceController { @RequestParam(value = "deviceType", required = false) Integer deviceType) { List list = deviceService.getDeviceList(deviceType); return success(convertList(list, device -> // 只返回 id、name 字段 - new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName()))); + new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName()))); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceUpdateGroupReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceUpdateGroupReqVO.java new file mode 100644 index 000000000..bf66fbf98 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceUpdateGroupReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +import java.util.Set; + +@Schema(description = "管理后台 - IoT 设备更新分组 Request VO") +@Data +public class IotDeviceUpdateGroupReqVO { + + @Schema(description = "设备编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") + @NotEmpty(message = "设备编号列表不能为空") + private Set ids; + + @Schema(description = "分组编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") + @NotEmpty(message = "分组编号列表不能为空") + private Set groupIds; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index a76f09486..42101626c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceUpdateGroupReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import jakarta.validation.Valid; @@ -33,6 +34,20 @@ public interface IotDeviceService { */ void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO); + /** + * 更新设备状态 + * + * @param updateReqVO 更新信息 + */ + void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO); + + /** + * 更新设备分组 + * + * @param updateReqVO 更新信息 + */ + void updateDeviceGroup(@Valid IotDeviceUpdateGroupReqVO updateReqVO); + /** * 删除单个设备 * @@ -71,13 +86,6 @@ public interface IotDeviceService { */ List getDeviceList(@Nullable Integer deviceType); - /** - * 更新设备状态 - * - * @param updateReqVO 更新信息 - */ - void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO); - /** * 获得设备数量 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 3af71593b..29944eae7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/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.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceUpdateGroupReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; @@ -29,6 +30,7 @@ import java.util.List; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; /** @@ -67,7 +69,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { } // 1.4 校验父设备是否为合法网关 if (IotProductDeviceTypeEnum.isGateway(product.getDeviceType()) - && createReqVO.getGatewayId() != null) { + && createReqVO.getGatewayId() != null) { validateGatewayDeviceExists(createReqVO.getGatewayId()); } // 1.5 校验分组存在 @@ -107,6 +109,22 @@ public class IotDeviceServiceImpl implements IotDeviceService { deviceMapper.updateById(updateObj); } + @Override + @Transactional(rollbackFor = Exception.class) + public void updateDeviceGroup(IotDeviceUpdateGroupReqVO updateReqVO) { + // 1.1 校验设备存在 + List devices = deviceMapper.selectBatchIds(updateReqVO.getIds()); + if (CollUtil.isEmpty(devices)) { + return; + } + // 1.2 校验分组存在 + deviceGroupService.validateDeviceGroupExists(updateReqVO.getGroupIds()); + + // 3. 更新设备分组 + deviceMapper.updateBatch(convertList(devices, device -> new IotDeviceDO() + .setId(device.getId()).setGroupIds(updateReqVO.getGroupIds()))); + } + @Override public void deleteDevice(Long id) { // 1.1 校验存在 From 555310de66d18250116f14d2cf93f42155cc3862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 14 Dec 2024 21:51:17 +0800 Subject: [PATCH 026/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=8C=85?= =?UTF-8?q?=E5=90=AB=E6=8F=92=E4=BB=B6=E5=AE=9E=E4=BE=8B=E5=92=8C=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=E5=AE=9A=E4=B9=89=E5=8F=8A=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 8 + yudao-module-iot/pom.xml | 1 + .../module/iot/enums/ErrorCodeConstants.java | 13 +- .../enums/plugin/IotPluginDeployTypeEnum.java | 53 ++++ .../iot/enums/plugin/IotPluginStatusEnum.java | 57 ++++ .../iot/enums/plugin/IotPluginTypeEnum.java | 53 ++++ yudao-module-iot/yudao-module-iot-biz/pom.xml | 6 + .../plugininfo/PluginInfoController.java | 98 +++++++ .../plugininfo/vo/PluginInfoPageReqVO.java | 57 ++++ .../admin/plugininfo/vo/PluginInfoRespVO.java | 70 +++++ .../plugininfo/vo/PluginInfoSaveReqVO.java | 49 ++++ .../PluginInstanceController.java | 94 ++++++ .../vo/PluginInstancePageReqVO.java | 36 +++ .../vo/PluginInstanceRespVO.java | 43 +++ .../vo/PluginInstanceSaveReqVO.java | 35 +++ .../dataobject/plugininfo/PluginInfoDO.java | 78 +++++ .../plugininstance/PluginInstanceDO.java | 51 ++++ .../mysql/plugininfo/PluginInfoMapper.java | 36 +++ .../plugininstance/PluginInstanceMapper.java | 29 ++ .../framework/plugin/SpringConfiguration.java | 15 + .../service/plugininfo/PluginInfoService.java | 72 +++++ .../plugininfo/PluginInfoServiceImpl.java | 267 ++++++++++++++++++ .../plugininstance/PluginInstanceService.java | 54 ++++ .../PluginInstanceServiceImpl.java | 70 +++++ .../mapper/plugininfo/PluginInfoMapper.xml | 12 + .../plugininstance/PluginInstanceMapper.xml | 12 + .../plugininfo/PluginInfoServiceImplTest.java | 171 +++++++++++ .../PluginInstanceServiceImplTest.java | 150 ++++++++++ .../yudao-module-iot-plugin/pom.xml | 31 ++ .../yudao/module/iot/plugin/package-info.java | 6 + 30 files changed, 1726 insertions(+), 1 deletion(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/PluginInstanceController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininfo/PluginInfoMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininstance/PluginInstanceMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininfo/PluginInfoMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImplTest.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImplTest.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 486fe124b..6eaa89dfe 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -66,6 +66,7 @@ 2.7.0 3.0.6 1.2.5 + 0.9.0 3.5.0 4.11.0 @@ -605,6 +606,13 @@ ${mqtt.version} + + + org.pf4j + pf4j-spring + ${pf4j-spring.version} + + diff --git a/yudao-module-iot/pom.xml b/yudao-module-iot/pom.xml index 069af1699..d9002abea 100644 --- a/yudao-module-iot/pom.xml +++ b/yudao-module-iot/pom.xml @@ -10,6 +10,7 @@ yudao-module-iot-api yudao-module-iot-biz + yudao-module-iot-plugin 4.0.0 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index b75effb10..5f58109b3 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -36,4 +36,15 @@ public interface ErrorCodeConstants { // ========== 设备分组 1-050-005-000 ========== ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在"); ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除"); -} + + // ========== 插件信息 1-050-006-000 ========== + ErrorCode PLUGIN_INFO_NOT_EXISTS = new ErrorCode(1_050_006_000, "插件信息不存在"); + ErrorCode PLUGIN_INSTALL_FAILED = new ErrorCode(1_050_006_001, "插件安装失败"); + ErrorCode PLUGIN_INSTALL_FAILED_FILE_NAME_NOT_MATCH = new ErrorCode(1_050_006_002, "插件安装失败,文件名与原插件id不匹配"); + ErrorCode PLUGIN_INFO_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件"); + ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效"); + + // ========== 插件实例 1-050-007-000 ========== + ErrorCode PLUGIN_INSTANCE_NOT_EXISTS = new ErrorCode(1_050_007_000, "插件实例不存在"); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java new file mode 100644 index 000000000..fd15514c4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.iot.enums.plugin; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; + +import java.util.Arrays; + +/** + * IoT 部署方式枚举 + * + * @author haohao + */ +@Getter +public enum IotPluginDeployTypeEnum implements IntArrayValuable { + + UPLOAD(0, "上传jar"), + ALONE(1, "独立运行"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginDeployTypeEnum::getDeployType).toArray(); + + /** + * 部署方式 + */ + private final Integer deployType; + + /** + * 部署方式名 + */ + private final String name; + + IotPluginDeployTypeEnum(Integer deployType, String name) { + this.deployType = deployType; + this.name = name; + } + + public static IotPluginDeployTypeEnum fromDeployType(Integer deployType) { + for (IotPluginDeployTypeEnum value : values()) { + if (value.getDeployType().equals(deployType)) { + return value; + } + } + return null; + } + + public static boolean isValidDeployType(Integer deployType) { + return fromDeployType(deployType) != null; + } + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java new file mode 100644 index 000000000..25b172022 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.iot.enums.plugin; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; + +import java.util.Arrays; + +/** + * IoT 插件状态枚举 + * + * @author haohao + */ +@Getter +public enum IotPluginStatusEnum implements IntArrayValuable { + + STOPPED(0, "停止"), + RUNNING(1, "运行"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginStatusEnum::getStatus).toArray(); + + /** + * 状态 + */ + private final Integer status; + + /** + * 状态名 + */ + private final String name; + + IotPluginStatusEnum(Integer status, String name) { + this.status = status; + this.name = name; + } + + public static IotPluginStatusEnum fromState(Integer state) { + for (IotPluginStatusEnum value : values()) { + if (value.getStatus().equals(state)) { + return value; + } + } + return null; + } + + public static boolean isValidState(Integer state) { + return fromState(state) != null; + } + + public static boolean contains(Integer status) { + return Arrays.stream(values()).anyMatch(e -> e.getStatus().equals(status)); + } + + @Override + public int[] array() { + return new int[0]; + } +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java new file mode 100644 index 000000000..9e1e5d7f0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.iot.enums.plugin; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; + +import java.util.Arrays; + +/** + * IoT 插件类型枚举 + * + * @author haohao + */ +@Getter +public enum IotPluginTypeEnum implements IntArrayValuable { + + NORMAL(0, "普通插件"), + DEVICE(1, "设备插件"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + + /** + * 类型名 + */ + private final String name; + + IotPluginTypeEnum(Integer type, String name) { + this.type = type; + this.name = name; + } + + public static IotPluginTypeEnum fromType(Integer type) { + for (IotPluginTypeEnum value : values()) { + if (value.getType().equals(type)) { + return value; + } + } + return null; + } + + public static boolean isValidType(Integer type) { + return fromType(type) != null; + } + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 013287d2b..b003e1785 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -69,6 +69,12 @@ org.eclipse.paho org.eclipse.paho.client.mqttv3 + + + + org.pf4j + pf4j-spring + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java new file mode 100644 index 000000000..d87a14590 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import cn.iocoder.yudao.module.iot.service.plugininfo.PluginInfoService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_IS_EMPTY; + +@Tag(name = "管理后台 - IoT 插件信息") +@RestController +@RequestMapping("/iot/plugin-info") +@Validated +public class PluginInfoController { + + @Resource + private PluginInfoService pluginInfoService; + + @PostMapping("/create") + @Operation(summary = "创建插件信息") + @PreAuthorize("@ss.hasPermission('iot:plugin-info:create')") + public CommonResult createPluginInfo(@Valid @RequestBody PluginInfoSaveReqVO createReqVO) { + return success(pluginInfoService.createPluginInfo(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新插件信息") + @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") + public CommonResult updatePluginInfo(@Valid @RequestBody PluginInfoSaveReqVO updateReqVO) { + pluginInfoService.updatePluginInfo(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除插件信息") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:plugin-info:delete')") + public CommonResult deletePluginInfo(@RequestParam("id") Long id) { + pluginInfoService.deletePluginInfo(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得插件信息") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") + public CommonResult getPluginInfo(@RequestParam("id") Long id) { + PluginInfoDO pluginInfo = pluginInfoService.getPluginInfo(id); + return success(BeanUtils.toBean(pluginInfo, PluginInfoRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得插件信息分页") + @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") + public CommonResult> getPluginInfoPage(@Valid PluginInfoPageReqVO pageReqVO) { + PageResult pageResult = pluginInfoService.getPluginInfoPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, PluginInfoRespVO.class)); + } + + @RequestMapping(value = "/update-jar", + method = {RequestMethod.POST, RequestMethod.PUT}) // 解决 uni-app 不支持 Put 上传文件的问题 + @Operation(summary = "上传Jar包") + public CommonResult uploadJar( + @RequestParam("id") Long id, + @RequestParam("jar") MultipartFile file) throws Exception { + if (file.isEmpty()) { + throw exception(FILE_IS_EMPTY); + } + pluginInfoService.uploadJar(id, file); + return success(true); + } + + // 修改插件状态 + @PutMapping("/update-status") + @Operation(summary = "修改插件状态") + @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") + public CommonResult updateUserStatus(@Valid @RequestBody PluginInfoSaveReqVO reqVO) { + pluginInfoService.updatePluginStatus(reqVO.getId(), reqVO.getStatus()); + return success(true); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java new file mode 100644 index 000000000..1ddb8e1ff --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 插件信息分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PluginInfoPageReqVO extends PageParam { + + @Schema(description = "插件包id", example = "24627") + private String pluginId; + + @Schema(description = "插件名称", example = "赵六") + private String name; + + @Schema(description = "描述", example = "你猜") + private String description; + + @Schema(description = "部署方式", example = "2") + private Integer deployType; + + @Schema(description = "插件包文件名") + private String file; + + @Schema(description = "插件版本") + private String version; + + @Schema(description = "插件类型", example = "2") + private Integer type; + + @Schema(description = "设备插件协议类型") + private String protocol; + + @Schema(description = "状态") + private Integer status; + + @Schema(description = "插件配置项描述信息") + private String configSchema; + + @Schema(description = "插件配置信息") + private String config; + + @Schema(description = "插件脚本") + private String script; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java new file mode 100644 index 000000000..1e9f2b7dd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - IoT 插件信息 Response VO") +@Data +@ExcelIgnoreUnannotated +public class PluginInfoRespVO { + + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") + @ExcelProperty("主键ID") + private Long id; + + @Schema(description = "插件包id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") + @ExcelProperty("插件包id") + private String pluginId; + + @Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @ExcelProperty("插件名称") + private String name; + + @Schema(description = "描述", example = "你猜") + @ExcelProperty("描述") + private String description; + + @Schema(description = "部署方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("部署方式") + private Integer deployType; + + @Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("插件包文件名") + private String file; + + @Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("插件版本") + private String version; + + @Schema(description = "插件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("插件类型") + private Integer type; + + @Schema(description = "设备插件协议类型") + @ExcelProperty("设备插件协议类型") + private String protocol; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("状态") + private Integer status; + + @Schema(description = "插件配置项描述信息") + @ExcelProperty("插件配置项描述信息") + private String configSchema; + + @Schema(description = "插件配置信息") + @ExcelProperty("插件配置信息") + private String config; + + @Schema(description = "插件脚本") + @ExcelProperty("插件脚本") + private String script; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoSaveReqVO.java new file mode 100644 index 000000000..8ce254a3a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoSaveReqVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +@Schema(description = "管理后台 - IoT 插件信息新增/修改 Request VO") +@Data +public class PluginInfoSaveReqVO { + + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") + private Long id; + + @Schema(description = "插件包id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") + private String pluginId; + + @Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + + @Schema(description = "描述", example = "你猜") + private String description; + + @Schema(description = "部署方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer deployType; + + @Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED) + private String file; + + @Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED) + private String version; + + @Schema(description = "插件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer type; + + @Schema(description = "设备插件协议类型") + private String protocol; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer status; + + @Schema(description = "插件配置项描述信息") + private String configSchema; + + @Schema(description = "插件配置信息") + private String config; + + @Schema(description = "插件脚本") + private String script; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/PluginInstanceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/PluginInstanceController.java new file mode 100644 index 000000000..9382f8c6d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/PluginInstanceController.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininstance; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; +import cn.iocoder.yudao.module.iot.service.plugininstance.PluginInstanceService; + +@Tag(name = "管理后台 - IoT 插件实例") +@RestController +@RequestMapping("/iot/plugin-instance") +@Validated +public class PluginInstanceController { + + @Resource + private PluginInstanceService pluginInstanceService; + + @PostMapping("/create") + @Operation(summary = "创建IoT 插件实例") + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:create')") + public CommonResult createPluginInstance(@Valid @RequestBody PluginInstanceSaveReqVO createReqVO) { + return success(pluginInstanceService.createPluginInstance(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新IoT 插件实例") + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:update')") + public CommonResult updatePluginInstance(@Valid @RequestBody PluginInstanceSaveReqVO updateReqVO) { + pluginInstanceService.updatePluginInstance(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除IoT 插件实例") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:delete')") + public CommonResult deletePluginInstance(@RequestParam("id") Long id) { + pluginInstanceService.deletePluginInstance(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得IoT 插件实例") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:query')") + public CommonResult getPluginInstance(@RequestParam("id") Long id) { + PluginInstanceDO pluginInstance = pluginInstanceService.getPluginInstance(id); + return success(BeanUtils.toBean(pluginInstance, PluginInstanceRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得IoT 插件实例分页") + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:query')") + public CommonResult> getPluginInstancePage(@Valid PluginInstancePageReqVO pageReqVO) { + PageResult pageResult = pluginInstanceService.getPluginInstancePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, PluginInstanceRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出IoT 插件实例 Excel") + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportPluginInstanceExcel(@Valid PluginInstancePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = pluginInstanceService.getPluginInstancePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "IoT 插件实例.xls", "数据", PluginInstanceRespVO.class, + BeanUtils.toBean(list, PluginInstanceRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java new file mode 100644 index 000000000..2e678fa9d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 插件实例分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PluginInstancePageReqVO extends PageParam { + + @Schema(description = "插件主程序id", example = "23738") + private String mainId; + + @Schema(description = "插件id", example = "26498") + private Long pluginId; + + @Schema(description = "插件主程序所在ip") + private String ip; + + @Schema(description = "插件主程序端口") + private Integer port; + + @Schema(description = "心跳时间,心路时间超过30秒需要剔除") + private Long heartbeatAt; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java new file mode 100644 index 000000000..e71ff2904 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - IoT 插件实例 Response VO") +@Data +@ExcelIgnoreUnannotated +public class PluginInstanceRespVO { + + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "23864") + @ExcelProperty("主键ID") + private Long id; + + @Schema(description = "插件主程序id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23738") + @ExcelProperty("插件主程序id") + private String mainId; + + @Schema(description = "插件id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26498") + @ExcelProperty("插件id") + private Long pluginId; + + @Schema(description = "插件主程序所在ip", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("插件主程序所在ip") + private String ip; + + @Schema(description = "插件主程序端口", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("插件主程序端口") + private Integer port; + + @Schema(description = "心跳时间,心路时间超过30秒需要剔除", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("心跳时间,心路时间超过30秒需要剔除") + private Long heartbeatAt; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java new file mode 100644 index 000000000..8d927045d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; + +@Schema(description = "管理后台 - IoT 插件实例新增/修改 Request VO") +@Data +public class PluginInstanceSaveReqVO { + + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "23864") + private Long id; + + @Schema(description = "插件主程序id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23738") + @NotEmpty(message = "插件主程序id不能为空") + private String mainId; + + @Schema(description = "插件id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26498") + @NotNull(message = "插件id不能为空") + private Long pluginId; + + @Schema(description = "插件主程序所在ip", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "插件主程序所在ip不能为空") + private String ip; + + @Schema(description = "插件主程序端口", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "插件主程序端口不能为空") + private Integer port; + + @Schema(description = "心跳时间,心路时间超过30秒需要剔除", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "心跳时间,心路时间超过30秒需要剔除不能为空") + private Long heartbeatAt; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java new file mode 100644 index 000000000..07b2cc7ff --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * IoT 插件信息 DO + * + * @author 芋道源码 + */ +@TableName("iot_plugin_info") +@KeySequence("iot_plugin_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PluginInfoDO extends BaseDO { + + /** + * 主键ID + */ + @TableId + private Long id; + /** + * 插件包id + */ + private String pluginId; + /** + * 插件名称 + */ + private String name; + /** + * 描述 + */ + private String description; + /** + * 部署方式 + */ + private Integer deployType; + /** + * 插件包文件名 + */ + private String file; + /** + * 插件版本 + */ + private String version; + /** + * 插件类型 + */ + private Integer type; + /** + * 设备插件协议类型 + */ + private String protocol; + /** + * 状态 + */ + private Integer status; + /** + * 插件配置项描述信息 + */ + private String configSchema; + /** + * 插件配置信息 + */ + private String config; + /** + * 插件脚本 + */ + private String script; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java new file mode 100644 index 000000000..79dd762c7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * IoT 插件实例 DO + * + * @author 芋道源码 + */ +@TableName("iot_plugin_instance") +@KeySequence("iot_plugin_instance_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PluginInstanceDO extends BaseDO { + + /** + * 主键ID + */ + @TableId + private Long id; + /** + * 插件主程序id + */ + private String mainId; + /** + * 插件id + */ + private Long pluginId; + /** + * 插件主程序所在ip + */ + private String ip; + /** + * 插件主程序端口 + */ + private Integer port; + /** + * 心跳时间,心路时间超过30秒需要剔除 + */ + private Long heartbeatAt; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininfo/PluginInfoMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininfo/PluginInfoMapper.java new file mode 100644 index 000000000..69c0bd392 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininfo/PluginInfoMapper.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.plugininfo; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.*; + +/** + * IoT 插件信息 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface PluginInfoMapper extends BaseMapperX { + + default PageResult selectPage(PluginInfoPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(PluginInfoDO::getPluginId, reqVO.getPluginId()) + .likeIfPresent(PluginInfoDO::getName, reqVO.getName()) + .eqIfPresent(PluginInfoDO::getDescription, reqVO.getDescription()) + .eqIfPresent(PluginInfoDO::getDeployType, reqVO.getDeployType()) + .eqIfPresent(PluginInfoDO::getFile, reqVO.getFile()) + .eqIfPresent(PluginInfoDO::getVersion, reqVO.getVersion()) + .eqIfPresent(PluginInfoDO::getType, reqVO.getType()) + .eqIfPresent(PluginInfoDO::getProtocol, reqVO.getProtocol()) + .eqIfPresent(PluginInfoDO::getStatus, reqVO.getStatus()) + .eqIfPresent(PluginInfoDO::getConfigSchema, reqVO.getConfigSchema()) + .eqIfPresent(PluginInfoDO::getConfig, reqVO.getConfig()) + .eqIfPresent(PluginInfoDO::getScript, reqVO.getScript()) + .betweenIfPresent(PluginInfoDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PluginInfoDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininstance/PluginInstanceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininstance/PluginInstanceMapper.java new file mode 100644 index 000000000..6c7f1d231 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininstance/PluginInstanceMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.plugininstance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.*; + +/** + * IoT 插件实例 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface PluginInstanceMapper extends BaseMapperX { + + default PageResult selectPage(PluginInstancePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(PluginInstanceDO::getMainId, reqVO.getMainId()) + .eqIfPresent(PluginInstanceDO::getPluginId, reqVO.getPluginId()) + .eqIfPresent(PluginInstanceDO::getIp, reqVO.getIp()) + .eqIfPresent(PluginInstanceDO::getPort, reqVO.getPort()) + .eqIfPresent(PluginInstanceDO::getHeartbeatAt, reqVO.getHeartbeatAt()) + .betweenIfPresent(PluginInstanceDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(PluginInstanceDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java new file mode 100644 index 000000000..f43b69c12 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.iot.framework.plugin; + +import org.pf4j.spring.SpringPluginManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SpringConfiguration { + + @Bean + public SpringPluginManager pluginManager() { + return new SpringPluginManager(); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java new file mode 100644 index 000000000..f9ae48677 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.iot.service.plugininfo; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import jakarta.validation.Valid; +import org.springframework.web.multipart.MultipartFile; + +import java.io.InputStream; + +/** + * IoT 插件信息 Service 接口 + * + * @author 芋道源码 + */ +public interface PluginInfoService { + + /** + * 创建IoT 插件信息 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createPluginInfo(@Valid PluginInfoSaveReqVO createReqVO); + + /** + * 更新IoT 插件信息 + * + * @param updateReqVO 更新信息 + */ + void updatePluginInfo(@Valid PluginInfoSaveReqVO updateReqVO); + + /** + * 删除IoT 插件信息 + * + * @param id 编号 + */ + void deletePluginInfo(Long id); + + /** + * 获得IoT 插件信息 + * + * @param id 编号 + * @return IoT 插件信息 + */ + PluginInfoDO getPluginInfo(Long id); + + /** + * 获得IoT 插件信息分页 + * + * @param pageReqVO 分页查询 + * @return IoT 插件信息分页 + */ + PageResult getPluginInfoPage(PluginInfoPageReqVO pageReqVO); + + /** + * 上传插件的 JAR 包 + * + * @param id 插件id + * @param file 文件 + */ + void uploadJar(Long id, MultipartFile file); + + /** + * 更新插件的状态 + * + * @param id 插件id + * @param status 状态 + */ + void updatePluginStatus(Long id, Integer status); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java new file mode 100644 index 000000000..65ad6ad1d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java @@ -0,0 +1,267 @@ +package cn.iocoder.yudao.module.iot.service.plugininfo; + +import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.PluginDescriptor; +import org.pf4j.PluginState; +import org.pf4j.PluginWrapper; +import org.pf4j.spring.SpringPluginManager; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.multipart.MultipartFile; + +import java.nio.file.Path; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; + +/** + * IoT 插件信息 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class PluginInfoServiceImpl implements PluginInfoService { + + @Resource + private PluginInfoMapper pluginInfoMapper; + + @Resource + private SpringPluginManager pluginManager; + + @Resource + private FileApi fileApi; + + @Override + public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) { + // 插入 + PluginInfoDO pluginInfo = BeanUtils.toBean(createReqVO, PluginInfoDO.class); + pluginInfoMapper.insert(pluginInfo); + // 返回 + return pluginInfo.getId(); + } + + @Override + public void updatePluginInfo(PluginInfoSaveReqVO updateReqVO) { + // 校验存在 + validatePluginInfoExists(updateReqVO.getId()); + // 更新 + PluginInfoDO updateObj = BeanUtils.toBean(updateReqVO, PluginInfoDO.class); + pluginInfoMapper.updateById(updateObj); + } + + @Override + public void deletePluginInfo(Long id) { + // 校验存在 + PluginInfoDO pluginInfoDO = validatePluginInfoExists(id); + + // 停止插件 + if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { + throw exception(PLUGIN_INFO_DELETE_FAILED_RUNNING); + } + + // 卸载插件 + PluginWrapper plugin = pluginManager.getPlugin(pluginInfoDO.getPluginId()); + if (plugin != null) { + // 查询插件是否是启动状态 + if (plugin.getPluginState().equals(PluginState.STARTED)) { + // 停止插件 + pluginManager.stopPlugin(plugin.getPluginId()); + } + // 卸载插件 + pluginManager.unloadPlugin(plugin.getPluginId()); + } + + // 删除 + pluginInfoMapper.deleteById(id); + } + + private PluginInfoDO validatePluginInfoExists(Long id) { + PluginInfoDO pluginInfo = pluginInfoMapper.selectById(id); + if (pluginInfo == null) { + throw exception(PLUGIN_INFO_NOT_EXISTS); + } + return pluginInfo; + } + + @Override + public PluginInfoDO getPluginInfo(Long id) { + return pluginInfoMapper.selectById(id); + } + + @Override + public PageResult getPluginInfoPage(PluginInfoPageReqVO pageReqVO) { + return pluginInfoMapper.selectPage(pageReqVO); + } + + @Override + public void uploadJar(Long id, MultipartFile file) { + // 1. 校验存在 + PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); + + // 2. 判断文件名称与插件 ID 是否匹配 + String pluginId = pluginInfoDo.getPluginId(); + + // 3. 停止卸载旧的插件 + // 3.1. 获取插件信息 + PluginWrapper plugin = pluginManager.getPlugin(pluginId); + if (plugin != null) { + // 3.2. 如果插件状态是启动的,停止插件 + if (plugin.getPluginState().equals(PluginState.STARTED)) { + pluginManager.stopPlugin(pluginId); + } + // 3.3. 卸载插件 + pluginManager.unloadPlugin(pluginId); + } + + // 4. 上传插件 + String pluginIdNew; + try { + String path = fileApi.createFile(IoUtil.readBytes(file.getInputStream())); + Path pluginPath = Path.of(path); + pluginIdNew = pluginManager.loadPlugin(pluginPath); + } catch (Exception e) { + throw exception(PLUGIN_INSTALL_FAILED); + } + + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginIdNew); + if (pluginWrapper == null) { + throw exception(PLUGIN_INSTALL_FAILED); + } + + + // 5. 读取配置文件和脚本 + String configJson = ""; + String script = ""; + + pluginInfoDo.setPluginId(pluginIdNew); + pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); + pluginInfoDo.setFile(file.getOriginalFilename()); + pluginInfoDo.setConfigSchema(configJson); + pluginInfoDo.setScript(script); + + PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); + pluginInfoDo.setVersion(pluginDescriptor.getVersion()); + pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription()); + pluginInfoMapper.updateById(pluginInfoDo); + + + // 5. 读取配置文件和脚本 +// String configJson = ""; + // String script = ""; +// try (JarFile jarFile = new JarFile(pluginInfoUpdate.getPluginPath())) { +// // 5.1 获取config文件在jar包中的路径 +// String configFile = "classes/config.json"; +// JarEntry configEntry = jarFile.getJarEntry(configFile); +// +// if (configEntry != null) { +// // 5.2 读取配置文件 +// configJson = IoUtil.read(jarFile.getInputStream(configEntry), Charset.defaultCharset()); +// log.info("configJson:{}", configJson); +// } +// +// // 5.3 读取script.js脚本 +// String scriptFile = "classes/script.js"; +// JarEntry scriptEntity = jarFile.getJarEntry(scriptFile); +// if (scriptEntity != null) { +// // 5.4 读取脚本文件 +// script = IoUtil.read(jarFile.getInputStream(scriptEntity), Charset.defaultCharset()); +// log.info("script:{}", script); +// } +// } catch (Exception e) { +// throw exception(PLUGIN_INSTALL_FAILED); +// } + + +// PluginState pluginState = pluginInfoUpdate.getPluginState(); +// if (pluginState == PluginState.STARTED) { +// pluginInfoDo.setStatus(IotPluginStatusEnum.RUNNING.getStatus()); +// } +// pluginInfoDo.setPluginId(pluginInfoUpdate.getPluginId()); +// pluginInfoDo.setFile(file.getOriginalFilename()); +// pluginInfoDo.setConfigSchema(configJson); +// pluginInfoDo.setScript(script); +// +// PluginDescriptor pluginDescriptor = pluginInfoUpdate.getPluginDescriptor(); +// pluginInfoDo.setVersion(pluginDescriptor.getPluginVersion()); +// pluginInfoDo.setDescription(pluginDescriptor.getDescription()); +// pluginInfoMapper.updateById(pluginInfoDo); + } + + @Override + public void updatePluginStatus(Long id, Integer status) { + // 1. 校验存在 + PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); + + // 插件状态无效 + if (!IotPluginStatusEnum.contains(status)) { + throw exception(PLUGIN_STATUS_INVALID); + } + + // 插件包为空 +// String pluginId = pluginInfoDo.getPluginId(); +// if (StrUtil.isBlank(pluginId)) { +// throw exception(PLUGIN_INFO_NOT_EXISTS); +// } +// com.gitee.starblues.core.PluginInfo pluginInfo = pluginOperator.getPluginInfo(pluginId); +// if (pluginInfo != null) { +// if (pluginInfoDo.getStatus().equals(IotPluginStatusEnum.RUNNING.getStatus()) && pluginInfo.getPluginState() != PluginState.STARTED) { +// // 启动插件 +// pluginOperator.start(pluginId); +// } else if (pluginInfoDo.getStatus().equals(IotPluginStatusEnum.STOPPED.getStatus()) && pluginInfo.getPluginState() == PluginState.STARTED) { +// // 停止插件 +// pluginOperator.stop(pluginId); +// } +// } else { +// // 已经停止,未获取到插件 +// if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { +// throw exception(PLUGIN_STATUS_INVALID); +// } +// } + pluginInfoDo.setStatus(status); + pluginInfoMapper.updateById(pluginInfoDo); + } + + @PostConstruct + public void init() { + Executors.newSingleThreadScheduledExecutor().schedule(this::startPlugins, 3, TimeUnit.SECONDS); + } + + @SneakyThrows + private void startPlugins() { +// while (!pluginOperator.inited()) { +// Thread.sleep(1000L); +// } + + for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { + if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { + continue; + } + log.info("start plugin:{}", pluginInfoDO.getPluginId()); + try { +// com.gitee.starblues.core.PluginInfo plugin = pluginOperator.getPluginInfo(pluginInfoDO.getPluginId()); +// if (plugin != null) { +// pluginOperator.start(plugin.getPluginId()); +// } + } catch (Exception e) { + log.error("start plugin error", e); + } + } + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceService.java new file mode 100644 index 000000000..0789c4638 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.service.plugininstance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstancePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstanceSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; +import jakarta.validation.Valid; + +/** + * IoT 插件实例 Service 接口 + * + * @author 芋道源码 + */ +public interface PluginInstanceService { + + /** + * 创建IoT 插件实例 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createPluginInstance(@Valid PluginInstanceSaveReqVO createReqVO); + + /** + * 更新IoT 插件实例 + * + * @param updateReqVO 更新信息 + */ + void updatePluginInstance(@Valid PluginInstanceSaveReqVO updateReqVO); + + /** + * 删除IoT 插件实例 + * + * @param id 编号 + */ + void deletePluginInstance(Long id); + + /** + * 获得IoT 插件实例 + * + * @param id 编号 + * @return IoT 插件实例 + */ + PluginInstanceDO getPluginInstance(Long id); + + /** + * 获得IoT 插件实例分页 + * + * @param pageReqVO 分页查询 + * @return IoT 插件实例分页 + */ + PageResult getPluginInstancePage(PluginInstancePageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java new file mode 100644 index 000000000..405efe163 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.iot.service.plugininstance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstancePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstanceSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; +import cn.iocoder.yudao.module.iot.dal.mysql.plugininstance.PluginInstanceMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INSTANCE_NOT_EXISTS; + +/** + * IoT 插件实例 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class PluginInstanceServiceImpl implements PluginInstanceService { + + @Resource + private PluginInstanceMapper pluginInstanceMapper; + + @Override + public Long createPluginInstance(PluginInstanceSaveReqVO createReqVO) { + // 插入 + PluginInstanceDO pluginInstance = BeanUtils.toBean(createReqVO, PluginInstanceDO.class); + pluginInstanceMapper.insert(pluginInstance); + // 返回 + return pluginInstance.getId(); + } + + @Override + public void updatePluginInstance(PluginInstanceSaveReqVO updateReqVO) { + // 校验存在 + validatePluginInstanceExists(updateReqVO.getId()); + // 更新 + PluginInstanceDO updateObj = BeanUtils.toBean(updateReqVO, PluginInstanceDO.class); + pluginInstanceMapper.updateById(updateObj); + } + + @Override + public void deletePluginInstance(Long id) { + // 校验存在 + validatePluginInstanceExists(id); + // 删除 + pluginInstanceMapper.deleteById(id); + } + + private void validatePluginInstanceExists(Long id) { + if (pluginInstanceMapper.selectById(id) == null) { + throw exception(PLUGIN_INSTANCE_NOT_EXISTS); + } + } + + @Override + public PluginInstanceDO getPluginInstance(Long id) { + return pluginInstanceMapper.selectById(id); + } + + @Override + public PageResult getPluginInstancePage(PluginInstancePageReqVO pageReqVO) { + return pluginInstanceMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininfo/PluginInfoMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininfo/PluginInfoMapper.xml new file mode 100644 index 000000000..f24f7e14c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininfo/PluginInfoMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml new file mode 100644 index 000000000..2d297c785 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImplTest.java new file mode 100644 index 000000000..d921161f8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImplTest.java @@ -0,0 +1,171 @@ +package cn.iocoder.yudao.module.iot.service.plugininfo; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import jakarta.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.springframework.context.annotation.Import; + +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link PluginInfoServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(PluginInfoServiceImpl.class) +public class PluginInfoServiceImplTest extends BaseDbUnitTest { + + @Resource + private PluginInfoServiceImpl pluginInfoService; + + @Resource + private PluginInfoMapper pluginInfoMapper; + + @Test + public void testCreatePluginInfo_success() { + // 准备参数 + PluginInfoSaveReqVO createReqVO = randomPojo(PluginInfoSaveReqVO.class).setId(null); + + // 调用 + Long pluginInfoId = pluginInfoService.createPluginInfo(createReqVO); + // 断言 + assertNotNull(pluginInfoId); + // 校验记录的属性是否正确 + PluginInfoDO pluginInfo = pluginInfoMapper.selectById(pluginInfoId); + assertPojoEquals(createReqVO, pluginInfo, "id"); + } + + @Test + public void testUpdatePluginInfo_success() { + // mock 数据 + PluginInfoDO dbPluginInfo = randomPojo(PluginInfoDO.class); + pluginInfoMapper.insert(dbPluginInfo);// @Sql: 先插入出一条存在的数据 + // 准备参数 + PluginInfoSaveReqVO updateReqVO = randomPojo(PluginInfoSaveReqVO.class, o -> { + o.setId(dbPluginInfo.getId()); // 设置更新的 ID + }); + + // 调用 + pluginInfoService.updatePluginInfo(updateReqVO); + // 校验是否更新正确 + PluginInfoDO pluginInfo = pluginInfoMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, pluginInfo); + } + + @Test + public void testUpdatePluginInfo_notExists() { + // 准备参数 + PluginInfoSaveReqVO updateReqVO = randomPojo(PluginInfoSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> pluginInfoService.updatePluginInfo(updateReqVO), PLUGIN_INFO_NOT_EXISTS); + } + + @Test + public void testDeletePluginInfo_success() { + // mock 数据 + PluginInfoDO dbPluginInfo = randomPojo(PluginInfoDO.class); + pluginInfoMapper.insert(dbPluginInfo);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbPluginInfo.getId(); + + // 调用 + pluginInfoService.deletePluginInfo(id); + // 校验数据不存在了 + assertNull(pluginInfoMapper.selectById(id)); + } + + @Test + public void testDeletePluginInfo_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> pluginInfoService.deletePluginInfo(id), PLUGIN_INFO_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetPluginInfoPage() { + // mock 数据 + PluginInfoDO dbPluginInfo = randomPojo(PluginInfoDO.class, o -> { // 等会查询到 + o.setPluginId(null); + o.setName(null); + o.setDescription(null); + o.setDeployType(null); + o.setFile(null); + o.setVersion(null); + o.setType(null); + o.setProtocol(null); + o.setStatus(null); + o.setConfigSchema(null); + o.setConfig(null); + o.setScript(null); + o.setCreateTime(null); + }); + pluginInfoMapper.insert(dbPluginInfo); + // 测试 pluginId 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setPluginId(null))); + // 测试 name 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setName(null))); + // 测试 description 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setDescription(null))); + // 测试 deployType 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setDeployType(null))); + // 测试 file 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setFile(null))); + // 测试 version 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setVersion(null))); + // 测试 type 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setType(null))); + // 测试 protocol 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setProtocol(null))); + // 测试 state 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setStatus(null))); + // 测试 configSchema 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setConfigSchema(null))); + // 测试 config 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setConfig(null))); + // 测试 script 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setScript(null))); + // 测试 createTime 不匹配 + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setCreateTime(null))); + // 准备参数 + PluginInfoPageReqVO reqVO = new PluginInfoPageReqVO(); + reqVO.setPluginId(null); + reqVO.setName(null); + reqVO.setDescription(null); + reqVO.setDeployType(null); + reqVO.setFile(null); + reqVO.setVersion(null); + reqVO.setType(null); + reqVO.setProtocol(null); + reqVO.setStatus(null); + reqVO.setConfigSchema(null); + reqVO.setConfig(null); + reqVO.setScript(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = pluginInfoService.getPluginInfoPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbPluginInfo, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImplTest.java new file mode 100644 index 000000000..fe6235bde --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImplTest.java @@ -0,0 +1,150 @@ +package cn.iocoder.yudao.module.iot.service.plugininstance; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import jakarta.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; +import cn.iocoder.yudao.module.iot.dal.mysql.plugininstance.PluginInstanceMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link PluginInstanceServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(PluginInstanceServiceImpl.class) +public class PluginInstanceServiceImplTest extends BaseDbUnitTest { + + @Resource + private PluginInstanceServiceImpl pluginInstanceService; + + @Resource + private PluginInstanceMapper pluginInstanceMapper; + + @Test + public void testCreatePluginInstance_success() { + // 准备参数 + PluginInstanceSaveReqVO createReqVO = randomPojo(PluginInstanceSaveReqVO.class).setId(null); + + // 调用 + Long pluginInstanceId = pluginInstanceService.createPluginInstance(createReqVO); + // 断言 + assertNotNull(pluginInstanceId); + // 校验记录的属性是否正确 + PluginInstanceDO pluginInstance = pluginInstanceMapper.selectById(pluginInstanceId); + assertPojoEquals(createReqVO, pluginInstance, "id"); + } + + @Test + public void testUpdatePluginInstance_success() { + // mock 数据 + PluginInstanceDO dbPluginInstance = randomPojo(PluginInstanceDO.class); + pluginInstanceMapper.insert(dbPluginInstance);// @Sql: 先插入出一条存在的数据 + // 准备参数 + PluginInstanceSaveReqVO updateReqVO = randomPojo(PluginInstanceSaveReqVO.class, o -> { + o.setId(dbPluginInstance.getId()); // 设置更新的 ID + }); + + // 调用 + pluginInstanceService.updatePluginInstance(updateReqVO); + // 校验是否更新正确 + PluginInstanceDO pluginInstance = pluginInstanceMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, pluginInstance); + } + + @Test + public void testUpdatePluginInstance_notExists() { + // 准备参数 + PluginInstanceSaveReqVO updateReqVO = randomPojo(PluginInstanceSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> pluginInstanceService.updatePluginInstance(updateReqVO), PLUGIN_INSTANCE_NOT_EXISTS); + } + + @Test + public void testDeletePluginInstance_success() { + // mock 数据 + PluginInstanceDO dbPluginInstance = randomPojo(PluginInstanceDO.class); + pluginInstanceMapper.insert(dbPluginInstance);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbPluginInstance.getId(); + + // 调用 + pluginInstanceService.deletePluginInstance(id); + // 校验数据不存在了 + assertNull(pluginInstanceMapper.selectById(id)); + } + + @Test + public void testDeletePluginInstance_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> pluginInstanceService.deletePluginInstance(id), PLUGIN_INSTANCE_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetPluginInstancePage() { + // mock 数据 + PluginInstanceDO dbPluginInstance = randomPojo(PluginInstanceDO.class, o -> { // 等会查询到 + o.setMainId(null); + o.setPluginId(null); + o.setIp(null); + o.setPort(null); + o.setHeartbeatAt(null); + o.setCreateTime(null); + }); + pluginInstanceMapper.insert(dbPluginInstance); + // 测试 mainId 不匹配 + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setMainId(null))); + // 测试 pluginId 不匹配 + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setPluginId(null))); + // 测试 ip 不匹配 + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setIp(null))); + // 测试 port 不匹配 + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setPort(null))); + // 测试 heartbeatAt 不匹配 + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setHeartbeatAt(null))); + // 测试 createTime 不匹配 + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setCreateTime(null))); + // 准备参数 + PluginInstancePageReqVO reqVO = new PluginInstancePageReqVO(); + reqVO.setMainId(null); + reqVO.setPluginId(null); + reqVO.setIp(null); + reqVO.setPort(null); + reqVO.setHeartbeatAt(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = pluginInstanceService.getPluginInstancePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbPluginInstance, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/pom.xml new file mode 100644 index 000000000..49c321581 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/pom.xml @@ -0,0 +1,31 @@ + + + + yudao-module-iot + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-module-iot-plugin + jar + + ${project.artifactId} + + 物联网 模块 - 插件 + + + + + cn.iocoder.boot + yudao-common + + + + org.pf4j + pf4j-spring + + + + diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java new file mode 100644 index 000000000..567dcb038 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java @@ -0,0 +1,6 @@ +/** + * 占位 + * + * TODO 芋艿:后续删除 + */ +package cn.iocoder.yudao.module.iot.plugin; From dea8883f8243b5bd2d67c5213c9b9ac76a24d9dc Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 15 Dec 2024 08:38:12 +0800 Subject: [PATCH 027/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=8F=92=E4=BB=B6=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=9B=B8=E5=85=B3=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enums/plugin/IotPluginDeployTypeEnum.java | 2 +- .../iot/enums/plugin/IotPluginStatusEnum.java | 9 +- .../iot/enums/plugin/IotPluginTypeEnum.java | 13 +- .../plugininfo/PluginInfoController.java | 2 - .../plugininfo/vo/PluginInfoPageReqVO.java | 8 +- .../admin/plugininfo/vo/PluginInfoRespVO.java | 13 +- .../vo/PluginInstancePageReqVO.java | 1 + .../dataobject/plugininfo/PluginInfoDO.java | 9 +- .../plugininstance/PluginInstanceDO.java | 14 +- .../service/device/IotDeviceDataService.java | 1 - .../plugininfo/PluginInfoServiceImplTest.java | 171 ------------------ .../PluginInstanceServiceImplTest.java | 150 --------------- 12 files changed, 39 insertions(+), 354 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImplTest.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImplTest.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java index fd15514c4..11898f683 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java @@ -13,7 +13,7 @@ import java.util.Arrays; @Getter public enum IotPluginDeployTypeEnum implements IntArrayValuable { - UPLOAD(0, "上传jar"), + UPLOAD(0, "上传 jar"), // TODO @haohao:UPLOAD 和 ALONE 感觉有点冲突,前者是部署方式,后者是运行方式。这个后续再讨论下哈 ALONE(1, "独立运行"); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginDeployTypeEnum::getDeployType).toArray(); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java index 25b172022..9aba854b0 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java @@ -42,6 +42,11 @@ public enum IotPluginStatusEnum implements IntArrayValuable { return null; } + @Override + public int[] array() { + return ARRAYS; + } + public static boolean isValidState(Integer state) { return fromState(state) != null; } @@ -50,8 +55,4 @@ public enum IotPluginStatusEnum implements IntArrayValuable { return Arrays.stream(values()).anyMatch(e -> e.getStatus().equals(status)); } - @Override - public int[] array() { - return new int[0]; - } } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java index 9e1e5d7f0..27368d268 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.enums.plugin; import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Arrays; @@ -10,6 +11,7 @@ import java.util.Arrays; * * @author haohao */ +@AllArgsConstructor @Getter public enum IotPluginTypeEnum implements IntArrayValuable { @@ -28,11 +30,12 @@ public enum IotPluginTypeEnum implements IntArrayValuable { */ private final String name; - IotPluginTypeEnum(Integer type, String name) { - this.type = type; - this.name = name; + @Override + public int[] array() { + return ARRAYS; } + // TODO @haohao:可以使用 hutool 简化 public static IotPluginTypeEnum fromType(Integer type) { for (IotPluginTypeEnum value : values()) { if (value.getType().equals(type)) { @@ -46,8 +49,4 @@ public enum IotPluginTypeEnum implements IntArrayValuable { return fromType(type) != null; } - @Override - public int[] array() { - return ARRAYS; - } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java index d87a14590..b7efd088e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java @@ -20,7 +20,6 @@ import org.springframework.web.multipart.MultipartFile; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_IS_EMPTY; @Tag(name = "管理后台 - IoT 插件信息") @@ -86,7 +85,6 @@ public class PluginInfoController { return success(true); } - // 修改插件状态 @PutMapping("/update-status") @Operation(summary = "修改插件状态") @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java index 1ddb8e1ff..a3b36da9d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginTypeEnum; import lombok.*; import io.swagger.v3.oas.annotations.media.Schema; import cn.iocoder.yudao.framework.common.pojo.PageParam; @@ -8,13 +10,12 @@ import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +// TODO @haohao:只查询必要字段哈 @Schema(description = "管理后台 - IoT 插件信息分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class PluginInfoPageReqVO extends PageParam { - @Schema(description = "插件包id", example = "24627") + @Schema(description = "插件包 ID ", example = "24627") private String pluginId; @Schema(description = "插件名称", example = "赵六") @@ -33,6 +34,7 @@ public class PluginInfoPageReqVO extends PageParam { private String version; @Schema(description = "插件类型", example = "2") + @InEnum(IotPluginTypeEnum.class) private Integer type; @Schema(description = "设备插件协议类型") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java index 1e9f2b7dd..6f081764a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java @@ -1,22 +1,23 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; +import lombok.Data; import java.time.LocalDateTime; -import com.alibaba.excel.annotation.*; @Schema(description = "管理后台 - IoT 插件信息 Response VO") @Data @ExcelIgnoreUnannotated public class PluginInfoRespVO { - @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") - @ExcelProperty("主键ID") + @Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") + @ExcelProperty("主键 ID") private Long id; - @Schema(description = "插件包id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") - @ExcelProperty("插件包id") + @Schema(description = "插件包 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") + @ExcelProperty("插件包 ID") private String pluginId; @Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java index 2e678fa9d..9fccdc0ae 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java @@ -8,6 +8,7 @@ import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +// TODO @haohao:建议搞个 plugin,然后里面分 info 和 instance。另外,是不是 info => config 会好点,插件配置? @Schema(description = "管理后台 - IoT 插件实例分页 Request VO") @Data @EqualsAndHashCode(callSuper = true) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java index 07b2cc7ff..043cdb9c8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java @@ -22,12 +22,13 @@ import lombok.*; public class PluginInfoDO extends BaseDO { /** - * 主键ID + * 主键 ID */ @TableId private Long id; + // TODO @haohao:这个是不是改成类似 key 之类的字段哈? /** - * 插件包id + * 插件包 ID */ private String pluginId; /** @@ -41,10 +42,12 @@ public class PluginInfoDO extends BaseDO { /** * 部署方式 */ + // TODO @haohao:枚举 private Integer deployType; /** * 插件包文件名 */ + // TODO @haohao:是不是叫 fileName 哈?避免后续有别的字段,类似 fileUrl? private String file; /** * 插件版本 @@ -53,6 +56,7 @@ public class PluginInfoDO extends BaseDO { /** * 插件类型 */ + // TODO @haohao:枚举 private Integer type; /** * 设备插件协议类型 @@ -61,6 +65,7 @@ public class PluginInfoDO extends BaseDO { /** * 状态 */ + // TODO @haohao:枚举 private Integer status; /** * 插件配置项描述信息 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java index 79dd762c7..17f295a55 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java @@ -1,12 +1,12 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance; -import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +// TODO @haohao:一些必要的关联、枚举 /** * IoT 插件实例 DO * @@ -28,7 +28,7 @@ public class PluginInstanceDO extends BaseDO { @TableId private Long id; /** - * 插件主程序id + * 插件主程序 ID */ private String mainId; /** @@ -44,7 +44,7 @@ public class PluginInstanceDO extends BaseDO { */ private Integer port; /** - * 心跳时间,心路时间超过30秒需要剔除 + * 心跳时间,心路时间超过 30 秒需要剔除 */ private Long heartbeatAt; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index 4f390ca3b..70fd23014 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -15,7 +15,6 @@ import java.util.Map; */ public interface IotDeviceDataService { - /** * 保存设备数据 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImplTest.java deleted file mode 100644 index d921161f8..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImplTest.java +++ /dev/null @@ -1,171 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.plugininfo; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import jakarta.annotation.Resource; - -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; - -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; -import cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper; -import cn.iocoder.yudao.framework.common.pojo.PageResult; - -import org.springframework.context.annotation.Import; - -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; -import static org.junit.jupiter.api.Assertions.*; - -/** - * {@link PluginInfoServiceImpl} 的单元测试类 - * - * @author 芋道源码 - */ -@Import(PluginInfoServiceImpl.class) -public class PluginInfoServiceImplTest extends BaseDbUnitTest { - - @Resource - private PluginInfoServiceImpl pluginInfoService; - - @Resource - private PluginInfoMapper pluginInfoMapper; - - @Test - public void testCreatePluginInfo_success() { - // 准备参数 - PluginInfoSaveReqVO createReqVO = randomPojo(PluginInfoSaveReqVO.class).setId(null); - - // 调用 - Long pluginInfoId = pluginInfoService.createPluginInfo(createReqVO); - // 断言 - assertNotNull(pluginInfoId); - // 校验记录的属性是否正确 - PluginInfoDO pluginInfo = pluginInfoMapper.selectById(pluginInfoId); - assertPojoEquals(createReqVO, pluginInfo, "id"); - } - - @Test - public void testUpdatePluginInfo_success() { - // mock 数据 - PluginInfoDO dbPluginInfo = randomPojo(PluginInfoDO.class); - pluginInfoMapper.insert(dbPluginInfo);// @Sql: 先插入出一条存在的数据 - // 准备参数 - PluginInfoSaveReqVO updateReqVO = randomPojo(PluginInfoSaveReqVO.class, o -> { - o.setId(dbPluginInfo.getId()); // 设置更新的 ID - }); - - // 调用 - pluginInfoService.updatePluginInfo(updateReqVO); - // 校验是否更新正确 - PluginInfoDO pluginInfo = pluginInfoMapper.selectById(updateReqVO.getId()); // 获取最新的 - assertPojoEquals(updateReqVO, pluginInfo); - } - - @Test - public void testUpdatePluginInfo_notExists() { - // 准备参数 - PluginInfoSaveReqVO updateReqVO = randomPojo(PluginInfoSaveReqVO.class); - - // 调用, 并断言异常 - assertServiceException(() -> pluginInfoService.updatePluginInfo(updateReqVO), PLUGIN_INFO_NOT_EXISTS); - } - - @Test - public void testDeletePluginInfo_success() { - // mock 数据 - PluginInfoDO dbPluginInfo = randomPojo(PluginInfoDO.class); - pluginInfoMapper.insert(dbPluginInfo);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbPluginInfo.getId(); - - // 调用 - pluginInfoService.deletePluginInfo(id); - // 校验数据不存在了 - assertNull(pluginInfoMapper.selectById(id)); - } - - @Test - public void testDeletePluginInfo_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> pluginInfoService.deletePluginInfo(id), PLUGIN_INFO_NOT_EXISTS); - } - - @Test - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 - public void testGetPluginInfoPage() { - // mock 数据 - PluginInfoDO dbPluginInfo = randomPojo(PluginInfoDO.class, o -> { // 等会查询到 - o.setPluginId(null); - o.setName(null); - o.setDescription(null); - o.setDeployType(null); - o.setFile(null); - o.setVersion(null); - o.setType(null); - o.setProtocol(null); - o.setStatus(null); - o.setConfigSchema(null); - o.setConfig(null); - o.setScript(null); - o.setCreateTime(null); - }); - pluginInfoMapper.insert(dbPluginInfo); - // 测试 pluginId 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setPluginId(null))); - // 测试 name 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setName(null))); - // 测试 description 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setDescription(null))); - // 测试 deployType 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setDeployType(null))); - // 测试 file 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setFile(null))); - // 测试 version 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setVersion(null))); - // 测试 type 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setType(null))); - // 测试 protocol 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setProtocol(null))); - // 测试 state 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setStatus(null))); - // 测试 configSchema 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setConfigSchema(null))); - // 测试 config 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setConfig(null))); - // 测试 script 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setScript(null))); - // 测试 createTime 不匹配 - pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setCreateTime(null))); - // 准备参数 - PluginInfoPageReqVO reqVO = new PluginInfoPageReqVO(); - reqVO.setPluginId(null); - reqVO.setName(null); - reqVO.setDescription(null); - reqVO.setDeployType(null); - reqVO.setFile(null); - reqVO.setVersion(null); - reqVO.setType(null); - reqVO.setProtocol(null); - reqVO.setStatus(null); - reqVO.setConfigSchema(null); - reqVO.setConfig(null); - reqVO.setScript(null); - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); - - // 调用 - PageResult pageResult = pluginInfoService.getPluginInfoPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbPluginInfo, pageResult.getList().get(0)); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImplTest.java deleted file mode 100644 index fe6235bde..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImplTest.java +++ /dev/null @@ -1,150 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.plugininstance; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; - -import jakarta.annotation.Resource; - -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; - -import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; -import cn.iocoder.yudao.module.iot.dal.mysql.plugininstance.PluginInstanceMapper; -import cn.iocoder.yudao.framework.common.pojo.PageResult; - -import jakarta.annotation.Resource; -import org.springframework.context.annotation.Import; -import java.util.*; -import java.time.LocalDateTime; - -import static cn.hutool.core.util.RandomUtil.*; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -/** - * {@link PluginInstanceServiceImpl} 的单元测试类 - * - * @author 芋道源码 - */ -@Import(PluginInstanceServiceImpl.class) -public class PluginInstanceServiceImplTest extends BaseDbUnitTest { - - @Resource - private PluginInstanceServiceImpl pluginInstanceService; - - @Resource - private PluginInstanceMapper pluginInstanceMapper; - - @Test - public void testCreatePluginInstance_success() { - // 准备参数 - PluginInstanceSaveReqVO createReqVO = randomPojo(PluginInstanceSaveReqVO.class).setId(null); - - // 调用 - Long pluginInstanceId = pluginInstanceService.createPluginInstance(createReqVO); - // 断言 - assertNotNull(pluginInstanceId); - // 校验记录的属性是否正确 - PluginInstanceDO pluginInstance = pluginInstanceMapper.selectById(pluginInstanceId); - assertPojoEquals(createReqVO, pluginInstance, "id"); - } - - @Test - public void testUpdatePluginInstance_success() { - // mock 数据 - PluginInstanceDO dbPluginInstance = randomPojo(PluginInstanceDO.class); - pluginInstanceMapper.insert(dbPluginInstance);// @Sql: 先插入出一条存在的数据 - // 准备参数 - PluginInstanceSaveReqVO updateReqVO = randomPojo(PluginInstanceSaveReqVO.class, o -> { - o.setId(dbPluginInstance.getId()); // 设置更新的 ID - }); - - // 调用 - pluginInstanceService.updatePluginInstance(updateReqVO); - // 校验是否更新正确 - PluginInstanceDO pluginInstance = pluginInstanceMapper.selectById(updateReqVO.getId()); // 获取最新的 - assertPojoEquals(updateReqVO, pluginInstance); - } - - @Test - public void testUpdatePluginInstance_notExists() { - // 准备参数 - PluginInstanceSaveReqVO updateReqVO = randomPojo(PluginInstanceSaveReqVO.class); - - // 调用, 并断言异常 - assertServiceException(() -> pluginInstanceService.updatePluginInstance(updateReqVO), PLUGIN_INSTANCE_NOT_EXISTS); - } - - @Test - public void testDeletePluginInstance_success() { - // mock 数据 - PluginInstanceDO dbPluginInstance = randomPojo(PluginInstanceDO.class); - pluginInstanceMapper.insert(dbPluginInstance);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbPluginInstance.getId(); - - // 调用 - pluginInstanceService.deletePluginInstance(id); - // 校验数据不存在了 - assertNull(pluginInstanceMapper.selectById(id)); - } - - @Test - public void testDeletePluginInstance_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> pluginInstanceService.deletePluginInstance(id), PLUGIN_INSTANCE_NOT_EXISTS); - } - - @Test - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 - public void testGetPluginInstancePage() { - // mock 数据 - PluginInstanceDO dbPluginInstance = randomPojo(PluginInstanceDO.class, o -> { // 等会查询到 - o.setMainId(null); - o.setPluginId(null); - o.setIp(null); - o.setPort(null); - o.setHeartbeatAt(null); - o.setCreateTime(null); - }); - pluginInstanceMapper.insert(dbPluginInstance); - // 测试 mainId 不匹配 - pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setMainId(null))); - // 测试 pluginId 不匹配 - pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setPluginId(null))); - // 测试 ip 不匹配 - pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setIp(null))); - // 测试 port 不匹配 - pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setPort(null))); - // 测试 heartbeatAt 不匹配 - pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setHeartbeatAt(null))); - // 测试 createTime 不匹配 - pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setCreateTime(null))); - // 准备参数 - PluginInstancePageReqVO reqVO = new PluginInstancePageReqVO(); - reqVO.setMainId(null); - reqVO.setPluginId(null); - reqVO.setIp(null); - reqVO.setPort(null); - reqVO.setHeartbeatAt(null); - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); - - // 调用 - PageResult pageResult = pluginInstanceService.getPluginInstancePage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbPluginInstance, pageResult.getList().get(0)); - } - -} \ No newline at end of file From 92c2717d461cc117ce0d2c595d3705606a58c287 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 15 Dec 2024 10:46:33 +0800 Subject: [PATCH 028/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E7=AE=A1?= =?UTF-8?q?=E7=90=86=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=89=B9=E9=87=8F=E5=AF=BC?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../admin/device/IotDeviceController.java | 26 ++++++ .../vo/device/IotDeviceImportExcelVO.java | 37 ++++++++ .../vo/device/IotDeviceImportRespVO.java | 23 +++++ .../mysql/device/IotDeviceGroupMapper.java | 4 + .../iot/dal/mysql/device/IotDeviceMapper.java | 4 + .../dal/mysql/product/IotProductMapper.java | 2 +- .../service/device/IotDeviceGroupService.java | 8 ++ .../device/IotDeviceGroupServiceImpl.java | 5 + .../iot/service/device/IotDeviceService.java | 13 ++- .../service/device/IotDeviceServiceImpl.java | 93 +++++++++++++++++-- .../service/product/IotProductService.java | 16 ++++ .../product/IotProductServiceImpl.java | 22 +++-- 13 files changed, 239 insertions(+), 15 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportRespVO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 5f58109b3..633b3cb4f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -29,6 +29,7 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_KEY_EXISTS = new ErrorCode(1_050_003_003, "设备标识已经存在"); ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在"); ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备"); + ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!"); // ========== 产品分类 1-050-004-000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 35b4abe93..e0c214bc1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -18,8 +18,10 @@ import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -133,4 +135,28 @@ public class IotDeviceController { new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName()))); } + @PostMapping("/import") + @Operation(summary = "导入设备") + @PreAuthorize("@ss.hasPermission('iot:device:import')") + public CommonResult importDevice( + @RequestParam("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) + throws Exception { + List list = ExcelUtils.read(file, IotDeviceImportExcelVO.class); + return success(deviceService.importDevice(list, updateSupport)); + } + + @GetMapping("/get-import-template") + @Operation(summary = "获得导入设备模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List list = Arrays.asList( + IotDeviceImportExcelVO.builder().deviceName("温度传感器001").parentDeviceName("gateway110") + .productKey("1de24640dfe").groupNames("灰度分组,生产分组").build(), + IotDeviceImportExcelVO.builder().deviceName("biubiu") + .productKey("YzvHxd4r67sT4s2B").groupNames("").build()); + // 输出 + ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java new file mode 100644 index 000000000..710e74263 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * 设备 Excel 导入 VO + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免设备导入有问题 +public class IotDeviceImportExcelVO { + + @ExcelProperty("设备名称") + @NotEmpty(message = "设备名称不能为空") + private String deviceName; + + @ExcelProperty("父设备名称") + @Schema(description = "父设备名称", example = "网关001") + private String parentDeviceName; + + @ExcelProperty("产品标识") + @NotEmpty(message = "产品标识不能为空") + private String productKey; + + @ExcelProperty("设备分组") + private String groupNames; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportRespVO.java new file mode 100644 index 000000000..bf52b123f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - IoT 设备导入 Response VO") +@Data +@Builder +public class IotDeviceImportRespVO { + + @Schema(description = "创建成功的设备名称数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List createDeviceNames; + + @Schema(description = "更新成功的设备名称数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List updateDeviceNames; + + @Schema(description = "导入失败的设备集合,key为设备名称,value为失败原因", requiredMode = Schema.RequiredMode.REQUIRED) + private Map failureDeviceNames; +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java index 605ce5270..1f80ae455 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java @@ -28,4 +28,8 @@ public interface IotDeviceGroupMapper extends BaseMapperX { return selectList(IotDeviceGroupDO::getStatus, status); } + default IotDeviceGroupDO selectByName(String name) { + return selectOne(IotDeviceGroupDO::getName, name); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 59794c4ed..893d7eefd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -29,6 +29,10 @@ public interface IotDeviceMapper extends BaseMapperX { .orderByDesc(IotDeviceDO::getId)); } + default IotDeviceDO selectByDeviceName(String deviceName) { + return selectOne(IotDeviceDO::getDeviceName, deviceName); + } + default IotDeviceDO selectByProductKeyAndDeviceName(String productKey, String deviceName) { return selectOne(IotDeviceDO::getProductKey, productKey, IotDeviceDO::getDeviceName, deviceName); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index eac1d29e8..aef149ae7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -23,7 +23,7 @@ public interface IotProductMapper extends BaseMapperX { } default IotProductDO selectByProductKey(String productKey) { - return selectOne(new LambdaQueryWrapperX().eq(IotProductDO::getProductKey, productKey)); + return selectOne(IotProductDO::getProductKey, productKey); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java index 5219f2d4b..45e6ab25e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java @@ -69,6 +69,14 @@ public interface IotDeviceGroupService { */ IotDeviceGroupDO getDeviceGroup(Long id); + /** + * 获得设备分组 + * + * @param name 名称 + * @return 设备分组 + */ + IotDeviceGroupDO getDeviceGroupByName(String name); + /** * 获得设备分组分页 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java index cfa24784b..06e5cb11d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java @@ -76,6 +76,11 @@ public class IotDeviceGroupServiceImpl implements IotDeviceGroupService { return deviceGroupMapper.selectById(id); } + @Override + public IotDeviceGroupDO getDeviceGroupByName(String name) { + return deviceGroupMapper.selectByName(name); + } + @Override public PageResult getDeviceGroupPage(IotDeviceGroupPageReqVO pageReqVO) { return deviceGroupMapper.selectPage(pageReqVO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 42101626c..b8a3511cd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSa import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceUpdateGroupReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceImportRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceImportExcelVO; import jakarta.validation.Valid; import javax.annotation.Nullable; @@ -71,7 +73,7 @@ public interface IotDeviceService { IotDeviceDO getDevice(Long id); /** - * 获得设备分页 + * ��得设备分页 * * @param pageReqVO 分页查询 * @return IoT 设备分页 @@ -111,4 +113,13 @@ public interface IotDeviceService { */ IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName); + /** + * 导入设备 + * + * @param importDevices 导入设备列表 + * @param updateSupport 是否支持更新 + * @return 导入结果 + */ + IotDeviceImportRespVO importDevice(List importDevices, boolean updateSupport); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 29944eae7..a43521ff9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -3,20 +3,22 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceUpdateGroupReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; +import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -25,9 +27,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Nullable; import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; -import java.util.Objects; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -244,6 +244,15 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); } + /** + * 生成 deviceKey + * + * @return 生成的 deviceKey + */ + private String generateDeviceKey() { + return RandomUtil.randomString(16); + } + /** * 生成 deviceSecret * @@ -282,4 +291,74 @@ public class IotDeviceServiceImpl implements IotDeviceService { return RandomUtil.randomString(32); } + @Override + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入 + public IotDeviceImportRespVO importDevice(List importDevices, boolean updateSupport) { + // 1. 参数校验 + if (CollUtil.isEmpty(importDevices)) { + throw exception(DEVICE_IMPORT_LIST_IS_EMPTY); + } + + // 2. 遍历,逐个创建 or 更新 + IotDeviceImportRespVO respVO = IotDeviceImportRespVO.builder().createDeviceNames(new ArrayList<>()) + .updateDeviceNames(new ArrayList<>()).failureDeviceNames(new LinkedHashMap<>()).build(); + importDevices.forEach(importDevice -> { + try { + // 2.1.1 校验字段是否符合要求 + try { + ValidationUtils.validate(importDevice); + } catch (ConstraintViolationException ex){ + respVO.getFailureDeviceNames().put(importDevice.getDeviceName(), ex.getMessage()); + return; + } + // 2.1.2 校验产品是否存在 + IotProductDO product = productService.validateProductExists(importDevice.getProductKey()); + // 2.1.3 校验父设备是否存在 + Long gatewayId = null; + if (StrUtil.isNotEmpty(importDevice.getParentDeviceName())) { + IotDeviceDO gatewayDevice = deviceMapper.selectByDeviceName(importDevice.getParentDeviceName()); + if (gatewayDevice == null) { + throw exception(DEVICE_GATEWAY_NOT_EXISTS); + } + if (!IotProductDeviceTypeEnum.isGateway(gatewayDevice.getDeviceType())) { + throw exception(DEVICE_NOT_GATEWAY); + } + gatewayId = gatewayDevice.getId(); + } + // 2.1.4 校验设备分组是否存在 + Set groupIds = new HashSet<>(); + if (StrUtil.isNotEmpty(importDevice.getGroupNames())) { + String[] groupNames = importDevice.getGroupNames().split(","); + for (String groupName : groupNames) { + IotDeviceGroupDO group = deviceGroupService.getDeviceGroupByName(groupName); + if (group == null) { + throw exception(DEVICE_GROUP_NOT_EXISTS); + } + groupIds.add(group.getId()); + } + } + + // 2.2.1 判断如果不存在,在进行插入 + IotDeviceDO existDevice = deviceMapper.selectByDeviceName(importDevice.getDeviceName()); + if (existDevice == null) { + createDevice(new IotDeviceSaveReqVO() + .setDeviceName(importDevice.getDeviceName()).setDeviceKey(generateDeviceKey()) + .setProductId(product.getId()).setGatewayId(gatewayId).setGroupIds(groupIds)); + respVO.getCreateDeviceNames().add(importDevice.getDeviceName()); + return; + } + // 2.2.2 如果存在,判断是否允许更新 + if (updateSupport) { + throw exception(DEVICE_KEY_EXISTS); + } + updateDevice(new IotDeviceSaveReqVO().setId(existDevice.getId()) + .setGatewayId(gatewayId).setGroupIds(groupIds)); + respVO.getUpdateDeviceNames().add(importDevice.getDeviceName()); + } catch (ServiceException ex) { + respVO.getFailureDeviceNames().put(importDevice.getDeviceName(), ex.getMessage()); + } + }); + return respVO; + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index bcbf13ef4..9a2e96f67 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -45,6 +45,22 @@ public interface IotProductService { */ IotProductDO getProduct(Long id); + /** + * 校验产品存在 + * + * @param id 编号 + * @return 产品 + */ + IotProductDO validateProductExists(Long id); + + /** + * 校验产品存在 + * + * @param productKey 产品 key + * @return 产品 + */ + IotProductDO validateProductExists(String productKey); + /** * 获得产品分页 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index b1d2d666b..e7c144388 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -71,16 +71,26 @@ public class IotProductServiceImpl implements IotProductService { productMapper.deleteById(id); } - private IotProductDO validateProductExists(Long id) { - IotProductDO iotProductDO = productMapper.selectById(id); - if (iotProductDO == null) { + @Override + public IotProductDO validateProductExists(Long id) { + IotProductDO product = productMapper.selectById(id); + if (product == null) { throw exception(PRODUCT_NOT_EXISTS); } - return iotProductDO; + return product; } - private void validateProductStatus(IotProductDO iotProductDO) { - if (Objects.equals(iotProductDO.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) { + @Override + public IotProductDO validateProductExists(String productKey) { + IotProductDO product = productMapper.selectByProductKey(productKey); + if (product == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + return product; + } + + private void validateProductStatus(IotProductDO product) { + if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) { throw exception(PRODUCT_STATUS_NOT_DELETE); } } From 741096e20861db1ce978e8b3a06178ed04d587cc Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 16 Dec 2024 10:50:48 +0800 Subject: [PATCH 029/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E4=BA=A7=E5=93=81=E7=89=A9=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotProductThingModelAccessModeEnum.java} | 7 +++-- .../IotProductThingModelTypeEnum.java} | 10 +++---- .../thingModel/ThingModelProperty.java | 6 +++-- .../dataType/ThingModelDataType.java | 4 +-- .../vo/IotThinkModelFunctionPageReqVO.java | 4 +-- .../vo/IotThinkModelFunctionSaveReqVO.java | 4 +-- .../convert/device/IotDeviceDataConvert.java | 15 ----------- .../IotThinkModelFunctionConvert.java | 8 +++--- .../dal/dataobject/tdengine/FieldParser.java | 2 +- .../IotThinkModelFunctionDO.java | 4 +-- .../device/IotDeviceDataServiceImpl.java | 6 ++--- .../tdengine/IotSuperTableServiceImpl.java | 7 +++-- .../IotThingModelMessageServiceImpl.java | 6 ++--- .../IotThinkModelFunctionServiceImpl.java | 27 ++++++++++--------- 14 files changed, 48 insertions(+), 62 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/{product/IotAccessModeEnum.java => thingmodel/IotProductThingModelAccessModeEnum.java} (61%) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/{product/IotProductFunctionTypeEnum.java => thingmodel/IotProductThingModelTypeEnum.java} (69%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java similarity index 61% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java index 64ece99ca..80c96837f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.enums.product; +package cn.iocoder.yudao.module.iot.enums.thingmodel; import lombok.AllArgsConstructor; import lombok.Getter; @@ -10,10 +10,9 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotAccessModeEnum { +public enum IotProductThingModelAccessModeEnum { - READ("r"), - WRITE("w"), + READ_ONLY("r"), READ_WRITE("rw"); private final String mode; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java similarity index 69% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java index c8a03a4d3..153e93ecc 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.enums.product; +package cn.iocoder.yudao.module.iot.enums.thingmodel; import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; @@ -13,13 +13,13 @@ import java.util.Arrays; */ @AllArgsConstructor @Getter -public enum IotProductFunctionTypeEnum implements IntArrayValuable { +public enum IotProductThingModelTypeEnum implements IntArrayValuable { PROPERTY(1, "属性"), SERVICE(2, "服务"), EVENT(3, "事件"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductFunctionTypeEnum::getType).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductThingModelTypeEnum::getType).toArray(); /** * 类型 @@ -30,8 +30,8 @@ public enum IotProductFunctionTypeEnum implements IntArrayValuable { */ private final String description; - public static IotProductFunctionTypeEnum valueOfType(Integer type) { - for (IotProductFunctionTypeEnum value : values()) { + public static IotProductThingModelTypeEnum valueOfType(Integer type) { + for (IotProductThingModelTypeEnum value : values()) { if (value.getType().equals(type)) { return value; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java index 025d37e76..46bceaeeb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMod import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelDataType; import lombok.Data; +import java.util.List; + @Data public class ThingModelProperty { @@ -21,7 +23,7 @@ public class ThingModelProperty { private String accessMode; // "rw"、"r"、"w" private Boolean required; - // TODO @haohao:这个是不是 dataSpecs 和 dataSpecsList?https://help.aliyun.com/zh/iot/developer-reference/api-a99t11 - private ThingModelDataType dataType; + private ThingModelDataType dataSpecs; + private List dataSpecsList; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java index ec5f04bbb..66284fe24 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Data; @Data -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "dataType", visible = true) @JsonSubTypes({ @JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"), @JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"), @@ -19,6 +19,6 @@ import lombok.Data; }) public abstract class ThingModelDataType { - private String type; + private String dataType; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java index 8a590d429..48b8f1ab5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -22,7 +22,7 @@ public class IotThinkModelFunctionPageReqVO extends PageParam { private String name; @Schema(description = "功能类型", example = "1") - @InEnum(IotProductFunctionTypeEnum.class) + @InEnum(IotProductThingModelTypeEnum.class) private Integer type; @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java index 7d51ce504..a7534d78f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; -import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -38,7 +38,7 @@ public class IotThinkModelFunctionSaveReqVO { @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "功能类型不能为空") - @InEnum(IotProductFunctionTypeEnum.class) + @InEnum(IotProductThingModelTypeEnum.class) private Integer type; @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java index 3bad54ba0..2de045679 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java @@ -1,23 +1,8 @@ package cn.iocoder.yudao.module.iot.convert.device; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; -import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import org.mapstruct.Mapper; -import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - @Mapper public interface IotDeviceDataConvert { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java index 764d4c030..f4f4bb87e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; -import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @@ -26,21 +26,21 @@ public interface IotThinkModelFunctionConvert { IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); default ThingModelProperty convertToProperty(IotThinkModelFunctionSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { + if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { return bean.getProperty(); } return null; } default ThingModelEvent convertToEvent(IotThinkModelFunctionSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductFunctionTypeEnum.EVENT.getType())) { + if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.EVENT.getType())) { return bean.getEvent(); } return null; } default ThingModelService convertToService(IotThinkModelFunctionSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductFunctionTypeEnum.SERVICE.getType())) { + if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.SERVICE.getType())) { return bean.getService(); } return null; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index 344d65c9a..daad0b458 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -39,7 +39,7 @@ public class FieldParser { ThingModelDataType type = property.getDataType(); // 将物模型字段类型映射为td字段类型 - String fType = TYPE_MAPPING.get(type.getType().toUpperCase()); + String fType = TYPE_MAPPING.get(type.getDataType().toUpperCase()); // 如果字段类型为NCHAR,默认长度为64 int dataLength = 0; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java index 02b2f9707..d3d889191 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -66,7 +66,7 @@ public class IotThinkModelFunctionDO extends BaseDO { /** * 功能类型 *

- * 枚举 {@link IotProductFunctionTypeEnum} + * 枚举 {@link IotProductThingModelTypeEnum} */ private Integer type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index d68287cd4..8fb0edc41 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkMod import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; -import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import jakarta.annotation.Resource; @@ -75,7 +75,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { // 2. 获取设备属性最新数据 List thinkModelFunctionList = thinkModelFunctionService.getThinkModelFunctionListByProductKey(device.getProductKey()); thinkModelFunctionList = thinkModelFunctionList.stream() - .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType() + .filter(function -> IotProductThingModelTypeEnum.PROPERTY.getType() .equals(function.getType())).toList(); // 3. 过滤标识符和属性名称 @@ -100,7 +100,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); deviceData.setThinkModelFunctionId(function.getId()); deviceData.setName(function.getName()); - deviceData.setDataType(function.getProperty().getDataType().getType()); + deviceData.setDataType(function.getProperty().getDataType().getDataType()); } list.add(deviceData); }); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java index 20989181e..1d16651d5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java @@ -10,8 +10,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; -import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -217,8 +216,8 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { thingModel.setProductKey(product.getProductKey()); List properties = functionList.stream() - .filter(function -> IotProductFunctionTypeEnum.PROPERTY.equals( - IotProductFunctionTypeEnum.valueOfType(function.getType()))) + .filter(function -> IotProductThingModelTypeEnum.PROPERTY.equals( + IotProductThingModelTypeEnum.valueOfType(function.getType()))) .map(this::buildThingModelProperty) .collect(Collectors.toList()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 9ffb47715..cf988ad99 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -17,7 +17,7 @@ import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; -import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import jakarta.annotation.Resource; @@ -94,7 +94,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ return iotThinkModelFunctionService .getThinkModelFunctionListByProductKey(productKey) .stream() - .filter(function -> IotProductFunctionTypeEnum.PROPERTY.getType().equals(function.getType())) + .filter(function -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(function.getType())) .toList(); } @@ -138,7 +138,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ .deviceId(device.getId()) .thinkModelFunctionId(iotThinkModelFunctionDO.getId()) .name(iotThinkModelFunctionDO.getName()) - .dataType(iotThinkModelFunctionDO.getProperty().getDataType().getType()) + .dataType(iotThinkModelFunctionDO.getProperty().getDataType().getDataType()) .build(); deviceDataRedisDAO.set(deviceData); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index bfccfb45a..18a47e808 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -18,8 +18,8 @@ import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunct import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; -import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum; -import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotSuperTableService; @@ -74,7 +74,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe thinkModelFunctionMapper.insert(function); // 6. 如果创建的是属性,需要更新默认的事件和服务 - if (Objects.equals(createReqVO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { + if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } return function.getId(); @@ -128,7 +128,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe thinkModelFunctionMapper.updateById(thinkModelFunction); // 5. 如果更新的是属性,需要更新默认的事件和服务 - if (Objects.equals(updateReqVO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { + if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } } @@ -156,7 +156,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe thinkModelFunctionMapper.deleteById(id); // 3. 如果删除的是属性,需要更新默认的事件和服务 - if (Objects.equals(functionDO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { + if (Objects.equals(functionDO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey()); } } @@ -210,7 +210,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe public void createDefaultEventsAndServices(Long productId, String productKey) { // 1. 获取当前属性列表 List propertyList = thinkModelFunctionMapper - .selectListByProductIdAndType(productId, IotProductFunctionTypeEnum.PROPERTY.getType()); + .selectListByProductIdAndType(productId, IotProductThingModelTypeEnum.PROPERTY.getType()); // 2. 生成新的事件和服务列表 List newFunctionList = new ArrayList<>(); @@ -237,7 +237,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), - Arrays.asList(IotProductFunctionTypeEnum.EVENT.getType(), IotProductFunctionTypeEnum.SERVICE.getType()) + Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) ); // 3.1 使用 diffList 方法比较新旧列表 @@ -300,7 +300,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe .setIdentifier(event.getIdentifier()) .setName(event.getName()) .setDescription(event.getDescription()) - .setType(IotProductFunctionTypeEnum.EVENT.getType()) + .setType(IotProductThingModelTypeEnum.EVENT.getType()) .setEvent(event); } @@ -314,7 +314,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe .setIdentifier(service.getIdentifier()) .setName(service.getName()) .setDescription(service.getDescription()) - .setType(IotProductFunctionTypeEnum.SERVICE.getType()) + .setType(IotProductThingModelTypeEnum.SERVICE.getType()) .setService(service); } @@ -358,9 +358,10 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } List inputData = new ArrayList<>(); + // TODO @puhui999: 需要重构 for (IotThinkModelFunctionDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); - if (IotAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { + if (IotProductThingModelAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { ThingModelArgument arg = new ThingModelArgument() .setIdentifier(property.getIdentifier()) .setName(property.getName()) @@ -399,7 +400,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe for (IotThinkModelFunctionDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); if (ObjectUtils.equalsAny(property.getAccessMode(), - IotAccessModeEnum.READ.getMode(), IotAccessModeEnum.READ_WRITE.getMode())) { + IotProductThingModelAccessModeEnum.READ.getMode(), IotProductThingModelAccessModeEnum.READ_WRITE.getMode())) { ThingModelArgument arg = new ThingModelArgument() .setIdentifier(property.getIdentifier()) .setName(property.getName()) @@ -430,10 +431,10 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 创建数组类型,元素类型为文本类型(字符串) ThingModelArrayType arrayType = new ThingModelArrayType(); - arrayType.setType("array"); + arrayType.setDataType("array"); ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs(); ThingModelTextType textType = new ThingModelTextType(); - textType.setType("text"); + textType.setDataType("text"); arraySpecs.setItem(textType); arrayType.setSpecs(arraySpecs); inputArg.setDataType(arrayType); From f930f31fababd8b6a0ecdde4d34a253d123ea244 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 16 Dec 2024 12:12:22 +0800 Subject: [PATCH 030/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E4=BA=A7=E5=93=81=E7=89=A9=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E5=B1=9E=E6=80=A7=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotProductThingModelController.java} | 18 +-- .../IotThinkModelFunctionController.http | 0 .../thingmodel}/ThingModelEvent.java | 4 +- .../thingmodel/ThingModelProperty.java | 56 +++++++ .../thingmodel}/ThingModelRespVO.java | 2 +- .../thingmodel}/ThingModelService.java | 4 +- .../dataType/ThingModelArgument.java | 4 +- .../dataType/ThingModelArrayDataSpecs.java | 35 +++++ .../ThingModelBoolOrEnumDataSpecs.java | 28 ++++ .../dataType/ThingModelDataSpecs.java | 34 ++++ .../ThingModelDateOrTextDataSpecs.java | 26 +++ .../dataType/ThingModelNumericDataSpec.java | 47 ++++++ .../vo/IotThinkModelFunctionPageReqVO.java | 2 +- .../vo/IotThinkModelFunctionRespVO.java | 8 +- .../vo/IotThinkModelFunctionSaveReqVO.java | 8 +- .../thingModel/ThingModelProperty.java | 29 ---- .../dataType/ThingModelArraySpecs.java | 17 -- .../dataType/ThingModelArrayType.java | 12 -- .../dataType/ThingModelBoolType.java | 12 -- .../dataType/ThingModelDataType.java | 24 --- .../dataType/ThingModelDateType.java | 10 -- .../dataType/ThingModelDoubleType.java | 18 --- .../dataType/ThingModelEnumType.java | 15 -- .../dataType/ThingModelFloatType.java | 20 --- .../dataType/ThingModelIntType.java | 18 --- .../dataType/ThingModelStructField.java | 13 -- .../dataType/ThingModelStructType.java | 14 -- .../dataType/ThingModelTextType.java | 20 --- .../IotThinkModelFunctionConvert.java | 18 +-- .../dataobject/device/IotDeviceDataDO.java | 10 +- .../IotProductThingModelDO.java} | 12 +- .../dal/dataobject/tdengine/FieldParser.java | 30 ++-- .../IotThinkModelFunctionMapper.java | 62 ++++---- .../device/IotDeviceDataServiceImpl.java | 7 +- .../tdengine/IotSuperTableService.java | 4 +- .../tdengine/IotSuperTableServiceImpl.java | 12 +- .../IotThingModelMessageServiceImpl.java | 27 ++-- .../IotThinkModelFunctionService.java | 14 +- .../IotThinkModelFunctionServiceImpl.java | 148 +++++++++--------- 39 files changed, 424 insertions(+), 418 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodelfunction/IotThinkModelFunctionController.java => productthingmodel/IotProductThingModelController.java} (80%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodelfunction => productthingmodel}/IotThinkModelFunctionController.http (100%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodelfunction/thingModel => productthingmodel/thingmodel}/ThingModelEvent.java (70%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelProperty.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodelfunction/thingModel => productthingmodel/thingmodel}/ThingModelRespVO.java (89%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodelfunction/thingModel => productthingmodel/thingmodel}/ThingModelService.java (72%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodelfunction/thingModel => productthingmodel/thingmodel}/dataType/ThingModelArgument.java (66%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodelfunction => productthingmodel}/vo/IotThinkModelFunctionPageReqVO.java (93%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodelfunction => productthingmodel}/vo/IotThinkModelFunctionRespVO.java (82%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodelfunction => productthingmodel}/vo/IotThinkModelFunctionSaveReqVO.java (83%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/{thinkmodelfunction/IotThinkModelFunctionDO.java => productthingmodel/IotProductThingModelDO.java} (77%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java similarity index 80% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java index 4f48f3628..851637c12 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java @@ -1,13 +1,13 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction; +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -26,7 +26,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @RestController @RequestMapping("/iot/think-model-function") @Validated -public class IotThinkModelFunctionController { +public class IotProductThingModelController { @Resource private IotThinkModelFunctionService thinkModelFunctionService; @@ -60,7 +60,7 @@ public class IotThinkModelFunctionController { @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") public CommonResult getThinkModelFunction(@RequestParam("id") Long id) { - IotThinkModelFunctionDO function = thinkModelFunctionService.getThinkModelFunction(id); + IotProductThingModelDO function = thinkModelFunctionService.getThinkModelFunction(id); return success(IotThinkModelFunctionConvert.INSTANCE.convert(function)); } @@ -69,7 +69,7 @@ public class IotThinkModelFunctionController { @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") public CommonResult> getThinkModelFunctionListByProductId(@RequestParam("productId") Long productId) { - List list = thinkModelFunctionService.getThinkModelFunctionListByProductId(productId); + List list = thinkModelFunctionService.getThinkModelFunctionListByProductId(productId); return success(IotThinkModelFunctionConvert.INSTANCE.convertList(list)); } @@ -77,7 +77,7 @@ public class IotThinkModelFunctionController { @Operation(summary = "获得产品物模型分页") @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") public CommonResult> getThinkModelFunctionPage(@Valid IotThinkModelFunctionPageReqVO pageReqVO) { - PageResult pageResult = thinkModelFunctionService.getThinkModelFunctionPage(pageReqVO); + PageResult pageResult = thinkModelFunctionService.getThinkModelFunctionPage(pageReqVO); return success(BeanUtils.toBean(pageResult, IotThinkModelFunctionRespVO.class)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotThinkModelFunctionController.http similarity index 100% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotThinkModelFunctionController.http diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelEvent.java similarity index 70% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelEvent.java index d7fa68758..11563dfa8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelEvent.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArgument; import lombok.Data; import java.util.List; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelProperty.java new file mode 100644 index 000000000..b07d00c94 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelProperty.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel; + +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; +import lombok.Data; + +import java.util.List; + +/** + * 物模型中的属性 + * + * dataSpecs 和 dataSpecsList 之中必须传入且只能传入一个 + * + * @author HUIHUI + */ +@Data +public class ThingModelProperty { + + /** + * 属性标识符 + */ + private String identifier; + /** + * 属性名称 + */ + private String name; + /** + * 属性描述 + */ + private String description; + /** + * 云端可以对该属性进行的操作类型 + * 关联枚举 {@link IotProductThingModelAccessModeEnum} + */ + private String accessMode; + /** + * 是否是标准品类的必选服务。 + * + * - true:是 + * - false:否 + */ + private Boolean required; + /** + * 数据类型,与 dataSpecs 的 dataType 保持一致 + */ + private String dataType; + /** + * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 + */ + private ThingModelDataSpecs dataSpecs; + /** + * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 + */ + private List dataSpecsList; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelRespVO.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelRespVO.java index d7478e54a..eeb0937bf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel; import lombok.*; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelService.java similarity index 72% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelService.java index d97e05e9c..dfcc8a64b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelService.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArgument; import lombok.Data; import java.util.List; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java similarity index 66% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java index 2be24004e..40d691971 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; import lombok.Data; @@ -7,7 +7,7 @@ public class ThingModelArgument { private String identifier; private String name; - private ThingModelDataType dataType; + private ThingModelDataSpecs dataType; /** * 用于区分输入或输出参数,"input" 或 "output" */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java new file mode 100644 index 000000000..4bbf14a5f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; + +import lombok.Data; + +import java.util.List; + +/** + * 物模型数据类型为数组的 DataSpec 定义 + * + * @author HUIHUI + */ +@Data +public class ThingModelArrayDataSpecs extends ThingModelDataSpecs { + + /** + * 数组中的元素个数。 + */ + private Long size; + /** + * 数组中的元素的数据类型。可选值:struct、int、float、double 或 text。 + */ + private String childDataType; + /** + * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中。 + * 仅当 dataType 不是列表型时,才传入此字段。 + */ + private ThingModelDataSpecs dataSpecs; + /** + * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中。 + * 仅当 dataType 是列表型时,才传入此字段。 + */ + private List dataSpecsList; + +} + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java new file mode 100644 index 000000000..c76342398 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 物模型数据类型为布尔型或枚举型的 DataSpec 定义 + * + * 数据类型,取值为 bool 或 enum。 + * + * @author HUIHUI + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelBoolOrEnumDataSpecs extends ThingModelDataSpecs { + + /** + * 枚举项的名称。 + * 可包含中文、大小写英文字母、数字、下划线(_)和短划线(-)。 + * 必须以中文、英文字母或数字开头,长度不超过 20 个字符。 + */ + private String name; + /** + * 枚举值。 + */ + private Integer value; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java new file mode 100644 index 000000000..a4a7847ff --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import lombok.Data; + +/** + * 抽象类 ThingModelDataSpecs + * + * 用于表示物模型数据的通用类型,根据具体的 "dataType" 字段动态映射到对应的子类。 + * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 + * + * @author HUIHUI + */ +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "dataType", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "int"), + @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "float"), + @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "double"), + @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "text"), + @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "date"), + @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "bool"), + @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "enum"), + @JsonSubTypes.Type(value = ThingModelArrayDataSpecs.class, name = "array") +}) +public abstract class ThingModelDataSpecs { + + /** + * 数据类型 + */ + private String dataType; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java new file mode 100644 index 000000000..f3f2a67ce --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; + +import lombok.Data; + +/** + * 物模型数据类型为时间型或文本型的 DataSpec 定义 + * + * 数据类型,取值为 date 或 text。 + * + * @author HUIHUI + */ +@Data +public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs { + + /** + * 数据长度,单位为字节。取值不能超过 2048。 + * 当 dataType 为 text 时,需传入该参数。 + */ + private Long length; + /** + * 默认值,可选参数,用于存储默认值。 + */ + private String defaultValue; + +} + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java new file mode 100644 index 000000000..9b4963110 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; + +import lombok.Data; + +/** + * 物模型数据类型为数值的 DataSpec 定义 + * + * 数据类型,取值为 int、float 或 double。 + * + * @author HUIHUI + */ +@Data +public class ThingModelNumericDataSpec extends ThingModelDataSpecs { + + /** + * 最大值,需转为字符串类型。值必须与 dataType 类型一致。 + * 例如,当 dataType 为 int 时,取值为 "200",而不是 200。 + */ + private String max; + /** + * 最小值,需转为字符串类型。值必须与 dataType 类型一致。 + * 例如,当 dataType 为 int 时,取值为 "0",而不是 0。 + */ + private String min; + /** + * 步长,需转为字符串类型。值必须与 dataType 类型一致。 + * 例如,当 dataType 为 int 时,取值为 "10",而不是 10。 + */ + private String step; + /** + * 精度。当 dataType 为 float 或 double 时可选传入。 + */ + private String precise; + /** + * 默认值,可传入用于存储的默认值。 + */ + private String defaultValue; + /** + * 单位的符号。 + */ + private String unit; + /** + * 单位的名称。 + */ + private String unitName; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionPageReqVO.java similarity index 93% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionPageReqVO.java index 48b8f1ab5..548e21573 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionPageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionRespVO.java similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionRespVO.java index e2f3d2ddc..8ac5acd35 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionRespVO.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionSaveReqVO.java similarity index 83% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionSaveReqVO.java index a7534d78f..f58018f0b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionSaveReqVO.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java deleted file mode 100644 index 46bceaeeb..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; - -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelDataType; -import lombok.Data; - -import java.util.List; - -@Data -public class ThingModelProperty { - - /** - * 属性标识符 - */ - private String identifier; - /** - * 属性名称 - */ - private String name; - /** - * 属性描述 - */ - private String description; - - private String accessMode; // "rw"、"r"、"w" - private Boolean required; - private ThingModelDataType dataSpecs; - private List dataSpecsList; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java deleted file mode 100644 index c3faf6161..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; - -@Data -public class ThingModelArraySpecs { - - /** - * 数组长度 - */ - private int size; - /** - * 数组元素的类型 - */ - private ThingModelDataType item; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java deleted file mode 100644 index bab87be0a..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; - -// TODO @haohao:这个是不是和别的类,不太统一哈 -@Data -public class ThingModelArrayType extends ThingModelDataType { - - private ThingModelArraySpecs specs; - -} - diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java deleted file mode 100644 index b8ca64195..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode(callSuper = true) -public class ThingModelBoolType extends ThingModelDataType { - - // Bool 类型一般不需要额外的 specs - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java deleted file mode 100644 index 66284fe24..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import lombok.Data; - -@Data -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "dataType", visible = true) -@JsonSubTypes({ - @JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"), - @JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"), - @JsonSubTypes.Type(value = ThingModelDoubleType.class, name = "double"), - @JsonSubTypes.Type(value = ThingModelTextType.class, name = "text"), - @JsonSubTypes.Type(value = ThingModelDateType.class, name = "date"), - @JsonSubTypes.Type(value = ThingModelBoolType.class, name = "bool"), - @JsonSubTypes.Type(value = ThingModelEnumType.class, name = "enum"), - @JsonSubTypes.Type(value = ThingModelStructType.class, name = "struct"), - @JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array") -}) -public abstract class ThingModelDataType { - - private String dataType; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java deleted file mode 100644 index 854229339..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; - -@Data -public class ThingModelDateType extends ThingModelDataType { - - // Date 类型一般不需要额外的 specs - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java deleted file mode 100644 index e5f3ad268..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; - -@Data -public class ThingModelDoubleType extends ThingModelDataType { - private ThingModelDoubleSpecs specs; -} - -@Data -class ThingModelDoubleSpecs { - - private Double min; - private Double max; - private Double step; - private String unit; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java deleted file mode 100644 index 3dcb068e9..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; - -import java.util.Map; - -@Data -public class ThingModelEnumType extends ThingModelDataType { - - /** - * 枚举值和描述的键值对 - */ - private Map specs; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java deleted file mode 100644 index 27926fa49..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode(callSuper = true) -public class ThingModelFloatType extends ThingModelDataType { - private ThingModelFloatSpecs specs; -} - -@Data -class ThingModelFloatSpecs { - - private Float min; - private Float max; - private Float step; - private String unit; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java deleted file mode 100644 index a126eb749..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; - -@Data -public class ThingModelIntType extends ThingModelDataType { - private ThingModelIntSpecs specs; -} - -@Data -class ThingModelIntSpecs { - - private Integer min; - private Integer max; - private Integer step; - private String unit; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java deleted file mode 100644 index 5e079f22b..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; - -@Data -public class ThingModelStructField { - - private String identifier; - private String name; - private ThingModelDataType dataType; - private String description; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java deleted file mode 100644 index f0996513c..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; - -import java.util.List; - -@Data -public class ThingModelStructType extends ThingModelDataType { - - private List specs; - -} - - diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java deleted file mode 100644 index 16d1e402e..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; - -import lombok.Data; - -@Data -public class ThingModelTextType extends ThingModelDataType { - - private ThingModelTextSpecs specs; - -} - -@Data -class ThingModelTextSpecs { - - /** - * 最大长度 - */ - private Integer length; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java index f4f4bb87e..32ddefc72 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java @@ -1,11 +1,11 @@ package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -23,7 +23,7 @@ public interface IotThinkModelFunctionConvert { @Mapping(target = "property", expression = "java(convertToProperty(bean))") @Mapping(target = "event", expression = "java(convertToEvent(bean))") @Mapping(target = "service", expression = "java(convertToService(bean))") - IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); + IotProductThingModelDO convert(IotThinkModelFunctionSaveReqVO bean); default ThingModelProperty convertToProperty(IotThinkModelFunctionSaveReqVO bean) { if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { @@ -50,8 +50,8 @@ public interface IotThinkModelFunctionConvert { @Mapping(target = "property", source = "property") @Mapping(target = "event", source = "event") @Mapping(target = "service", source = "service") - IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); + IotThinkModelFunctionRespVO convert(IotProductThingModelDO bean); // 批量转换 - List convertList(List list); + List convertList(List list); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java index 892a6b8b7..73e7ee34d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -30,7 +30,7 @@ public class IotDeviceDataDO { /** * 物模型编号 *

- * 关联 {@link IotThinkModelFunctionDO#getId()} + * 关联 {@link IotProductThingModelDO#getId()} */ private Long thinkModelFunctionId; @@ -51,21 +51,21 @@ public class IotDeviceDataDO { /** * 属性标识符 *

- * 关联 {@link IotThinkModelFunctionDO#getIdentifier()} + * 关联 {@link IotProductThingModelDO#getIdentifier()} */ private String identifier; /** * 属性名称 *

- * 关联 {@link IotThinkModelFunctionDO#getName()} + * 关联 {@link IotProductThingModelDO#getName()} */ private String name; /** * 数据类型 *

- * 关联 {@link IotThinkModelFunctionDO#getProperty()#getDataType()} + * 关联 {@link IotProductThingModelDO#getProperty()#getDataType()} */ private String dataType; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java similarity index 77% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java index d3d889191..71fb1692a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction; +package cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; @@ -19,7 +19,7 @@ import lombok.NoArgsConstructor; /** * IoT 产品物模型功能 DO *

- * 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 + * 每个 {@link IotProductDO} 和 {@link IotProductThingModelDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 * * @author 芋道源码 */ @@ -29,7 +29,7 @@ import lombok.NoArgsConstructor; @Builder @NoArgsConstructor @AllArgsConstructor -public class IotThinkModelFunctionDO extends BaseDO { +public class IotProductThingModelDO extends BaseDO { /** * 物模型功能编号 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index daad0b458..6dfe54c07 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelDataType; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelDataSpecs; import java.util.HashMap; import java.util.List; @@ -36,17 +36,19 @@ public class FieldParser { */ public static TdFieldDO parse(ThingModelProperty property) { String fieldName = property.getIdentifier().toLowerCase(); - ThingModelDataType type = property.getDataType(); - - // 将物模型字段类型映射为td字段类型 - String fType = TYPE_MAPPING.get(type.getDataType().toUpperCase()); - - // 如果字段类型为NCHAR,默认长度为64 - int dataLength = 0; - if ("NCHAR".equals(fType)) { - dataLength = 64; - } - return new TdFieldDO(fieldName, fType, dataLength); + //// TODO @puhui999: 需要重构 + //ThingModelDataSpecs type = property.getDataType(); + // + //// 将物模型字段类型映射为td字段类型 + //String fType = TYPE_MAPPING.get(type.getDataType().toUpperCase()); + // + //// 如果字段类型为NCHAR,默认长度为64 + //int dataLength = 0; + //if ("NCHAR".equals(fType)) { + // dataLength = 64; + //} + //return new TdFieldDO(fieldName, fType, dataLength); + return null; } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index c8745aab6..8b1496c3e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -15,48 +15,48 @@ import java.util.List; * @author 芋道源码 */ @Mapper -public interface IotThinkModelFunctionMapper extends BaseMapperX { +public interface IotThinkModelFunctionMapper extends BaseMapperX { - default PageResult selectPage(IotThinkModelFunctionPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(IotThinkModelFunctionDO::getIdentifier, reqVO.getIdentifier()) - .likeIfPresent(IotThinkModelFunctionDO::getName, reqVO.getName()) - .eqIfPresent(IotThinkModelFunctionDO::getType, reqVO.getType()) - .eqIfPresent(IotThinkModelFunctionDO::getProductId, reqVO.getProductId()) - .notIn(IotThinkModelFunctionDO::getIdentifier, "get", "set", "post") - .orderByDesc(IotThinkModelFunctionDO::getId)); + default PageResult selectPage(IotThinkModelFunctionPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotProductThingModelDO::getIdentifier, reqVO.getIdentifier()) + .likeIfPresent(IotProductThingModelDO::getName, reqVO.getName()) + .eqIfPresent(IotProductThingModelDO::getType, reqVO.getType()) + .eqIfPresent(IotProductThingModelDO::getProductId, reqVO.getProductId()) + .notIn(IotProductThingModelDO::getIdentifier, "get", "set", "post") + .orderByDesc(IotProductThingModelDO::getId)); } - default IotThinkModelFunctionDO selectByProductIdAndIdentifier(Long productId, String identifier) { - return selectOne(IotThinkModelFunctionDO::getProductId, productId, - IotThinkModelFunctionDO::getIdentifier, identifier); + default IotProductThingModelDO selectByProductIdAndIdentifier(Long productId, String identifier) { + return selectOne(IotProductThingModelDO::getProductId, productId, + IotProductThingModelDO::getIdentifier, identifier); } - default List selectListByProductId(Long productId) { - return selectList(IotThinkModelFunctionDO::getProductId, productId); + default List selectListByProductId(Long productId) { + return selectList(IotProductThingModelDO::getProductId, productId); } - default List selectListByProductIdAndType(Long productId, Integer type) { - return selectList(IotThinkModelFunctionDO::getProductId, productId, - IotThinkModelFunctionDO::getType, type); + default List selectListByProductIdAndType(Long productId, Integer type) { + return selectList(IotProductThingModelDO::getProductId, productId, + IotProductThingModelDO::getType, type); } - default List selectListByProductIdAndIdentifiersAndTypes(Long productId, - List identifiers, - List types) { - return selectList(new LambdaQueryWrapperX() - .eq(IotThinkModelFunctionDO::getProductId, productId) - .in(IotThinkModelFunctionDO::getIdentifier, identifiers) - .in(IotThinkModelFunctionDO::getType, types)); + default List selectListByProductIdAndIdentifiersAndTypes(Long productId, + List identifiers, + List types) { + return selectList(new LambdaQueryWrapperX() + .eq(IotProductThingModelDO::getProductId, productId) + .in(IotProductThingModelDO::getIdentifier, identifiers) + .in(IotProductThingModelDO::getType, types)); } - default IotThinkModelFunctionDO selectByProductIdAndName(Long productId, String name) { - return selectOne(IotThinkModelFunctionDO::getProductId, productId, - IotThinkModelFunctionDO::getName, name); + default IotProductThingModelDO selectByProductIdAndName(Long productId, String name) { + return selectOne(IotProductThingModelDO::getProductId, productId, + IotProductThingModelDO::getName, name); } - default List selectListByProductKey(String productKey) { - return selectList(IotThinkModelFunctionDO::getProductKey, productKey); + default List selectListByProductKey(String productKey) { + return selectList(IotProductThingModelDO::getProductKey, productKey); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 8fb0edc41..67a9e8474 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -7,9 +7,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; @@ -73,7 +73,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { // 1. 获取设备信息 IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); // 2. 获取设备属性最新数据 - List thinkModelFunctionList = thinkModelFunctionService.getThinkModelFunctionListByProductKey(device.getProductKey()); + List thinkModelFunctionList = thinkModelFunctionService.getThinkModelFunctionListByProductKey(device.getProductKey()); thinkModelFunctionList = thinkModelFunctionList.stream() .filter(function -> IotProductThingModelTypeEnum.PROPERTY.getType() .equals(function.getType())).toList(); @@ -90,6 +90,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { .toList(); } // 4. 获取设备属性最新数据 + // TODO @puhui999: 需要重构 thinkModelFunctionList.forEach(function -> { IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), function.getIdentifier()); if (deviceData == null) { @@ -100,7 +101,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); deviceData.setThinkModelFunctionId(function.getId()); deviceData.setName(function.getName()); - deviceData.setDataType(function.getProperty().getDataType().getDataType()); + //deviceData.setDataType(function.getProperty().getDataType().getDataType()); } list.add(deviceData); }); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java index 8aec32f32..e66278ccd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import java.util.List; @@ -14,5 +14,5 @@ public interface IotSuperTableService { /** * 创建超级表数据模型 */ - void createSuperTableDataModel(IotProductDO product, List functionList); + void createSuperTableDataModel(IotProductDO product, List functionList); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java index 1d16651d5..84e98296e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import jakarta.annotation.Resource; @@ -33,7 +33,7 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { private String url; @Override - public void createSuperTableDataModel(IotProductDO product, List functionList) { + public void createSuperTableDataModel(IotProductDO product, List functionList) { ThingModelRespVO thingModel = buildThingModel(product, functionList); if (thingModel.getModel() == null || CollUtil.isEmpty(thingModel.getModel().getProperties())) { @@ -210,7 +210,7 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 构建物模型 */ - private ThingModelRespVO buildThingModel(IotProductDO product, List functionList) { + private ThingModelRespVO buildThingModel(IotProductDO product, List functionList) { ThingModelRespVO thingModel = new ThingModelRespVO(); thingModel.setId(product.getId()); thingModel.setProductKey(product.getProductKey()); @@ -231,7 +231,7 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 构建物模型属性 */ - private ThingModelProperty buildThingModelProperty(IotThinkModelFunctionDO function) { + private ThingModelProperty buildThingModelProperty(IotProductThingModelDO function) { ThingModelProperty property = BeanUtil.copyProperties(function, ThingModelProperty.class); property.setDataType(function.getProperty().getDataType()); return property; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index cf988ad99..e86998047 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; @@ -71,7 +71,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 Map params = thingModelMessage.dataToMap(); - List functionList = getValidFunctionList(thingModelMessage.getProductKey()); + List functionList = getValidFunctionList(thingModelMessage.getProductKey()); if (functionList.isEmpty()) { return; } @@ -90,7 +90,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ .build()); } - private List getValidFunctionList(String productKey) { + private List getValidFunctionList(String productKey) { return iotThinkModelFunctionService .getThinkModelFunctionListByProductKey(productKey) .stream() @@ -98,13 +98,13 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ .toList(); } - private List filterAndCollectValidFields(Map params, List functionList, IotDeviceDO device, Long time) { + private List filterAndCollectValidFields(Map params, List functionList, IotDeviceDO device, Long time) { // 1. 获取属性标识符集合 - Set propertyIdentifiers = CollectionUtils.convertSet(functionList, IotThinkModelFunctionDO::getIdentifier); + Set propertyIdentifiers = CollectionUtils.convertSet(functionList, IotProductThingModelDO::getIdentifier); // 2. 构建属性标识符和属性的映射 - Map functionMap = functionList.stream() - .collect(Collectors.toMap(IotThinkModelFunctionDO::getIdentifier, function -> function)); + Map functionMap = functionList.stream() + .collect(Collectors.toMap(IotProductThingModelDO::getIdentifier, function -> function)); // 3. 过滤并收集有效的属性字段 List schemaFieldValues = new ArrayList<>(); @@ -124,21 +124,22 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * 缓存设备属性 * * @param device 设备信息 - * @param iotThinkModelFunctionDO 物模型属性 + * @param iotProductThingModelDO 物模型属性 * @param val 属性值 * @param time 时间 */ - private void setDeviceDataCache(IotDeviceDO device, IotThinkModelFunctionDO iotThinkModelFunctionDO, Object val, Long time) { + private void setDeviceDataCache(IotDeviceDO device, IotProductThingModelDO iotProductThingModelDO, Object val, Long time) { + // TODO @puhui999: 需要重构 IotDeviceDataDO deviceData = IotDeviceDataDO.builder() .productKey(device.getProductKey()) .deviceName(device.getDeviceName()) - .identifier(iotThinkModelFunctionDO.getIdentifier()) + .identifier(iotProductThingModelDO.getIdentifier()) .value(val != null ? val.toString() : null) .updateTime(DateUtil.toLocalDateTime(new Date(time))) .deviceId(device.getId()) - .thinkModelFunctionId(iotThinkModelFunctionDO.getId()) - .name(iotThinkModelFunctionDO.getName()) - .dataType(iotThinkModelFunctionDO.getProperty().getDataType().getDataType()) + .thinkModelFunctionId(iotProductThingModelDO.getId()) + .name(iotProductThingModelDO.getName()) + //.dataType(iotProductThingModelDO.getProperty().getDataType().getDataType()) .build(); deviceDataRedisDAO.set(deviceData); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java index f60610faf..ce2884453 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import jakarta.validation.Valid; import java.util.List; @@ -44,7 +44,7 @@ public interface IotThinkModelFunctionService { * @param id 编号 * @return 产品物模型 */ - IotThinkModelFunctionDO getThinkModelFunction(Long id); + IotProductThingModelDO getThinkModelFunction(Long id); /** * 获得产品物模型列表 @@ -52,7 +52,7 @@ public interface IotThinkModelFunctionService { * @param productId 产品编号 * @return 产品物模型列表 */ - List getThinkModelFunctionListByProductId(Long productId); + List getThinkModelFunctionListByProductId(Long productId); /** * 获得产品物模型分页 @@ -60,7 +60,7 @@ public interface IotThinkModelFunctionService { * @param pageReqVO 分页查询 * @return 产品物模型分页 */ - PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO); + PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO); /** * 创建超级表数据模型 @@ -75,5 +75,5 @@ public interface IotThinkModelFunctionService { * @param productKey 产品 Key * @return 产品物模型列表 */ - List getThinkModelFunctionListByProductKey(String productKey); + List getThinkModelFunctionListByProductKey(String productKey); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 18a47e808..a23878954 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -4,23 +4,20 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArraySpecs; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArrayType; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelTextType; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArrayDataSpecs; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelDateOrTextDataSpecs; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotSuperTableService; import jakarta.annotation.Resource; @@ -70,7 +67,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe validateProductStatus(createReqVO.getProductId()); // 5. 插入数据库 - IotThinkModelFunctionDO function = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); + IotProductThingModelDO function = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); thinkModelFunctionMapper.insert(function); // 6. 如果创建的是属性,需要更新默认的事件和服务 @@ -98,14 +95,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } private void validateNameUnique(Long productId, String name) { - IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndName(productId, name); + IotProductThingModelDO function = thinkModelFunctionMapper.selectByProductIdAndName(productId, name); if (function != null) { throw exception(THINK_MODEL_FUNCTION_NAME_EXISTS); } } private void validateIdentifierUnique(Long productId, String identifier) { - IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); + IotProductThingModelDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); if (function != null) { throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS); } @@ -124,7 +121,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe validateProductStatus(updateReqVO.getProductId()); // 4. 更新数据库 - IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); + IotProductThingModelDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); thinkModelFunctionMapper.updateById(thinkModelFunction); // 5. 如果更新的是属性,需要更新默认的事件和服务 @@ -134,7 +131,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { - IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); + IotProductThingModelDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); if (function != null && ObjectUtil.notEqual(function.getId(), id)) { throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS); } @@ -144,7 +141,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Transactional(rollbackFor = Exception.class) public void deleteThinkModelFunction(Long id) { // 1. 校验功能是否存在 - IotThinkModelFunctionDO functionDO = thinkModelFunctionMapper.selectById(id); + IotProductThingModelDO functionDO = thinkModelFunctionMapper.selectById(id); if (functionDO == null) { throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); } @@ -173,17 +170,17 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } @Override - public IotThinkModelFunctionDO getThinkModelFunction(Long id) { + public IotProductThingModelDO getThinkModelFunction(Long id) { return thinkModelFunctionMapper.selectById(id); } @Override - public List getThinkModelFunctionListByProductId(Long productId) { + public List getThinkModelFunctionListByProductId(Long productId) { return thinkModelFunctionMapper.selectListByProductId(productId); } @Override - public PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO) { + public PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO) { return thinkModelFunctionMapper.selectPage(pageReqVO); } @@ -193,14 +190,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe IotProductDO product = productService.getProduct(productId); // 2. 查询产品的物模型功能列表 - List functionList = thinkModelFunctionMapper.selectListByProductId(productId); + List functionList = thinkModelFunctionMapper.selectListByProductId(productId); // 3. 生成 TDengine 的数据模型 dbStructureDataService.createSuperTableDataModel(product, functionList); } @Override - public List getThinkModelFunctionListByProductKey(String productKey) { + public List getThinkModelFunctionListByProductKey(String productKey) { return thinkModelFunctionMapper.selectListByProductKey(productKey); } @@ -209,45 +206,45 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe */ public void createDefaultEventsAndServices(Long productId, String productKey) { // 1. 获取当前属性列表 - List propertyList = thinkModelFunctionMapper + List propertyList = thinkModelFunctionMapper .selectListByProductIdAndType(productId, IotProductThingModelTypeEnum.PROPERTY.getType()); // 2. 生成新的事件和服务列表 - List newFunctionList = new ArrayList<>(); + List newFunctionList = new ArrayList<>(); // 生成属性上报事件 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); if (propertyPostEvent != null) { - IotThinkModelFunctionDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent); + IotProductThingModelDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent); newFunctionList.add(eventFunction); } // 生成属性设置服务 ThingModelService propertySetService = generatePropertySetService(propertyList); if (propertySetService != null) { - IotThinkModelFunctionDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService); + IotProductThingModelDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService); newFunctionList.add(setServiceFunction); } // 生成属性获取服务 ThingModelService propertyGetService = generatePropertyGetService(propertyList); if (propertyGetService != null) { - IotThinkModelFunctionDO getServiceFunction = buildServiceFunctionDO(productId, productKey, propertyGetService); + IotProductThingModelDO getServiceFunction = buildServiceFunctionDO(productId, productKey, propertyGetService); newFunctionList.add(getServiceFunction); } // 3. 获取数据库中的默认的旧事件和服务列表 - List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes( + List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) ); // 3.1 使用 diffList 方法比较新旧列表 - List> diffResult = diffList(oldFunctionList, newFunctionList, + List> diffResult = diffList(oldFunctionList, newFunctionList, // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier()) && Objects.equals(oldFunc.getType(), newFunc.getType())); - List createList = diffResult.get(0); // 需要新增的 - List updateList = diffResult.get(1); // 需要更新的 - List deleteList = diffResult.get(2); // 需要删除的 + List createList = diffResult.get(0); // 需要新增的 + List updateList = diffResult.get(1); // 需要更新的 + List deleteList = diffResult.get(2); // 需要删除的 // 3.2 批量执行数据库操作 // 新增数据库中的新事件和服务列表 @@ -258,14 +255,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe if (CollUtil.isNotEmpty(updateList)) { // 首先,为每个需要更新的对象设置其对应的 ID updateList.forEach(updateFunc -> { - IotThinkModelFunctionDO oldFunc = findFunctionByIdentifierAndType( + IotProductThingModelDO oldFunc = findFunctionByIdentifierAndType( oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType()); if (oldFunc != null) { updateFunc.setId(oldFunc.getId()); } }); // 过滤掉没有设置 ID 的对象 - List validUpdateList = updateList.stream() + List validUpdateList = updateList.stream() .filter(func -> func.getId() != null) .collect(Collectors.toList()); // 执行批量更新 @@ -276,7 +273,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 删除数据库中的旧事件和服务列表 if (CollUtil.isNotEmpty(deleteList)) { - Set idsToDelete = CollectionUtils.convertSet(deleteList, IotThinkModelFunctionDO::getId); + Set idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThingModelDO::getId); thinkModelFunctionMapper.deleteByIds(idsToDelete); } } @@ -284,8 +281,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe /** * 根据标识符和类型查找功能对象 */ - private IotThinkModelFunctionDO findFunctionByIdentifierAndType(List functionList, - String identifier, Integer type) { + private IotProductThingModelDO findFunctionByIdentifierAndType(List functionList, + String identifier, Integer type) { return CollUtil.findOne(functionList, func -> Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)); } @@ -293,8 +290,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe /** * 构建事件功能对象 */ - private IotThinkModelFunctionDO buildEventFunctionDO(Long productId, String productKey, ThingModelEvent event) { - return new IotThinkModelFunctionDO() + private IotProductThingModelDO buildEventFunctionDO(Long productId, String productKey, ThingModelEvent event) { + return new IotProductThingModelDO() .setProductId(productId) .setProductKey(productKey) .setIdentifier(event.getIdentifier()) @@ -307,8 +304,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe /** * 构建服务功能对象 */ - private IotThinkModelFunctionDO buildServiceFunctionDO(Long productId, String productKey, ThingModelService service) { - return new IotThinkModelFunctionDO() + private IotProductThingModelDO buildServiceFunctionDO(Long productId, String productKey, ThingModelService service) { + return new IotProductThingModelDO() .setProductId(productId) .setProductKey(productKey) .setIdentifier(service.getIdentifier()) @@ -321,7 +318,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe /** * 生成属性上报事件 */ - private ThingModelEvent generatePropertyPostEvent(List propertyList) { + private ThingModelEvent generatePropertyPostEvent(List propertyList) { if (CollUtil.isEmpty(propertyList)) { return null; } @@ -335,12 +332,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 将属性列表转换为事件的输出参数 List outputData = new ArrayList<>(); - for (IotThinkModelFunctionDO functionDO : propertyList) { + // TODO @puhui999: 需要重构 + for (IotProductThingModelDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); ThingModelArgument arg = new ThingModelArgument() .setIdentifier(property.getIdentifier()) .setName(property.getName()) - .setDataType(property.getDataType()) + //.setDataType(property.getDataType()) .setDescription(property.getDescription()) .setDirection("output"); // 设置为输出参数 outputData.add(arg); @@ -352,24 +350,24 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe /** * 生成属性设置服务 */ - private ThingModelService generatePropertySetService(List propertyList) { + private ThingModelService generatePropertySetService(List propertyList) { if (propertyList == null || propertyList.isEmpty()) { return null; } List inputData = new ArrayList<>(); // TODO @puhui999: 需要重构 - for (IotThinkModelFunctionDO functionDO : propertyList) { + for (IotProductThingModelDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); - if (IotProductThingModelAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { - ThingModelArgument arg = new ThingModelArgument() - .setIdentifier(property.getIdentifier()) - .setName(property.getName()) - .setDataType(property.getDataType()) - .setDescription(property.getDescription()) - .setDirection("input"); // 设置为输入参数 - inputData.add(arg); - } + //if (IotProductThingModelAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { + // ThingModelArgument arg = new ThingModelArgument() + // .setIdentifier(property.getIdentifier()) + // .setName(property.getName()) + // .setDataType(property.getDataType()) + // .setDescription(property.getDescription()) + // .setDirection("input"); // 设置为输入参数 + // inputData.add(arg); + //} } if (inputData.isEmpty()) { // 如果没有可写属性,不生成属性设置服务 @@ -391,24 +389,24 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe /** * 生成属性获取服务 */ - private ThingModelService generatePropertyGetService(List propertyList) { + private ThingModelService generatePropertyGetService(List propertyList) { if (propertyList == null || propertyList.isEmpty()) { return null; } - + // TODO @puhui999: 需要重构 List outputData = new ArrayList<>(); - for (IotThinkModelFunctionDO functionDO : propertyList) { + for (IotProductThingModelDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); - if (ObjectUtils.equalsAny(property.getAccessMode(), - IotProductThingModelAccessModeEnum.READ.getMode(), IotProductThingModelAccessModeEnum.READ_WRITE.getMode())) { - ThingModelArgument arg = new ThingModelArgument() - .setIdentifier(property.getIdentifier()) - .setName(property.getName()) - .setDataType(property.getDataType()) - .setDescription(property.getDescription()) - .setDirection("output"); // 设置为输出参数 - outputData.add(arg); - } + //if (ObjectUtils.equalsAny(property.getAccessMode(), + // IotProductThingModelAccessModeEnum.READ.getMode(), IotProductThingModelAccessModeEnum.READ_WRITE.getMode())) { + // ThingModelArgument arg = new ThingModelArgument() + // .setIdentifier(property.getIdentifier()) + // .setName(property.getName()) + // .setDataType(property.getDataType()) + // .setDescription(property.getDescription()) + // .setDirection("output"); // 设置为输出参数 + // outputData.add(arg); + //} } if (outputData.isEmpty()) { // 如果没有可读属性,不生成属性获取服务 @@ -430,13 +428,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe .setDirection("input"); // 设置为输入参数 // 创建数组类型,元素类型为文本类型(字符串) - ThingModelArrayType arrayType = new ThingModelArrayType(); + ThingModelArrayDataSpecs arrayType = new ThingModelArrayDataSpecs(); arrayType.setDataType("array"); - ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs(); - ThingModelTextType textType = new ThingModelTextType(); + //ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs(); + ThingModelDateOrTextDataSpecs textType = new ThingModelDateOrTextDataSpecs(); textType.setDataType("text"); - arraySpecs.setItem(textType); - arrayType.setSpecs(arraySpecs); + //arraySpecs.setItem(textType); + //arrayType.setSpecs(arraySpecs); inputArg.setDataType(arrayType); service.setInputData(Collections.singletonList(inputArg)); From 9e98768022f004d0a5832e6e65ab3d29c993ab8e Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 16 Dec 2024 16:41:28 +0800 Subject: [PATCH 031/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E4=BA=A7=E5=93=81=E7=89=A9=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=20CRUD=20=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotProductThingModelController.http | 187 ++++++++++++++++++ .../IotProductThingModelController.java | 56 +++--- .../IotThinkModelFunctionController.http | 112 ----------- .../dataType/ThingModelArrayDataSpecs.java | 16 +- .../ThingModelBoolOrEnumDataSpecs.java | 2 + .../dataType/ThingModelDataSpecs.java | 3 +- .../ThingModelDateOrTextDataSpecs.java | 4 + .../dataType/ThingModelNumericDataSpec.java | 4 + .../dataType/ThingModelStructDataSpecs.java | 58 ++++++ ...ava => IotProductThingModelPageReqVO.java} | 2 +- ...O.java => IotProductThingModelRespVO.java} | 2 +- ...ava => IotProductThingModelSaveReqVO.java} | 2 +- .../IotProductThingModelConvert.java} | 39 ++-- .../IotProductThingModelDO.java | 4 +- ...r.java => IotProductThingModelMapper.java} | 6 +- .../device/IotDeviceDataServiceImpl.java | 6 +- .../product/IotProductServiceImpl.java | 4 +- .../IotProductThingModelService.java} | 23 +-- .../IotProductThingModelServiceImpl.java} | 75 +++---- .../IotThingModelMessageServiceImpl.java | 8 +- 20 files changed, 382 insertions(+), 231 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.http delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotThinkModelFunctionController.http create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelStructDataSpecs.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/{IotThinkModelFunctionPageReqVO.java => IotProductThingModelPageReqVO.java} (94%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/{IotThinkModelFunctionRespVO.java => IotProductThingModelRespVO.java} (98%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/{IotThinkModelFunctionSaveReqVO.java => IotProductThingModelSaveReqVO.java} (97%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/{thinkmodelfunction/IotThinkModelFunctionConvert.java => productthingmodel/IotProductThingModelConvert.java} (66%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/{IotThinkModelFunctionMapper.java => IotProductThingModelMapper.java} (92%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{thinkmodelfunction/IotThinkModelFunctionService.java => productthingmodel/IotProductThingModelService.java} (64%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{thinkmodelfunction/IotThinkModelFunctionServiceImpl.java => productthingmodel/IotProductThingModelServiceImpl.java} (85%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.http new file mode 100644 index 000000000..7742705ef --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.http @@ -0,0 +1,187 @@ +### 请求 /iot/product-thing-model/create 接口 => 成功 +POST {{baseUrl}}/iot/product-thing-model/create +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "productId": 12, + "productKey": "CJVS54fObwZJ9Qe5CJVS54fObwZJ9Qe5", + "identifier": "Temperature", + "name": "温度", + "description": "当前温度值", + "type": 1, + "property": { + "identifier": "Temperature", + "name": "温度", + "accessMode": "r", + "required": true, + "dataType": "int", + "dataSpecs": { + "dataType": "int", + "max": "200", + "min": "0", + "step": "10", + "defaultValue": "30", + "unit": "%", + "unitName": "百分比" + }, + "description": "当前温度值" + } +} + +### 请求 /iot/product-thing-model/create 接口 => 成功 +POST {{baseUrl}}/iot/product-thing-model/create +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "productId": 12, + "productKey": "CJVS54fObwZJ9Qe5CJVS54fObwZJ9Qe5", + "identifier": "switch", + "name": "开关", + "description": "温度计开关", + "type": 1, + "property": { + "identifier": "switch", + "name": "开关", + "description": "温度计开关", + "accessMode": "rw", + "required": true, + "dataType": "bool", + "dataSpecsList": [ + { + "dataType": "bool", + "name": "关", + "value": 0 + }, + { + "dataType": "bool", + "name": "开", + "value": 1 + } + ] + } +} + +### 请求 /iot/product-thing-model/create 接口 => 成功 +POST {{baseUrl}}/iot/product-thing-model/create +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "productId": 12, + "productKey": "CJVS54fObwZJ9Qe5CJVS54fObwZJ9Qe5", + "identifier": "argb", + "name": "温度计 argb 颜色", + "description": "温度计 argb 颜色", + "type": 1, + "property": { + "identifier": "argb", + "name": "温度计 argb 颜色", + "description": "温度计 argb 颜色", + "accessMode": "rw", + "required": true, + "dataType": "array", + "dataSpecs": { + "dataType": "array", + "size": 10, + "childDataType": "struct", + "dataSpecsList": [ + { + "identifier": "switch", + "name": "开关", + "description": "温度计开关", + "accessMode": "rw", + "required": true, + "dataType": "struct", + "childDataType": "bool", + "dataSpecsList": [ + { + "dataType": "bool", + "name": "关", + "value": 0 + }, + { + "dataType": "bool", + "name": "开", + "value": 1 + } + ] + }, + { + "identifier": "Temperature", + "name": "温度", + "accessMode": "r", + "required": true, + "dataType": "struct", + "childDataType": "int", + "dataSpecs": { + "dataType": "int", + "max": "200", + "min": "0", + "step": "10", + "defaultValue": "30", + "unit": "%", + "unitName": "百分比" + }, + "description": "当前温度值" + } + ] + } + } +} + +### 请求 /iot/product-thing-model/update 接口 => 成功 +PUT {{baseUrl}}/iot/product-thing-model/update +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "id": 33, + "productId": 12, + "productKey": "CJVS54fObwZJ9Qe5CJVS54fObwZJ9Qe5", + "identifier": "switch", + "name": "开关", + "description": "温度计开关", + "type": 1, + "property": { + "identifier": "switch", + "name": "开关", + "description": "温度计开关", + "accessMode": "r", + "required": true, + "dataType": "bool", + "dataSpecsList": [ + { + "dataType": "bool", + "name": "关", + "value": 0 + }, + { + "dataType": "bool", + "name": "开", + "value": 1 + } + ] + } +} + +### 请求 /iot/product-thing-model/delete 接口 => 成功 +DELETE {{baseUrl}}/iot/product-thing-model/delete?id=36 +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +### 请求 /iot/product-thing-model/get 接口 => 成功 +GET {{baseUrl}}/iot/product-thing-model/get?id=40 +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + + +### 请求 /iot/product-thing-model/list-by-product-id 接口 => 成功 +GET {{baseUrl}}/iot/product-thing-model/list-by-product-id?productId=1001 +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java index 851637c12..11a2ffcc5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java @@ -3,12 +3,12 @@ package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.productthingmodel.IotProductThingModelConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; -import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; +import cn.iocoder.yudao.module.iot.service.productthingmodel.IotProductThingModelService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -24,61 +24,61 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - IoT 产品物模型") @RestController -@RequestMapping("/iot/think-model-function") +@RequestMapping("/iot/product-thing-model") @Validated public class IotProductThingModelController { @Resource - private IotThinkModelFunctionService thinkModelFunctionService; + private IotProductThingModelService thinkModelFunctionService; @PostMapping("/create") @Operation(summary = "创建产品物模型") - @PreAuthorize("@ss.hasPermission('iot:think-model-function:create')") - public CommonResult createThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO createReqVO) { - return success(thinkModelFunctionService.createThinkModelFunction(createReqVO)); + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:create')") + public CommonResult createProductThingModel(@Valid @RequestBody IotProductThingModelSaveReqVO createReqVO) { + return success(thinkModelFunctionService.createProductThingModel(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新产品物模型") - @PreAuthorize("@ss.hasPermission('iot:think-model-function:update')") - public CommonResult updateThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO updateReqVO) { - thinkModelFunctionService.updateThinkModelFunction(updateReqVO); + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:update')") + public CommonResult updateProductThingModel(@Valid @RequestBody IotProductThingModelSaveReqVO updateReqVO) { + thinkModelFunctionService.updateProductThingModel(updateReqVO); return success(true); } @DeleteMapping("/delete") @Operation(summary = "删除产品物模型") @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:think-model-function:delete')") - public CommonResult deleteThinkModelFunction(@RequestParam("id") Long id) { - thinkModelFunctionService.deleteThinkModelFunction(id); + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:delete')") + public CommonResult deleteProductThingModel(@RequestParam("id") Long id) { + thinkModelFunctionService.deleteProductThingModel(id); return success(true); } @GetMapping("/get") @Operation(summary = "获得产品物模型") @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") - public CommonResult getThinkModelFunction(@RequestParam("id") Long id) { - IotProductThingModelDO function = thinkModelFunctionService.getThinkModelFunction(id); - return success(IotThinkModelFunctionConvert.INSTANCE.convert(function)); + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") + public CommonResult getProductThingModel(@RequestParam("id") Long id) { + IotProductThingModelDO function = thinkModelFunctionService.getProductThingModel(id); + return success(IotProductThingModelConvert.INSTANCE.convert(function)); } @GetMapping("/list-by-product-id") @Operation(summary = "获得产品物模型") @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") - public CommonResult> getThinkModelFunctionListByProductId(@RequestParam("productId") Long productId) { - List list = thinkModelFunctionService.getThinkModelFunctionListByProductId(productId); - return success(IotThinkModelFunctionConvert.INSTANCE.convertList(list)); + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") + public CommonResult> getProductThingModelListByProductId(@RequestParam("productId") Long productId) { + List list = thinkModelFunctionService.getProductThingModelListByProductId(productId); + return success(IotProductThingModelConvert.INSTANCE.convertList(list)); } @GetMapping("/page") @Operation(summary = "获得产品物模型分页") - @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") - public CommonResult> getThinkModelFunctionPage(@Valid IotThinkModelFunctionPageReqVO pageReqVO) { - PageResult pageResult = thinkModelFunctionService.getThinkModelFunctionPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotThinkModelFunctionRespVO.class)); + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") + public CommonResult> getProductThingModelPage(@Valid IotProductThingModelPageReqVO pageReqVO) { + PageResult pageResult = thinkModelFunctionService.getProductThingModelPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotProductThingModelRespVO.class)); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotThinkModelFunctionController.http deleted file mode 100644 index 56464dd80..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotThinkModelFunctionController.http +++ /dev/null @@ -1,112 +0,0 @@ -### 请求 /iot/think-model-function/create 接口 => 成功 -POST {{baseUrl}}/iot/think-model-function/create -Content-Type: application/json -tenant-id: {{adminTenentId}} -Authorization: Bearer {{token}} - -{ - "productId": 1001, - "productKey": "smart-sensor-001", - "identifier": "Temperature", - "name": "温度", - "description": "当前温度值", - "type": 1, - "property": { - "identifier": "Temperature", - "name": "温度", - "accessMode": "r", - "required": true, - "dataType": { - "type": "float", - "specs": { - "min": -10.0, - "max": 100.0, - "step": 0.1, - "unit": "℃" - } - }, - "description": "当前温度值" - } -} - -### 请求 /iot/think-model-function/create 接口 => 成功 -POST {{baseUrl}}/iot/think-model-function/create -Content-Type: application/json -tenant-id: {{adminTenentId}} -Authorization: Bearer {{token}} - -{ - "productId": 1001, - "productKey": "smart-sensor-001", - "identifier": "Humidity", - "name": "湿度", - "description": "当前湿度值", - "type": 1, - "property": { - "identifier": "Humidity", - "name": "湿度", - "accessMode": "r", - "required": true, - "dataType": { - "type": "float", - "specs": { - "min": 0.0, - "max": 100.0, - "step": 0.1, - "unit": "%" - } - }, - "description": "当前湿度值" - } -} - - - - -### 请求 /iot/think-model-function/update 接口 => 成功 -PUT {{baseUrl}}/iot/think-model-function/update -Content-Type: application/json -tenant-id: {{adminTenentId}} -Authorization: Bearer {{token}} - -{ - "id": 11, - "productId": 1001, - "productKey": "smart-sensor-001", - "identifier": "Temperature", - "name": "温度", - "description": "当前温度值", - "type": 1, - "property": { - "identifier": "Temperature", - "name": "温度", - "accessMode": "r", - "required": true, - "dataType": { - "type": "float", - "specs": { - "min": -111.0, - "max": 222.0, - "step": 0.1, - "unit": "℃" - } - }, - "description": "当前温度值" - } -} - -### 请求 /iot/think-model-function/delete 接口 => 成功 -DELETE {{baseUrl}}/iot/think-model-function/delete?id=7 -tenant-id: {{adminTenentId}} -Authorization: Bearer {{token}} - -### 请求 /iot/think-model-function/get 接口 => 成功 -GET {{baseUrl}}/iot/think-model-function/get?id=10 -tenant-id: {{adminTenentId}} -Authorization: Bearer {{token}} - - -### 请求 /iot/think-model-function/list-by-product-id 接口 => 成功 -GET {{baseUrl}}/iot/think-model-function/list-by-product-id?productId=1001 -tenant-id: {{adminTenentId}} -Authorization: Bearer {{token}} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java index 4bbf14a5f..5eeef76b9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java @@ -1,6 +1,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; +import lombok.EqualsAndHashCode; import java.util.List; @@ -10,24 +13,21 @@ import java.util.List; * @author HUIHUI */ @Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 public class ThingModelArrayDataSpecs extends ThingModelDataSpecs { /** * 数组中的元素个数。 */ - private Long size; + private Integer size; /** * 数组中的元素的数据类型。可选值:struct、int、float、double 或 text。 */ private String childDataType; /** - * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中。 - * 仅当 dataType 不是列表型时,才传入此字段。 - */ - private ThingModelDataSpecs dataSpecs; - /** - * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中。 - * 仅当 dataType 是列表型时,才传入此字段。 + * 数据类型(childDataType)为列表型 struct 的数据规范存储在 dataSpecsList 中。 + * 此时 struct 取值范围为:int、float、double、text、date、enum、bool */ private List dataSpecsList; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java index c76342398..e2ab9bdbb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import lombok.EqualsAndHashCode; @@ -12,6 +13,7 @@ import lombok.EqualsAndHashCode; */ @Data @EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 public class ThingModelBoolOrEnumDataSpecs extends ThingModelDataSpecs { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java index a4a7847ff..32090f64b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java @@ -22,7 +22,8 @@ import lombok.Data; @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "date"), @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "bool"), @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "enum"), - @JsonSubTypes.Type(value = ThingModelArrayDataSpecs.class, name = "array") + @JsonSubTypes.Type(value = ThingModelArrayDataSpecs.class, name = "array"), + @JsonSubTypes.Type(value = ThingModelStructDataSpecs.class, name = "struct") }) public abstract class ThingModelDataSpecs { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java index f3f2a67ce..4ce7d2dee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; +import lombok.EqualsAndHashCode; /** * 物模型数据类型为时间型或文本型的 DataSpec 定义 @@ -10,6 +12,8 @@ import lombok.Data; * @author HUIHUI */ @Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java index 9b4963110..391cbf90a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; +import lombok.EqualsAndHashCode; /** * 物模型数据类型为数值的 DataSpec 定义 @@ -10,6 +12,8 @@ import lombok.Data; * @author HUIHUI */ @Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 public class ThingModelNumericDataSpec extends ThingModelDataSpecs { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelStructDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelStructDataSpecs.java new file mode 100644 index 000000000..04c38ed28 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelStructDataSpecs.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; + +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 物模型数据类型为 struct 的 DataSpec 定义 + * + * @author HUIHUI + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 +public class ThingModelStructDataSpecs extends ThingModelDataSpecs { + + /** + * 属性标识符 + */ + private String identifier; + /** + * 属性名称 + */ + private String name; + /** + * 属性描述 + */ + private String description; + /** + * 云端可以对该属性进行的操作类型 + * 关联枚举 {@link IotProductThingModelAccessModeEnum} + */ + private String accessMode; + /** + * 是否是标准品类的必选服务。 + * + * - true:是 + * - false:否 + */ + private Boolean required; + /** + * struct 数据的数据类型 + */ + private String childDataType; + /** + * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 + */ + private ThingModelDataSpecs dataSpecs; + /** + * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 + */ + private List dataSpecsList; + +} + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelPageReqVO.java similarity index 94% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelPageReqVO.java index 548e21573..31c5ba1d9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelPageReqVO.java @@ -13,7 +13,7 @@ import lombok.ToString; @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class IotThinkModelFunctionPageReqVO extends PageParam { +public class IotProductThingModelPageReqVO extends PageParam { @Schema(description = "功能标识") private String identifier; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelRespVO.java similarity index 98% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelRespVO.java index 8ac5acd35..83c51fb59 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelRespVO.java @@ -13,7 +13,7 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - IoT 产品物模型 Response VO") @Data @ExcelIgnoreUnannotated -public class IotThinkModelFunctionRespVO { +public class IotProductThingModelRespVO { @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") @ExcelProperty("产品ID") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelSaveReqVO.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelSaveReqVO.java index f58018f0b..e230c3918 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotThinkModelFunctionSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelSaveReqVO.java @@ -12,7 +12,7 @@ import lombok.Data; @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") @Data -public class IotThinkModelFunctionSaveReqVO { +public class IotProductThingModelSaveReqVO { @Schema(description = "编号", example = "1") private Long id; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/productthingmodel/IotProductThingModelConvert.java similarity index 66% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/productthingmodel/IotProductThingModelConvert.java index 32ddefc72..1d57982d5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/productthingmodel/IotProductThingModelConvert.java @@ -1,57 +1,62 @@ -package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction; +package cn.iocoder.yudao.module.iot.convert.productthingmodel; import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.mapstruct.Named; import org.mapstruct.factory.Mappers; import java.util.List; import java.util.Objects; @Mapper -public interface IotThinkModelFunctionConvert { +public interface IotProductThingModelConvert { - IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class); + IotProductThingModelConvert INSTANCE = Mappers.getMapper(IotProductThingModelConvert.class); // 将 SaveReqVO 转换为 DO @Mapping(target = "property", expression = "java(convertToProperty(bean))") @Mapping(target = "event", expression = "java(convertToEvent(bean))") @Mapping(target = "service", expression = "java(convertToService(bean))") - IotProductThingModelDO convert(IotThinkModelFunctionSaveReqVO bean); + IotProductThingModelDO convert(IotProductThingModelSaveReqVO bean); - default ThingModelProperty convertToProperty(IotThinkModelFunctionSaveReqVO bean) { + // 将 DO 转换为 RespVO + @Mapping(target = "property", source = "property") + @Mapping(target = "event", source = "event") + @Mapping(target = "service", source = "service") + IotProductThingModelRespVO convert(IotProductThingModelDO bean); + + // 批量转换 + List convertList(List list); + + @Named("convertToProperty") + default ThingModelProperty convertToProperty(IotProductThingModelSaveReqVO bean) { if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { return bean.getProperty(); } return null; } - default ThingModelEvent convertToEvent(IotThinkModelFunctionSaveReqVO bean) { + @Named("convertToEvent") + default ThingModelEvent convertToEvent(IotProductThingModelSaveReqVO bean) { if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.EVENT.getType())) { return bean.getEvent(); } return null; } - default ThingModelService convertToService(IotThinkModelFunctionSaveReqVO bean) { + @Named("convertToService") + default ThingModelService convertToService(IotProductThingModelSaveReqVO bean) { if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.SERVICE.getType())) { return bean.getService(); } return null; } - // 将 DO 转换为 RespVO - @Mapping(target = "property", source = "property") - @Mapping(target = "event", source = "event") - @Mapping(target = "service", source = "service") - IotThinkModelFunctionRespVO convert(IotProductThingModelDO bean); - - // 批量转换 - List convertList(List list); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java index 71fb1692a..1cececc0c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java @@ -23,8 +23,8 @@ import lombok.NoArgsConstructor; * * @author 芋道源码 */ -@TableName(value = "iot_think_model_function", autoResultMap = true) -@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName(value = "iot_product_thing_model", autoResultMap = true) +@KeySequence("iot_product_thing_model_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotProductThingModelMapper.java similarity index 92% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotProductThingModelMapper.java index 8b1496c3e..6ec0d4846 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotProductThingModelMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import org.apache.ibatis.annotations.Mapper; @@ -15,9 +15,9 @@ import java.util.List; * @author 芋道源码 */ @Mapper -public interface IotThinkModelFunctionMapper extends BaseMapperX { +public interface IotProductThingModelMapper extends BaseMapperX { - default PageResult selectPage(IotThinkModelFunctionPageReqVO reqVO) { + default PageResult selectPage(IotProductThingModelPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(IotProductThingModelDO::getIdentifier, reqVO.getIdentifier()) .likeIfPresent(IotProductThingModelDO::getName, reqVO.getName()) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 67a9e8474..6dbcf0ab7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -15,7 +15,7 @@ import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; -import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; +import cn.iocoder.yudao.module.iot.service.productthingmodel.IotProductThingModelService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; @@ -40,7 +40,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { @Resource private IotThingModelMessageService thingModelMessageService; @Resource - private IotThinkModelFunctionService thinkModelFunctionService; + private IotProductThingModelService thinkModelFunctionService; @Resource private TdEngineDMLMapper tdEngineDMLMapper; @@ -73,7 +73,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { // 1. 获取设备信息 IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); // 2. 获取设备属性最新数据 - List thinkModelFunctionList = thinkModelFunctionService.getThinkModelFunctionListByProductKey(device.getProductKey()); + List thinkModelFunctionList = thinkModelFunctionService.getProductThingModelListByProductKey(device.getProductKey()); thinkModelFunctionList = thinkModelFunctionList.stream() .filter(function -> IotProductThingModelTypeEnum.PROPERTY.getType() .equals(function.getType())).toList(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index e7c144388..dabc9ad4a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; +import cn.iocoder.yudao.module.iot.service.productthingmodel.IotProductThingModelService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; @@ -34,7 +34,7 @@ public class IotProductServiceImpl implements IotProductService { @Resource @Lazy - private IotThinkModelFunctionService thinkModelFunctionService; + private IotProductThingModelService thinkModelFunctionService; @Override public Long createProduct(IotProductSaveReqVO createReqVO) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java similarity index 64% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java index ce2884453..3cc568756 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; +package cn.iocoder.yudao.module.iot.service.productthingmodel; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; import jakarta.validation.Valid; @@ -13,7 +13,7 @@ import java.util.List; * * @author 芋道源码 */ -public interface IotThinkModelFunctionService { +public interface IotProductThingModelService { /** * 创建产品物模型 @@ -21,7 +21,7 @@ public interface IotThinkModelFunctionService { * @param createReqVO 创建信息 * @return 编号 */ - Long createThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO createReqVO); + Long createProductThingModel(@Valid IotProductThingModelSaveReqVO createReqVO); /** @@ -29,14 +29,14 @@ public interface IotThinkModelFunctionService { * * @param updateReqVO 更新信息 */ - void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO); + void updateProductThingModel(@Valid IotProductThingModelSaveReqVO updateReqVO); /** * 删除产品物模型 * * @param id 编号 */ - void deleteThinkModelFunction(Long id); + void deleteProductThingModel(Long id); /** * 获得产品物模型 @@ -44,7 +44,7 @@ public interface IotThinkModelFunctionService { * @param id 编号 * @return 产品物模型 */ - IotProductThingModelDO getThinkModelFunction(Long id); + IotProductThingModelDO getProductThingModel(Long id); /** * 获得产品物模型列表 @@ -52,7 +52,7 @@ public interface IotThinkModelFunctionService { * @param productId 产品编号 * @return 产品物模型列表 */ - List getThinkModelFunctionListByProductId(Long productId); + List getProductThingModelListByProductId(Long productId); /** * 获得产品物模型分页 @@ -60,7 +60,7 @@ public interface IotThinkModelFunctionService { * @param pageReqVO 分页查询 * @return 产品物模型分页 */ - PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO); + PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO); /** * 创建超级表数据模型 @@ -75,5 +75,6 @@ public interface IotThinkModelFunctionService { * @param productKey 产品 Key * @return 产品物模型列表 */ - List getThinkModelFunctionListByProductKey(String productKey); + List getProductThingModelListByProductKey(String productKey); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelServiceImpl.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelServiceImpl.java index a23878954..f5efd37bc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelServiceImpl.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; +package cn.iocoder.yudao.module.iot.service.productthingmodel; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; @@ -10,12 +10,12 @@ import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArgument; import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArrayDataSpecs; import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelDateOrTextDataSpecs; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotThinkModelFunctionSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.productthingmodel.IotProductThingModelConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; -import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotProductThingModelMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; @@ -41,10 +41,10 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @Service @Validated @Slf4j -public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionService { +public class IotProductThingModelServiceImpl implements IotProductThingModelService { @Resource - private IotThinkModelFunctionMapper thinkModelFunctionMapper; + private IotProductThingModelMapper productThingModelMapper; @Resource private IotProductService productService; @@ -53,7 +53,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Override @Transactional(rollbackFor = Exception.class) - public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { + public Long createProductThingModel(IotProductThingModelSaveReqVO createReqVO) { // 1. 校验功能标识符在同一产品下是否唯一 validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); @@ -67,12 +67,12 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe validateProductStatus(createReqVO.getProductId()); // 5. 插入数据库 - IotProductThingModelDO function = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); - thinkModelFunctionMapper.insert(function); + IotProductThingModelDO function = IotProductThingModelConvert.INSTANCE.convert(createReqVO); + productThingModelMapper.insert(function); // 6. 如果创建的是属性,需要更新默认的事件和服务 if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { - createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); + //createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } return function.getId(); } @@ -95,14 +95,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } private void validateNameUnique(Long productId, String name) { - IotProductThingModelDO function = thinkModelFunctionMapper.selectByProductIdAndName(productId, name); + IotProductThingModelDO function = productThingModelMapper.selectByProductIdAndName(productId, name); if (function != null) { throw exception(THINK_MODEL_FUNCTION_NAME_EXISTS); } } private void validateIdentifierUnique(Long productId, String identifier) { - IotProductThingModelDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); + IotProductThingModelDO function = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (function != null) { throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS); } @@ -110,9 +110,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Override @Transactional(rollbackFor = Exception.class) - public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { + public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { // 1. 校验功能是否存在 - validateThinkModelFunctionExists(updateReqVO.getId()); + validateproductThingModelMapperExists(updateReqVO.getId()); // 2. 校验功能标识符是否唯一 validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); @@ -121,8 +121,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe validateProductStatus(updateReqVO.getProductId()); // 4. 更新数据库 - IotProductThingModelDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); - thinkModelFunctionMapper.updateById(thinkModelFunction); + IotProductThingModelDO productThingModelDO = IotProductThingModelConvert.INSTANCE.convert(updateReqVO); + productThingModelMapper.updateById(productThingModelDO); // 5. 如果更新的是属性,需要更新默认的事件和服务 if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { @@ -131,7 +131,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { - IotProductThingModelDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); + IotProductThingModelDO function = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (function != null && ObjectUtil.notEqual(function.getId(), id)) { throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS); } @@ -139,9 +139,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Override @Transactional(rollbackFor = Exception.class) - public void deleteThinkModelFunction(Long id) { + public void deleteProductThingModel(Long id) { // 1. 校验功能是否存在 - IotProductThingModelDO functionDO = thinkModelFunctionMapper.selectById(id); + IotProductThingModelDO functionDO = productThingModelMapper.selectById(id); if (functionDO == null) { throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); } @@ -150,7 +150,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe validateProductStatus(functionDO.getProductId()); // 2. 删除功能 - thinkModelFunctionMapper.deleteById(id); + productThingModelMapper.deleteById(id); // 3. 如果删除的是属性,需要更新默认的事件和服务 if (Objects.equals(functionDO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { @@ -163,25 +163,25 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe * * @param id 功能编号 */ - private void validateThinkModelFunctionExists(Long id) { - if (thinkModelFunctionMapper.selectById(id) == null) { + private void validateproductThingModelMapperExists(Long id) { + if (productThingModelMapper.selectById(id) == null) { throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); } } @Override - public IotProductThingModelDO getThinkModelFunction(Long id) { - return thinkModelFunctionMapper.selectById(id); + public IotProductThingModelDO getProductThingModel(Long id) { + return productThingModelMapper.selectById(id); } @Override - public List getThinkModelFunctionListByProductId(Long productId) { - return thinkModelFunctionMapper.selectListByProductId(productId); + public List getProductThingModelListByProductId(Long productId) { + return productThingModelMapper.selectListByProductId(productId); } @Override - public PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO) { - return thinkModelFunctionMapper.selectPage(pageReqVO); + public PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) { + return productThingModelMapper.selectPage(pageReqVO); } @Override @@ -190,23 +190,24 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe IotProductDO product = productService.getProduct(productId); // 2. 查询产品的物模型功能列表 - List functionList = thinkModelFunctionMapper.selectListByProductId(productId); + List functionList = productThingModelMapper.selectListByProductId(productId); // 3. 生成 TDengine 的数据模型 dbStructureDataService.createSuperTableDataModel(product, functionList); } @Override - public List getThinkModelFunctionListByProductKey(String productKey) { - return thinkModelFunctionMapper.selectListByProductKey(productKey); + public List getProductThingModelListByProductKey(String productKey) { + return productThingModelMapper.selectListByProductKey(productKey); } + // TODO @puhui999: 需要重构 /** * 创建默认的事件和服务 */ public void createDefaultEventsAndServices(Long productId, String productKey) { // 1. 获取当前属性列表 - List propertyList = thinkModelFunctionMapper + List propertyList = productThingModelMapper .selectListByProductIdAndType(productId, IotProductThingModelTypeEnum.PROPERTY.getType()); // 2. 生成新的事件和服务列表 @@ -231,7 +232,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } // 3. 获取数据库中的默认的旧事件和服务列表 - List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes( + List oldFunctionList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) @@ -249,7 +250,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3.2 批量执行数据库操作 // 新增数据库中的新事件和服务列表 if (CollUtil.isNotEmpty(createList)) { - thinkModelFunctionMapper.insertBatch(createList); + productThingModelMapper.insertBatch(createList); } // 更新数据库中的事件和服务列表 if (CollUtil.isNotEmpty(updateList)) { @@ -267,14 +268,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe .collect(Collectors.toList()); // 执行批量更新 if (CollUtil.isNotEmpty(validUpdateList)) { - thinkModelFunctionMapper.updateBatch(validUpdateList); + productThingModelMapper.updateBatch(validUpdateList); } } // 删除数据库中的旧事件和服务列表 if (CollUtil.isNotEmpty(deleteList)) { Set idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThingModelDO::getId); - thinkModelFunctionMapper.deleteByIds(idsToDelete); + productThingModelMapper.deleteByIds(idsToDelete); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index e86998047..fdb0ca9e4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -19,7 +19,7 @@ import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; +import cn.iocoder.yudao.module.iot.service.productthingmodel.IotProductThingModelService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -47,7 +47,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ private String url; @Resource - private IotThinkModelFunctionService iotThinkModelFunctionService; + private IotProductThingModelService iotProductThingModelService; @Resource private IotDeviceService iotDeviceService; @Resource @@ -91,8 +91,8 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ } private List getValidFunctionList(String productKey) { - return iotThinkModelFunctionService - .getThinkModelFunctionListByProductKey(productKey) + return iotProductThingModelService + .getProductThingModelListByProductKey(productKey) .stream() .filter(function -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(function.getType())) .toList(); From 290fcd94d56334e4706935a5b250c1d925a5eaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 16 Dec 2024 18:18:53 +0800 Subject: [PATCH 032/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E6=94=AF=E6=8C=81=EF=BC=8C=E5=8C=85=E5=90=AB=E6=8F=92?= =?UTF-8?q?=E4=BB=B6API=E5=92=8C=E7=A4=BA=E4=BE=8B=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/pom.xml | 1 + yudao-module-iot/yudao-module-iot-biz/pom.xml | 8 + .../admin/plugininfo/Greetings.java | 40 +++++ .../admin/plugininfo/PluginController.java | 134 ++++++++++++++++ .../admin/plugininfo/WhazzupGreeting.java | 34 ++++ .../framework/plugin/SpringConfiguration.java | 8 + .../service/plugininfo/PluginInfoService.java | 6 +- .../plugininfo/PluginInfoServiceImpl.java | 120 ++++++-------- .../yudao-module-iot-plugin-api/pom.xml | 30 ++++ .../yudao/module/iot/api/Greeting.java | 27 ++++ .../yudao/module/iot/api}/package-info.java | 2 +- .../yudao-module-iot-plugin/plugin.properties | 5 + .../yudao-module-iot-plugin/pom.xml | 148 ++++++++++++++++-- .../src/main/assembly/assembly.xml | 37 +++++ .../iot/plugin/IoTHttpPluginController.java | 22 +++ .../yudao/module/iot/plugin/IoTPlugin.java | 33 ++++ .../module/iot/plugin/IotPluginConfig.java | 16 ++ .../module/iot/plugin/WelcomePlugin.java | 58 +++++++ 18 files changed, 637 insertions(+), 92 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java rename yudao-module-iot/{yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin => yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api}/package-info.java (53%) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/plugin.properties create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java diff --git a/yudao-module-iot/pom.xml b/yudao-module-iot/pom.xml index d9002abea..d47d3c7f6 100644 --- a/yudao-module-iot/pom.xml +++ b/yudao-module-iot/pom.xml @@ -11,6 +11,7 @@ yudao-module-iot-api yudao-module-iot-biz yudao-module-iot-plugin + yudao-module-iot-plugin-api 4.0.0 diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index b003e1785..774d35380 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -25,6 +25,13 @@ ${revision} + + cn.iocoder.boot + yudao-module-iot-plugin-api + 0.0.1 + compile + + cn.iocoder.boot yudao-spring-boot-starter-biz-tenant @@ -75,6 +82,7 @@ org.pf4j pf4j-spring + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java new file mode 100644 index 000000000..a8e557f15 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; + +import cn.iocoder.yudao.module.iot.api.Greeting; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 打招呼 测试用例 + */ +@Component +public class Greetings { + + @Autowired + private List greetings; + + public void printGreetings() { + System.out.printf("找到扩展点的 %d 个扩展 '%s'%n", greetings.size(), Greeting.class.getName()); + for (Greeting greeting : greetings) { + System.out.println(">>> " + greeting.getGreeting()); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java new file mode 100644 index 000000000..c4f9ab465 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java @@ -0,0 +1,134 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; + +import jakarta.annotation.Resource; +import org.pf4j.spring.SpringPluginManager; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.security.PermitAll; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 插件 Controller 测试用例 + */ +@RestController +@RequestMapping("/iot/plugins") +public class PluginController { + + @Resource + private ApplicationContext applicationContext; + @Resource + private SpringPluginManager springPluginManager; + @Resource + private Greetings greetings; + + @Value("${pf4j.pluginsDir}") + private String pluginsDir; + + /** + * 上传插件 JAR 文件并加载插件 + * + * @param file 上传的 JAR 文件 + * @return 上传结果 + */ + @PermitAll + @PostMapping("/upload") + public ResponseEntity uploadPlugin(@RequestParam("file") MultipartFile file) { + if (file.isEmpty()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("上传的文件为空"); + } + + // 确保插件目录存在 + Path pluginsPath = Paths.get(pluginsDir); + try { + if (!Files.exists(pluginsPath)) { + Files.createDirectories(pluginsPath); + } + + // 保存上传的 JAR 文件到插件目录 + String filename = file.getOriginalFilename(); + if (filename == null || (!filename.endsWith(".jar") && !filename.endsWith(".zip"))) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("上传的文件不是 JAR 或 ZIP 文件"); + } + + Path jarPath = pluginsPath.resolve(filename); + + Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING); + + // 加载插件 + String pluginId = springPluginManager.loadPlugin(jarPath.toAbsolutePath()); + + // 启动插件 + springPluginManager.startPlugin(pluginId); + + return ResponseEntity.ok("插件上传并加载成功"); + } catch (IOException e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("上传插件时发生错误: " + e.getMessage()); + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("加载插件时发生错误: " + e.getMessage()); + } + } + + /** + * 卸载指定插件 + * + * @param pluginId 插件 ID + * @return 卸载结果 + */ + @PermitAll + @DeleteMapping("/unload/{pluginId}") + public ResponseEntity unloadPlugin(@PathVariable String pluginId) { + if (springPluginManager.getPlugins().stream().noneMatch(plugin -> plugin.getDescriptor().getPluginId().equals(pluginId))) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("插件未加载: " + pluginId); + } + + springPluginManager.stopPlugin(pluginId); + springPluginManager.unloadPlugin(pluginId); + + // 删除插件 JAR 文件(可选) +// PluginWrapper plugin = pluginManager.getPlugin(pluginId); +// PluginDescriptor descriptor = plugin.getDescriptor(); +// Path jarPath = Paths.get(pluginsDir).resolve(descriptor.getPluginId() + ".jar"); +// Files.deleteIfExists(jarPath); + + return ResponseEntity.ok("插件卸载成功: " + pluginId); + } + + /** + * 列出所有已加载的插件 + * + * @return 插件列表 + */ + @PermitAll + @GetMapping("/list") + public ResponseEntity> listPlugins() { + List plugins = springPluginManager.getPlugins().stream() + .map(plugin -> plugin.getDescriptor().getPluginId()) + .collect(Collectors.toList()); + return ResponseEntity.ok(plugins); + } + + /** + * 打印问候语 + * + * @return 1 + */ + @PermitAll + @GetMapping("/printGreetings") + public ResponseEntity printGreetings() { + greetings.printGreetings(); + return ResponseEntity.ok(1); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java new file mode 100644 index 000000000..b6ca7f322 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; + +import cn.iocoder.yudao.module.iot.api.Greeting; +import org.pf4j.Extension; +import org.springframework.stereotype.Component; + +/** + * 打招呼 测试用例 + */ +@Extension +@Component +public class WhazzupGreeting implements Greeting { + + @Override + public String getGreeting() { + return "Whazzup"; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java index f43b69c12..db03332d9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.iot.framework.plugin; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.Greetings; import org.pf4j.spring.SpringPluginManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; @Configuration public class SpringConfiguration { @@ -12,4 +14,10 @@ public class SpringConfiguration { return new SpringPluginManager(); } + @Bean + @DependsOn("pluginManager") + public Greetings greetings() { + return new Greetings(); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java index f9ae48677..867103402 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java @@ -7,8 +7,6 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import jakarta.validation.Valid; import org.springframework.web.multipart.MultipartFile; -import java.io.InputStream; - /** * IoT 插件信息 Service 接口 * @@ -57,7 +55,7 @@ public interface PluginInfoService { /** * 上传插件的 JAR 包 * - * @param id 插件id + * @param id 插件id * @param file 文件 */ void uploadJar(Long id, MultipartFile file); @@ -65,7 +63,7 @@ public interface PluginInfoService { /** * 更新插件的状态 * - * @param id 插件id + * @param id 插件id * @param status 状态 */ void updatePluginStatus(Long id, Integer status); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java index 65ad6ad1d..daa76acc6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java @@ -17,13 +17,18 @@ import org.pf4j.PluginDescriptor; import org.pf4j.PluginState; import org.pf4j.PluginWrapper; import org.pf4j.spring.SpringPluginManager; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.web.multipart.MultipartFile; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @@ -47,6 +52,9 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Resource private FileApi fileApi; + @Value("${pf4j.pluginsDir}") + private String pluginsDir; + @Override public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) { // 插入 @@ -132,7 +140,7 @@ public class PluginInfoServiceImpl implements PluginInfoService { // 4. 上传插件 String pluginIdNew; try { - String path = fileApi.createFile(IoUtil.readBytes(file.getInputStream())); + String path = fileApi.createFile(pluginsDir, IoUtil.readBytes(file.getInputStream())); Path pluginPath = Path.of(path); pluginIdNew = pluginManager.loadPlugin(pluginPath); } catch (Exception e) { @@ -144,10 +152,31 @@ public class PluginInfoServiceImpl implements PluginInfoService { throw exception(PLUGIN_INSTALL_FAILED); } - // 5. 读取配置文件和脚本 String configJson = ""; String script = ""; + try (JarFile jarFile = new JarFile(pluginWrapper.getPluginPath().toFile())) { + // 5.1 获取config文件在jar包中的路径 + String configFile = "classes/config.json"; + JarEntry configEntry = jarFile.getJarEntry(configFile); + + if (configEntry != null) { + // 5.2 读取配置文件 + configJson = IoUtil.readUtf8(jarFile.getInputStream(configEntry)); + log.info("configJson:{}", configJson); + } + + // 5.3 读取script.js脚本 + String scriptFile = "classes/script.js"; + JarEntry scriptEntity = jarFile.getJarEntry(scriptFile); + if (scriptEntity != null) { + // 5.4 读取脚本文件 + script = IoUtil.readUtf8(jarFile.getInputStream(scriptEntity)); + log.info("script:{}", script); + } + } catch (Exception e) { + throw exception(PLUGIN_INSTALL_FAILED); + } pluginInfoDo.setPluginId(pluginIdNew); pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); @@ -159,48 +188,6 @@ public class PluginInfoServiceImpl implements PluginInfoService { pluginInfoDo.setVersion(pluginDescriptor.getVersion()); pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription()); pluginInfoMapper.updateById(pluginInfoDo); - - - // 5. 读取配置文件和脚本 -// String configJson = ""; - // String script = ""; -// try (JarFile jarFile = new JarFile(pluginInfoUpdate.getPluginPath())) { -// // 5.1 获取config文件在jar包中的路径 -// String configFile = "classes/config.json"; -// JarEntry configEntry = jarFile.getJarEntry(configFile); -// -// if (configEntry != null) { -// // 5.2 读取配置文件 -// configJson = IoUtil.read(jarFile.getInputStream(configEntry), Charset.defaultCharset()); -// log.info("configJson:{}", configJson); -// } -// -// // 5.3 读取script.js脚本 -// String scriptFile = "classes/script.js"; -// JarEntry scriptEntity = jarFile.getJarEntry(scriptFile); -// if (scriptEntity != null) { -// // 5.4 读取脚本文件 -// script = IoUtil.read(jarFile.getInputStream(scriptEntity), Charset.defaultCharset()); -// log.info("script:{}", script); -// } -// } catch (Exception e) { -// throw exception(PLUGIN_INSTALL_FAILED); -// } - - -// PluginState pluginState = pluginInfoUpdate.getPluginState(); -// if (pluginState == PluginState.STARTED) { -// pluginInfoDo.setStatus(IotPluginStatusEnum.RUNNING.getStatus()); -// } -// pluginInfoDo.setPluginId(pluginInfoUpdate.getPluginId()); -// pluginInfoDo.setFile(file.getOriginalFilename()); -// pluginInfoDo.setConfigSchema(configJson); -// pluginInfoDo.setScript(script); -// -// PluginDescriptor pluginDescriptor = pluginInfoUpdate.getPluginDescriptor(); -// pluginInfoDo.setVersion(pluginDescriptor.getPluginVersion()); -// pluginInfoDo.setDescription(pluginDescriptor.getDescription()); -// pluginInfoMapper.updateById(pluginInfoDo); } @Override @@ -213,26 +200,22 @@ public class PluginInfoServiceImpl implements PluginInfoService { throw exception(PLUGIN_STATUS_INVALID); } - // 插件包为空 -// String pluginId = pluginInfoDo.getPluginId(); -// if (StrUtil.isBlank(pluginId)) { -// throw exception(PLUGIN_INFO_NOT_EXISTS); -// } -// com.gitee.starblues.core.PluginInfo pluginInfo = pluginOperator.getPluginInfo(pluginId); -// if (pluginInfo != null) { -// if (pluginInfoDo.getStatus().equals(IotPluginStatusEnum.RUNNING.getStatus()) && pluginInfo.getPluginState() != PluginState.STARTED) { -// // 启动插件 -// pluginOperator.start(pluginId); -// } else if (pluginInfoDo.getStatus().equals(IotPluginStatusEnum.STOPPED.getStatus()) && pluginInfo.getPluginState() == PluginState.STARTED) { -// // 停止插件 -// pluginOperator.stop(pluginId); -// } -// } else { -// // 已经停止,未获取到插件 -// if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { -// throw exception(PLUGIN_STATUS_INVALID); -// } -// } + String pluginId = pluginInfoDo.getPluginId(); + PluginWrapper plugin = pluginManager.getPlugin(pluginId); + if (plugin != null) { + if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) && plugin.getPluginState() != PluginState.STARTED) { + // 启动插件 + pluginManager.startPlugin(pluginId); + } else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) && plugin.getPluginState() == PluginState.STARTED) { + // 停止插件 + pluginManager.stopPlugin(pluginId); + } + } else { + // 已经停止,未获取到插件 + if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { + throw exception(PLUGIN_STATUS_INVALID); + } + } pluginInfoDo.setStatus(status); pluginInfoMapper.updateById(pluginInfoDo); } @@ -244,20 +227,13 @@ public class PluginInfoServiceImpl implements PluginInfoService { @SneakyThrows private void startPlugins() { -// while (!pluginOperator.inited()) { -// Thread.sleep(1000L); -// } - for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { continue; } log.info("start plugin:{}", pluginInfoDO.getPluginId()); try { -// com.gitee.starblues.core.PluginInfo plugin = pluginOperator.getPluginInfo(pluginInfoDO.getPluginId()); -// if (plugin != null) { -// pluginOperator.start(plugin.getPluginId()); -// } + pluginManager.startPlugin(pluginInfoDO.getPluginId()); } catch (Exception e) { log.error("start plugin error", e); } diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml b/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml new file mode 100644 index 000000000..e04e818de --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + cn.iocoder.boot + yudao-module-iot-plugin-api + 0.0.1 + jar + + ${project.artifactId} + + 物联网 模块插件 API,暴露给其它模块调用 + + + + 0.9.0 + + + + + + org.pf4j + pf4j-spring + ${pf4j-spring.version} + provided + + + + diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java new file mode 100644 index 000000000..b28454937 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.iocoder.yudao.module.iot.api; + +import org.pf4j.ExtensionPoint; + +/** + * @author Decebal Suiu + */ +public interface Greeting extends ExtensionPoint { + + String getGreeting(); + +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java similarity index 53% rename from yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java rename to yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java index 567dcb038..7da0c665b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java +++ b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java @@ -3,4 +3,4 @@ * * TODO 芋艿:后续删除 */ -package cn.iocoder.yudao.module.iot.plugin; +package cn.iocoder.yudao.module.iot.api; diff --git a/yudao-module-iot/yudao-module-iot-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/plugin.properties new file mode 100644 index 000000000..bbfe3185c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/plugin.properties @@ -0,0 +1,5 @@ +plugin.id=iot-plugin-hppt +plugin.class=cn.iocoder.yudao.module.iot.plugin.WelcomePlugin +plugin.version=0.0.1 +plugin.provider=ahh +plugin.dependencies= diff --git a/yudao-module-iot/yudao-module-iot-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/pom.xml index 49c321581..52e58d57b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/pom.xml @@ -1,31 +1,149 @@ - - - yudao-module-iot - cn.iocoder.boot - ${revision} - + 4.0.0 + cn.iocoder.boot yudao-module-iot-plugin + 0.0.1 jar ${project.artifactId} - - 物联网 模块 - 插件 - + 物联网 模块 - 插件 + + + + iot-plugin-http + cn.iocoder.yudao.module.iot.plugin.WelcomePlugin + 0.0.1 + ahh + + + + 17 + ${java.version} + ${java.version} + 1.6 + 2.3 + 2.4 + 0.9.0 + + 3.3.1 + UTF-8 + + - cn.iocoder.boot - yudao-common + org.springframework.boot + spring-boot-starter-web + ${spring.boot.version} + provided - + org.pf4j pf4j-spring + ${pf4j-spring.version} + provided + + + + cn.iocoder.boot + yudao-module-iot-plugin-api + ${project.version} - + + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${maven-antrun-plugin.version} + + + unzip jar file + package + + + + + + + run + + + + + + + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + + src/main/assembly/assembly.xml + + + false + + + + make-assembly + package + + attached + + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.dependencies} + + + + + + + maven-deploy-plugin + + true + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml new file mode 100644 index 000000000..ce2e92cf9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml @@ -0,0 +1,37 @@ + + + plugin + + zip + + false + + + false + runtime + lib + + *:jar:* + + + + + + + target/plugin-classes + classes + + + diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java new file mode 100644 index 000000000..a6633388e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.plugin; + + +import org.pf4j.Extension; +import org.pf4j.ExtensionPoint; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/iot/plugin-demo") +@Extension +public class IoTHttpPluginController implements ExtensionPoint { + + @GetMapping("/greet") + public String greet() { + return "Hello from MyPlugin!"; + } + + @PostMapping("/message") + public void receiveMessage(@RequestBody String message) { + System.out.println("Received message: " + message); + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java new file mode 100644 index 000000000..78c07c404 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import org.pf4j.PluginWrapper; +import org.pf4j.spring.SpringPlugin; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +public class IoTPlugin extends SpringPlugin { + public IoTPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + System.out.println("IoTPlugin 启动"); + } + + @Override + public void stop() { + System.out.println("IoTPlugin 停止"); + super.stop(); // to close applicationContext + } + + @Override + protected ApplicationContext createApplicationContext() { + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + applicationContext.setClassLoader(getWrapper().getPluginClassLoader()); + applicationContext.register(IoTHttpPluginController.class); // 注册 IoTPluginConfig + applicationContext.refresh(); + System.out.println("IoTPlugin 加载完成"); + return applicationContext; + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java new file mode 100644 index 000000000..02b8bb5a0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.server.ConfigurableWebServerFactory; +import org.springframework.context.annotation.Bean; + +@Configuration +public class IoTPluginConfig { + + @Bean + public IoTHttpPluginController ioTHttpPluginController() { + return new IoTHttpPluginController(); + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java new file mode 100644 index 000000000..5c53cf8a8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.iocoder.yudao.module.iot.api.Greeting; +import org.apache.commons.lang.StringUtils; +import org.pf4j.Extension; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.pf4j.RuntimeMode; + +/** + * 打招呼 测试用例 + */ +public class WelcomePlugin extends Plugin { + + public WelcomePlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + System.out.println("WelcomePlugin.start()"); + // for testing the development mode + if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { + System.out.println(StringUtils.upperCase("WelcomePlugin")); + } + } + + @Override + public void stop() { + System.out.println("WelcomePlugin.stop()"); + } + + @Extension + public static class WelcomeGreeting implements Greeting { + + @Override + public String getGreeting() { + return "Welcome to PF4J"; + } + + } + +} \ No newline at end of file From ce4912304388f6dd4b38cdd1718b90019aa7578b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 16 Dec 2024 18:43:08 +0800 Subject: [PATCH 033/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E3=80=91IoT=EF=BC=9A=E6=9B=B4=E6=96=B0=E9=97=AE?= =?UTF-8?q?=E5=80=99=E8=AF=AD=E6=89=93=E5=8D=B0=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E9=97=AE=E5=80=99=E8=AF=AD=E6=95=B0=E9=87=8F?= =?UTF-8?q?=EF=BC=9B=E5=88=A0=E9=99=A4=E4=B8=8D=E5=86=8D=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=9A=84=E6=8F=92=E4=BB=B6=E6=8E=A7=E5=88=B6=E5=99=A8=E5=92=8C?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/plugininfo/Greetings.java | 5 +-- .../admin/plugininfo/PluginController.java | 6 ++-- .../iot/plugin/IoTHttpPluginController.java | 22 ------------- .../yudao/module/iot/plugin/IoTPlugin.java | 33 ------------------- .../module/iot/plugin/IotPluginConfig.java | 16 --------- 5 files changed, 6 insertions(+), 76 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java index a8e557f15..1b29a3447 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java @@ -30,11 +30,12 @@ public class Greetings { @Autowired private List greetings; - public void printGreetings() { + public Integer printGreetings() { System.out.printf("找到扩展点的 %d 个扩展 '%s'%n", greetings.size(), Greeting.class.getName()); for (Greeting greeting : greetings) { System.out.println(">>> " + greeting.getGreeting()); } + return greetings.size(); } -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java index c4f9ab465..4cd22bcca 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java @@ -123,12 +123,12 @@ public class PluginController { /** * 打印问候语 * - * @return 1 + * @return 问候语数量 */ @PermitAll @GetMapping("/printGreetings") public ResponseEntity printGreetings() { - greetings.printGreetings(); - return ResponseEntity.ok(1); + Integer count = greetings.printGreetings(); + return ResponseEntity.ok(count); } } diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java deleted file mode 100644 index a6633388e..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - - -import org.pf4j.Extension; -import org.pf4j.ExtensionPoint; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/iot/plugin-demo") -@Extension -public class IoTHttpPluginController implements ExtensionPoint { - - @GetMapping("/greet") - public String greet() { - return "Hello from MyPlugin!"; - } - - @PostMapping("/message") - public void receiveMessage(@RequestBody String message) { - System.out.println("Received message: " + message); - } -} diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java deleted file mode 100644 index 78c07c404..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - -import org.pf4j.PluginWrapper; -import org.pf4j.spring.SpringPlugin; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -public class IoTPlugin extends SpringPlugin { - public IoTPlugin(PluginWrapper wrapper) { - super(wrapper); - } - - @Override - public void start() { - System.out.println("IoTPlugin 启动"); - } - - @Override - public void stop() { - System.out.println("IoTPlugin 停止"); - super.stop(); // to close applicationContext - } - - @Override - protected ApplicationContext createApplicationContext() { - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); - applicationContext.setClassLoader(getWrapper().getPluginClassLoader()); - applicationContext.register(IoTHttpPluginController.class); // 注册 IoTPluginConfig - applicationContext.refresh(); - System.out.println("IoTPlugin 加载完成"); - return applicationContext; - } -} diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java deleted file mode 100644 index 02b8bb5a0..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.server.ConfigurableWebServerFactory; -import org.springframework.context.annotation.Bean; - -@Configuration -public class IoTPluginConfig { - - @Bean - public IoTHttpPluginController ioTHttpPluginController() { - return new IoTHttpPluginController(); - } -} From 0245aac530f8b07305f6feeb14ff7dbf035ee8ab Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 16 Dec 2024 20:42:07 +0800 Subject: [PATCH 034/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E8=AF=84=E5=AE=A1=20thinkmodel?= =?UTF-8?q?=20=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enums/thingmodel/IotProductThingModelAccessModeEnum.java | 2 +- .../iot/enums/thingmodel/IotProductThingModelTypeEnum.java | 1 + .../thingmodel/dataType/ThingModelArgument.java | 1 + .../thingmodel/dataType/ThingModelArrayDataSpecs.java | 1 - .../yudao/module/iot/convert/device/IotDeviceDataConvert.java | 1 + .../service/productthingmodel/IotProductThingModelService.java | 1 - 6 files changed, 4 insertions(+), 3 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java index 80c96837f..a75501803 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * IOT 访问方式枚举类 + * IOT 访问方式枚举类 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java index 153e93ecc..a12299e99 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java @@ -6,6 +6,7 @@ import lombok.Getter; import java.util.Arrays; +// TODO @芋艿:纠结下,到底叫 thinkmodel 好,还是 function 好 /** * IOT 产品功能(物模型)类型枚举类 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java index 40d691971..289bb6010 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java @@ -1,3 +1,4 @@ +// TODO @puhui999:productthingmodel 是不是不要这层包了 package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java index 5eeef76b9..3be26e296 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java index 2de045679..d8f6e4704 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.convert.device; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; +// TODO 是否要删除? @Mapper public interface IotDeviceDataConvert { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java index 3cc568756..413b6b014 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java @@ -23,7 +23,6 @@ public interface IotProductThingModelService { */ Long createProductThingModel(@Valid IotProductThingModelSaveReqVO createReqVO); - /** * 更新产品物模型 * From 91b817a9ecd1b22d2ea1ee5e0aa1a17f4b2bbd43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 16 Dec 2024 22:25:01 +0800 Subject: [PATCH 035/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E3=80=91IoT=EF=BC=9A=E5=88=A0=E9=99=A4=20WelcomePlugi?= =?UTF-8?q?n=EF=BC=8C=E6=96=B0=E5=A2=9E=20HttpPlugin=20=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20HTTP=20=E6=9C=8D=E5=8A=A1=E5=99=A8=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/pom.xml | 2 +- .../yudao-module-iot-plugin-api/pom.xml | 4 +- .../yudao-module-iot-plugin/plugin.properties | 5 - .../yudao-module-iot-plugin/pom.xml | 149 ++--------------- .../module/iot/plugin/WelcomePlugin.java | 58 ------- .../plugin.properties | 5 + .../yudao-module-iot-http-plugin/pom.xml | 156 ++++++++++++++++++ .../src/main/assembly/assembly.xml | 0 .../yudao/module/iot/plugin/HttpPlugin.java | 79 +++++++++ 9 files changed, 253 insertions(+), 205 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/plugin.properties delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml rename yudao-module-iot/yudao-module-iot-plugin/{ => yudao-module-iot-http-plugin}/src/main/assembly/assembly.xml (100%) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java diff --git a/yudao-module-iot/pom.xml b/yudao-module-iot/pom.xml index d47d3c7f6..ecfefab64 100644 --- a/yudao-module-iot/pom.xml +++ b/yudao-module-iot/pom.xml @@ -10,8 +10,8 @@ yudao-module-iot-api yudao-module-iot-biz - yudao-module-iot-plugin yudao-module-iot-plugin-api + yudao-module-iot-plugin 4.0.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml b/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml index e04e818de..6d5eb765b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 cn.iocoder.boot diff --git a/yudao-module-iot/yudao-module-iot-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/plugin.properties deleted file mode 100644 index bbfe3185c..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/plugin.properties +++ /dev/null @@ -1,5 +0,0 @@ -plugin.id=iot-plugin-hppt -plugin.class=cn.iocoder.yudao.module.iot.plugin.WelcomePlugin -plugin.version=0.0.1 -plugin.provider=ahh -plugin.dependencies= diff --git a/yudao-module-iot/yudao-module-iot-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/pom.xml index 52e58d57b..8ec68638f 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/pom.xml @@ -1,149 +1,20 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 cn.iocoder.boot yudao-module-iot-plugin 0.0.1 - jar + pom + + + yudao-module-iot-http-plugin + ${project.artifactId} - 物联网 模块 - 插件 + + 物联网模块 - 插件模块 + - - - iot-plugin-http - cn.iocoder.yudao.module.iot.plugin.WelcomePlugin - 0.0.1 - ahh - - - - 17 - ${java.version} - ${java.version} - 1.6 - 2.3 - 2.4 - 0.9.0 - - 3.3.1 - UTF-8 - - - - - - org.springframework.boot - spring-boot-starter-web - ${spring.boot.version} - provided - - - - org.pf4j - pf4j-spring - ${pf4j-spring.version} - provided - - - - cn.iocoder.boot - yudao-module-iot-plugin-api - ${project.version} - - - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - ${maven-antrun-plugin.version} - - - unzip jar file - package - - - - - - - run - - - - - - - maven-assembly-plugin - ${maven-assembly-plugin.version} - - - - src/main/assembly/assembly.xml - - - false - - - - make-assembly - package - - attached - - - - - - - org.apache.maven.plugins - maven-jar-plugin - ${maven-jar-plugin.version} - - - - ${plugin.id} - ${plugin.class} - ${plugin.version} - ${plugin.provider} - ${plugin.dependencies} - - - - - - - maven-deploy-plugin - - true - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java deleted file mode 100644 index 5c53cf8a8..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2012-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package cn.iocoder.yudao.module.iot.plugin; - -import cn.iocoder.yudao.module.iot.api.Greeting; -import org.apache.commons.lang.StringUtils; -import org.pf4j.Extension; -import org.pf4j.Plugin; -import org.pf4j.PluginWrapper; -import org.pf4j.RuntimeMode; - -/** - * 打招呼 测试用例 - */ -public class WelcomePlugin extends Plugin { - - public WelcomePlugin(PluginWrapper wrapper) { - super(wrapper); - } - - @Override - public void start() { - System.out.println("WelcomePlugin.start()"); - // for testing the development mode - if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { - System.out.println(StringUtils.upperCase("WelcomePlugin")); - } - } - - @Override - public void stop() { - System.out.println("WelcomePlugin.stop()"); - } - - @Extension - public static class WelcomeGreeting implements Greeting { - - @Override - public String getGreeting() { - return "Welcome to PF4J"; - } - - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties new file mode 100644 index 000000000..694c97ba5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties @@ -0,0 +1,5 @@ +plugin.id=http-plugin +plugin.class=cn.iocoder.yudao.module.iot.plugin.HttpPlugin +plugin.version=0.0.1 +plugin.provider=ahh +plugin.dependencies= diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml new file mode 100644 index 000000000..eccf47feb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -0,0 +1,156 @@ + + + 4.0.0 + cn.iocoder.boot + yudao-module-iot-http-plugin + 0.0.1 + jar + + ${project.artifactId} + 物联网 模块 - http 插件 + + + + http-plugin + cn.iocoder.yudao.module.iot.plugin.HttpPlugin + 0.0.1 + ahh + + + + 17 + ${java.version} + ${java.version} + 1.6 + 2.3 + 2.4 + 0.9.0 + + 1.18.34 + 3.3.1 + UTF-8 + + + + + + org.springframework.boot + spring-boot-starter-web + ${spring.boot.version} + provided + + + + org.pf4j + pf4j-spring + ${pf4j-spring.version} + provided + + + + cn.iocoder.boot + yudao-module-iot-plugin-api + ${project.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${maven-antrun-plugin.version} + + + unzip jar file + package + + + + + + + run + + + + + + + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + + src/main/assembly/assembly.xml + + + false + + + + make-assembly + package + + attached + + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.dependencies} + + + + + + + maven-deploy-plugin + + true + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java new file mode 100644 index 000000000..32926be45 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.iocoder.yudao.module.iot.api.Greeting; +import com.sun.net.httpserver.HttpServer; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.pf4j.Extension; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.pf4j.RuntimeMode; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; + +/** + * 一个启动 HTTP 服务器的简单插件。 + */ +@Slf4j +public class HttpPlugin extends Plugin { + + private HttpServer server; + + public HttpPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + log.info("HttpPlugin.start()"); + // for testing the development mode + if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { + log.info("HttpPlugin in DEVELOPMENT mode"); + } + startHttpServer(); + } + + @Override + public void stop() { + log.info("HttpPlugin.stop()"); + stopHttpServer(); + } + + private void startHttpServer() { + try { + server = HttpServer.create(new InetSocketAddress(9081), 0); + server.createContext("/", exchange -> { + String response = "Welcome to PF4J HTTP Server"; + exchange.sendResponseHeaders(200, response.getBytes().length); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + }); + server.setExecutor(null); + server.start(); + log.info("HTTP server started on port 9081"); + } catch (IOException e) { + log.error("Error starting HTTP server", e); + } + } + + private void stopHttpServer() { + if (server != null) { + server.stop(0); + log.info("HTTP server stopped"); + } + } + + @Extension + public static class WelcomeGreeting implements Greeting { + + @Override + public String getGreeting() { + return "Welcome to PF4J"; + } + + } + +} \ No newline at end of file From 10da1e095be48e839851a3c74c4352ced9999e13 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Tue, 17 Dec 2024 16:53:42 +0800 Subject: [PATCH 036/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IOT:=20=E4=BA=A7=E5=93=81=E7=89=A9=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E4=BB=A3=E7=A0=81=E8=AF=84=E5=AE=A1=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotProductThinkModelAccessModeEnum.java} | 4 +- .../IotProductThinkModelTypeEnum.java} | 10 +- .../IotProductThingModelController.java | 84 -------- .../dataType/ThingModelArgument.java | 18 -- .../IotProductThingModelController.http | 28 +-- .../IotProductThinkModelController.java | 84 ++++++++ .../model/ThinkModelEvent.java} | 8 +- .../model/ThinkModelProperty.java} | 14 +- .../model/ThinkModelRespVO.java} | 10 +- .../model/ThinkModelService.java} | 10 +- .../model/dataType/ThinkModelArgument.java | 17 ++ .../dataType/ThinkModelArrayDataSpecs.java} | 6 +- .../ThinkModelBoolOrEnumDataSpecs.java} | 4 +- .../model/dataType/ThinkModelDataSpecs.java} | 24 +-- .../ThinkModelDateOrTextDataSpecs.java} | 4 +- .../dataType/ThinkModelNumericDataSpec.java} | 4 +- .../dataType/ThinkModelStructDataSpecs.java} | 12 +- .../vo/IotProductThinkModelPageReqVO.java} | 8 +- .../vo/IotProductThinkModelRespVO.java} | 16 +- .../vo/IotProductThinkModelSaveReqVO.java} | 20 +- .../convert/device/IotDeviceDataConvert.java | 2 +- .../IotProductThingModelConvert.java | 62 ------ .../IotProductThinkModelConvert.java | 62 ++++++ .../dataobject/device/IotDeviceDataDO.java | 10 +- .../dal/dataobject/tdengine/FieldParser.java | 11 +- ...delMessage.java => ThinkModelMessage.java} | 2 +- .../IotProductThinkModelDO.java} | 26 +-- .../IotProductThinkModelMapper.java | 62 ++++++ .../IotProductThingModelMapper.java | 62 ------ .../device/IotDeviceDataServiceImpl.java | 22 +- .../product/IotProductServiceImpl.java | 4 +- .../tdengine/IotSuperTableService.java | 4 +- .../tdengine/IotSuperTableServiceImpl.java | 34 ++-- ....java => IotThinkModelMessageService.java} | 6 +- ...a => IotThinkModelMessageServiceImpl.java} | 44 ++-- .../IotProductThinkModelService.java} | 24 +-- .../IotProductThinkModelServiceImpl.java} | 188 +++++++++--------- 37 files changed, 504 insertions(+), 506 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/{thingmodel/IotProductThingModelAccessModeEnum.java => thinkmodel/IotProductThinkModelAccessModeEnum.java} (68%) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/{thingmodel/IotProductThingModelTypeEnum.java => thinkmodel/IotProductThinkModelTypeEnum.java} (73%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel => thinkmodel}/IotProductThingModelController.http (82%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThinkModelController.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/ThingModelEvent.java => thinkmodel/model/ThinkModelEvent.java} (58%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/ThingModelProperty.java => thinkmodel/model/ThinkModelProperty.java} (68%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/ThingModelRespVO.java => thinkmodel/model/ThinkModelRespVO.java} (66%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/ThingModelService.java => thinkmodel/model/ThinkModelService.java} (53%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java => thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java} (79%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java => thinkmodel/model/dataType/ThinkModelBoolOrEnumDataSpecs.java} (82%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java => thinkmodel/model/dataType/ThinkModelDataSpecs.java} (50%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java => thinkmodel/model/dataType/ThinkModelDateOrTextDataSpecs.java} (81%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java => thinkmodel/model/dataType/ThinkModelNumericDataSpec.java} (89%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/thingmodel/dataType/ThingModelStructDataSpecs.java => thinkmodel/model/dataType/ThinkModelStructDataSpecs.java} (74%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/vo/IotProductThingModelPageReqVO.java => thinkmodel/vo/IotProductThinkModelPageReqVO.java} (76%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/vo/IotProductThingModelRespVO.java => thinkmodel/vo/IotProductThinkModelRespVO.java} (75%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{productthingmodel/vo/IotProductThingModelSaveReqVO.java => thinkmodel/vo/IotProductThinkModelSaveReqVO.java} (70%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/productthingmodel/IotProductThingModelConvert.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodel/IotProductThinkModelConvert.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/{ThingModelMessage.java => ThinkModelMessage.java} (97%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/{productthingmodel/IotProductThingModelDO.java => thinkmodel/IotProductThinkModelDO.java} (66%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodel/IotProductThinkModelMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotProductThingModelMapper.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/{IotThingModelMessageService.java => IotThinkModelMessageService.java} (66%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/{IotThingModelMessageServiceImpl.java => IotThinkModelMessageServiceImpl.java} (86%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{productthingmodel/IotProductThingModelService.java => thinkmodel/IotProductThinkModelService.java} (58%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{productthingmodel/IotProductThingModelServiceImpl.java => thinkmodel/IotProductThinkModelServiceImpl.java} (66%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelAccessModeEnum.java similarity index 68% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelAccessModeEnum.java index a75501803..b7f6ca312 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelAccessModeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.enums.thingmodel; +package cn.iocoder.yudao.module.iot.enums.thinkmodel; import lombok.AllArgsConstructor; import lombok.Getter; @@ -10,7 +10,7 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotProductThingModelAccessModeEnum { +public enum IotProductThinkModelAccessModeEnum { READ_ONLY("r"), READ_WRITE("rw"); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java similarity index 73% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java index a12299e99..7c7562e27 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.enums.thingmodel; +package cn.iocoder.yudao.module.iot.enums.thinkmodel; import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; @@ -14,13 +14,13 @@ import java.util.Arrays; */ @AllArgsConstructor @Getter -public enum IotProductThingModelTypeEnum implements IntArrayValuable { +public enum IotProductThinkModelTypeEnum implements IntArrayValuable { PROPERTY(1, "属性"), SERVICE(2, "服务"), EVENT(3, "事件"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductThingModelTypeEnum::getType).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductThinkModelTypeEnum::getType).toArray(); /** * 类型 @@ -31,8 +31,8 @@ public enum IotProductThingModelTypeEnum implements IntArrayValuable { */ private final String description; - public static IotProductThingModelTypeEnum valueOfType(Integer type) { - for (IotProductThingModelTypeEnum value : values()) { + public static IotProductThinkModelTypeEnum valueOfType(Integer type) { + for (IotProductThinkModelTypeEnum value : values()) { if (value.getType().equals(type)) { return value; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java deleted file mode 100644 index 11a2ffcc5..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.java +++ /dev/null @@ -1,84 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.productthingmodel.IotProductThingModelConvert; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; -import cn.iocoder.yudao.module.iot.service.productthingmodel.IotProductThingModelService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - IoT 产品物模型") -@RestController -@RequestMapping("/iot/product-thing-model") -@Validated -public class IotProductThingModelController { - - @Resource - private IotProductThingModelService thinkModelFunctionService; - - @PostMapping("/create") - @Operation(summary = "创建产品物模型") - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:create')") - public CommonResult createProductThingModel(@Valid @RequestBody IotProductThingModelSaveReqVO createReqVO) { - return success(thinkModelFunctionService.createProductThingModel(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新产品物模型") - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:update')") - public CommonResult updateProductThingModel(@Valid @RequestBody IotProductThingModelSaveReqVO updateReqVO) { - thinkModelFunctionService.updateProductThingModel(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除产品物模型") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:delete')") - public CommonResult deleteProductThingModel(@RequestParam("id") Long id) { - thinkModelFunctionService.deleteProductThingModel(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得产品物模型") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") - public CommonResult getProductThingModel(@RequestParam("id") Long id) { - IotProductThingModelDO function = thinkModelFunctionService.getProductThingModel(id); - return success(IotProductThingModelConvert.INSTANCE.convert(function)); - } - - @GetMapping("/list-by-product-id") - @Operation(summary = "获得产品物模型") - @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") - public CommonResult> getProductThingModelListByProductId(@RequestParam("productId") Long productId) { - List list = thinkModelFunctionService.getProductThingModelListByProductId(productId); - return success(IotProductThingModelConvert.INSTANCE.convertList(list)); - } - - @GetMapping("/page") - @Operation(summary = "获得产品物模型分页") - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") - public CommonResult> getProductThingModelPage(@Valid IotProductThingModelPageReqVO pageReqVO) { - PageResult pageResult = thinkModelFunctionService.getProductThingModelPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotProductThingModelRespVO.class)); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java deleted file mode 100644 index 289bb6010..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArgument.java +++ /dev/null @@ -1,18 +0,0 @@ -// TODO @puhui999:productthingmodel 是不是不要这层包了 -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; - -import lombok.Data; - -@Data -public class ThingModelArgument { - - private String identifier; - private String name; - private ThingModelDataSpecs dataType; - /** - * 用于区分输入或输出参数,"input" 或 "output" - */ - private String direction; - private String description; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThingModelController.http similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.http rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThingModelController.http index 7742705ef..2343eed38 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/IotProductThingModelController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThingModelController.http @@ -1,5 +1,5 @@ -### 请求 /iot/product-thing-model/create 接口 => 成功 -POST {{baseUrl}}/iot/product-thing-model/create +### 请求 /iot/product-think-model/create 接口 => 成功 +POST {{baseUrl}}/iot/product-think-model/create Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -30,8 +30,8 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/product-thing-model/create 接口 => 成功 -POST {{baseUrl}}/iot/product-thing-model/create +### 请求 /iot/product-think-model/create 接口 => 成功 +POST {{baseUrl}}/iot/product-think-model/create Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -65,8 +65,8 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/product-thing-model/create 接口 => 成功 -POST {{baseUrl}}/iot/product-thing-model/create +### 请求 /iot/product-think-model/create 接口 => 成功 +POST {{baseUrl}}/iot/product-think-model/create Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -134,8 +134,8 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/product-thing-model/update 接口 => 成功 -PUT {{baseUrl}}/iot/product-thing-model/update +### 请求 /iot/product-think-model/update 接口 => 成功 +PUT {{baseUrl}}/iot/product-think-model/update Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -170,18 +170,18 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/product-thing-model/delete 接口 => 成功 -DELETE {{baseUrl}}/iot/product-thing-model/delete?id=36 +### 请求 /iot/product-think-model/delete 接口 => 成功 +DELETE {{baseUrl}}/iot/product-think-model/delete?id=36 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} -### 请求 /iot/product-thing-model/get 接口 => 成功 -GET {{baseUrl}}/iot/product-thing-model/get?id=40 +### 请求 /iot/product-think-model/get 接口 => 成功 +GET {{baseUrl}}/iot/product-think-model/get?id=40 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} -### 请求 /iot/product-thing-model/list-by-product-id 接口 => 成功 -GET {{baseUrl}}/iot/product-thing-model/list-by-product-id?productId=1001 +### 请求 /iot/product-think-model/list-by-product-id 接口 => 成功 +GET {{baseUrl}}/iot/product-think-model/list-by-product-id?productId=1001 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThinkModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThinkModelController.java new file mode 100644 index 000000000..03408b59d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThinkModelController.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.thinkmodel.IotProductThinkModelConvert; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 产品物模型") +@RestController +@RequestMapping("/iot/product-think-model") +@Validated +public class IotProductThinkModelController { + + @Resource + private IotProductThinkModelService thinkModelFunctionService; + + @PostMapping("/create") + @Operation(summary = "创建产品物模型") + @PreAuthorize("@ss.hasPermission('iot:product-think-model:create')") + public CommonResult createProductThinkModel(@Valid @RequestBody IotProductThinkModelSaveReqVO createReqVO) { + return success(thinkModelFunctionService.createProductThinkModel(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品物模型") + @PreAuthorize("@ss.hasPermission('iot:product-think-model:update')") + public CommonResult updateProductThinkModel(@Valid @RequestBody IotProductThinkModelSaveReqVO updateReqVO) { + thinkModelFunctionService.updateProductThinkModel(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品物模型") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:product-think-model:delete')") + public CommonResult deleteProductThinkModel(@RequestParam("id") Long id) { + thinkModelFunctionService.deleteProductThinkModel(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品物模型") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:product-think-model:query')") + public CommonResult getProductThinkModel(@RequestParam("id") Long id) { + IotProductThinkModelDO function = thinkModelFunctionService.getProductThinkModel(id); + return success(IotProductThinkModelConvert.INSTANCE.convert(function)); + } + + @GetMapping("/list-by-product-id") + @Operation(summary = "获得产品物模型") + @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:product-think-model:query')") + public CommonResult> getProductThinkModelListByProductId(@RequestParam("productId") Long productId) { + List list = thinkModelFunctionService.getProductThinkModelListByProductId(productId); + return success(IotProductThinkModelConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品物模型分页") + @PreAuthorize("@ss.hasPermission('iot:product-think-model:query')") + public CommonResult> getProductThinkModelPage(@Valid IotProductThinkModelPageReqVO pageReqVO) { + PageResult pageResult = thinkModelFunctionService.getProductThinkModelPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotProductThinkModelRespVO.class)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelEvent.java similarity index 58% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelEvent.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelEvent.java index 11563dfa8..7d16aa50b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelEvent.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelArgument; import lombok.Data; import java.util.List; @Data -public class ThingModelEvent { +public class ThinkModelEvent { /** * 事件标识符 @@ -26,7 +26,7 @@ public class ThingModelEvent { * "info"、"alert"、"error" */ private String type; - private List outputData; + private List outputData; private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelProperty.java similarity index 68% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelProperty.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelProperty.java index b07d00c94..a4d2e9892 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelProperty.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelDataSpecs; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelDataSpecs; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelAccessModeEnum; import lombok.Data; import java.util.List; @@ -14,7 +14,7 @@ import java.util.List; * @author HUIHUI */ @Data -public class ThingModelProperty { +public class ThinkModelProperty { /** * 属性标识符 @@ -30,7 +30,7 @@ public class ThingModelProperty { private String description; /** * 云端可以对该属性进行的操作类型 - * 关联枚举 {@link IotProductThingModelAccessModeEnum} + * 关联枚举 {@link IotProductThinkModelAccessModeEnum} */ private String accessMode; /** @@ -47,10 +47,10 @@ public class ThingModelProperty { /** * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 */ - private ThingModelDataSpecs dataSpecs; + private ThinkModelDataSpecs dataSpecs; /** * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 */ - private List dataSpecsList; + private List dataSpecsList; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelRespVO.java similarity index 66% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelRespVO.java index eeb0937bf..7eb06ce39 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model; import lombok.*; @@ -9,7 +9,7 @@ import java.util.List; @NoArgsConstructor @AllArgsConstructor @ToString -public class ThingModelRespVO { +public class ThinkModelRespVO { /** * 产品编号 @@ -35,16 +35,16 @@ public class ThingModelRespVO { /** * 属性列表 */ - private List properties; + private List properties; /** * 服务列表 */ - private List services; + private List services; /** * 事件列表 */ - private List events; + private List events; } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelService.java similarity index 53% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelService.java index dfcc8a64b..851df3656 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelService.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelArgument; import lombok.Data; import java.util.List; @Data -public class ThingModelService { +public class ThinkModelService { /** * 服务标识符 @@ -26,8 +26,8 @@ public class ThingModelService { * "sync"、"async" */ private String callType; - private List inputData; - private List outputData; + private List inputData; + private List outputData; private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java new file mode 100644 index 000000000..9192fc28d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; + +import lombok.Data; + +@Data +public class ThinkModelArgument { + + private String identifier; + private String name; + private ThinkModelDataSpecs dataType; + /** + * 用于区分输入或输出参数,"input" 或 "output" + */ + private String direction; + private String description; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java similarity index 79% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java index 3be26e296..5f3e2e8b4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelArrayDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @@ -14,7 +14,7 @@ import java.util.List; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThingModelArrayDataSpecs extends ThingModelDataSpecs { +public class ThinkModelArrayDataSpecs extends ThinkModelDataSpecs { /** * 数组中的元素个数。 @@ -28,7 +28,7 @@ public class ThingModelArrayDataSpecs extends ThingModelDataSpecs { * 数据类型(childDataType)为列表型 struct 的数据规范存储在 dataSpecsList 中。 * 此时 struct 取值范围为:int、float、double、text、date、enum、bool */ - private List dataSpecsList; + private List dataSpecsList; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelBoolOrEnumDataSpecs.java similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelBoolOrEnumDataSpecs.java index e2ab9bdbb..8a44b584c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelBoolOrEnumDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelBoolOrEnumDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @@ -14,7 +14,7 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThingModelBoolOrEnumDataSpecs extends ThingModelDataSpecs { +public class ThinkModelBoolOrEnumDataSpecs extends ThinkModelDataSpecs { /** * 枚举项的名称。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDataSpecs.java similarity index 50% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDataSpecs.java index 32090f64b..2d0174765 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDataSpecs.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Data; /** - * 抽象类 ThingModelDataSpecs + * 抽象类 ThinkModelDataSpecs * * 用于表示物模型数据的通用类型,根据具体的 "dataType" 字段动态映射到对应的子类。 * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 @@ -15,17 +15,17 @@ import lombok.Data; @Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "dataType", visible = true) @JsonSubTypes({ - @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "int"), - @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "float"), - @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "double"), - @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "text"), - @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "date"), - @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "bool"), - @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "enum"), - @JsonSubTypes.Type(value = ThingModelArrayDataSpecs.class, name = "array"), - @JsonSubTypes.Type(value = ThingModelStructDataSpecs.class, name = "struct") + @JsonSubTypes.Type(value = ThinkModelNumericDataSpec.class, name = "int"), + @JsonSubTypes.Type(value = ThinkModelNumericDataSpec.class, name = "float"), + @JsonSubTypes.Type(value = ThinkModelNumericDataSpec.class, name = "double"), + @JsonSubTypes.Type(value = ThinkModelDateOrTextDataSpecs.class, name = "text"), + @JsonSubTypes.Type(value = ThinkModelDateOrTextDataSpecs.class, name = "date"), + @JsonSubTypes.Type(value = ThinkModelBoolOrEnumDataSpecs.class, name = "bool"), + @JsonSubTypes.Type(value = ThinkModelBoolOrEnumDataSpecs.class, name = "enum"), + @JsonSubTypes.Type(value = ThinkModelArrayDataSpecs.class, name = "array"), + @JsonSubTypes.Type(value = ThinkModelStructDataSpecs.class, name = "struct") }) -public abstract class ThingModelDataSpecs { +public abstract class ThinkModelDataSpecs { /** * 数据类型 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDateOrTextDataSpecs.java similarity index 81% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDateOrTextDataSpecs.java index 4ce7d2dee..640316b47 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelDateOrTextDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDateOrTextDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @@ -14,7 +14,7 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs { +public class ThinkModelDateOrTextDataSpecs extends ThinkModelDataSpecs { /** * 数据长度,单位为字节。取值不能超过 2048。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelNumericDataSpec.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelNumericDataSpec.java index 391cbf90a..714b57bd6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelNumericDataSpec.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelNumericDataSpec.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @@ -14,7 +14,7 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThingModelNumericDataSpec extends ThingModelDataSpecs { +public class ThinkModelNumericDataSpec extends ThinkModelDataSpecs { /** * 最大值,需转为字符串类型。值必须与 dataType 类型一致。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelStructDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelStructDataSpecs.java similarity index 74% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelStructDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelStructDataSpecs.java index 04c38ed28..8cbb9afe5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/thingmodel/dataType/ThingModelStructDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelStructDataSpecs.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelAccessModeEnum; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import lombok.EqualsAndHashCode; @@ -15,7 +15,7 @@ import java.util.List; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThingModelStructDataSpecs extends ThingModelDataSpecs { +public class ThinkModelStructDataSpecs extends ThinkModelDataSpecs { /** * 属性标识符 @@ -31,7 +31,7 @@ public class ThingModelStructDataSpecs extends ThingModelDataSpecs { private String description; /** * 云端可以对该属性进行的操作类型 - * 关联枚举 {@link IotProductThingModelAccessModeEnum} + * 关联枚举 {@link IotProductThinkModelAccessModeEnum} */ private String accessMode; /** @@ -48,11 +48,11 @@ public class ThingModelStructDataSpecs extends ThingModelDataSpecs { /** * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 */ - private ThingModelDataSpecs dataSpecs; + private ThinkModelDataSpecs dataSpecs; /** * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 */ - private List dataSpecsList; + private List dataSpecsList; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelPageReqVO.java similarity index 76% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelPageReqVO.java index 31c5ba1d9..afb412228 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelPageReqVO.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -13,7 +13,7 @@ import lombok.ToString; @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class IotProductThingModelPageReqVO extends PageParam { +public class IotProductThinkModelPageReqVO extends PageParam { @Schema(description = "功能标识") private String identifier; @@ -22,7 +22,7 @@ public class IotProductThingModelPageReqVO extends PageParam { private String name; @Schema(description = "功能类型", example = "1") - @InEnum(IotProductThingModelTypeEnum.class) + @InEnum(IotProductThinkModelTypeEnum.class) private Integer type; @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelRespVO.java similarity index 75% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelRespVO.java index 83c51fb59..a79cd2677 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelRespVO.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -13,7 +13,7 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - IoT 产品物模型 Response VO") @Data @ExcelIgnoreUnannotated -public class IotProductThingModelRespVO { +public class IotProductThinkModelRespVO { @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") @ExcelProperty("产品ID") @@ -39,13 +39,13 @@ public class IotProductThingModelRespVO { private Integer type; @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) - private ThingModelProperty property; + private ThinkModelProperty property; @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED) - private ThingModelEvent event; + private ThinkModelEvent event; @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED) - private ThingModelService service; + private ThinkModelService service; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelSaveReqVO.java similarity index 70% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelSaveReqVO.java index e230c3918..3cce60427 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/productthingmodel/vo/IotProductThingModelSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelSaveReqVO.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -12,7 +12,7 @@ import lombok.Data; @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") @Data -public class IotProductThingModelSaveReqVO { +public class IotProductThinkModelSaveReqVO { @Schema(description = "编号", example = "1") private Long id; @@ -38,16 +38,16 @@ public class IotProductThingModelSaveReqVO { @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "功能类型不能为空") - @InEnum(IotProductThingModelTypeEnum.class) + @InEnum(IotProductThinkModelTypeEnum.class) private Integer type; @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) - private ThingModelProperty property; + private ThinkModelProperty property; @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED) - private ThingModelService service; + private ThinkModelService service; @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED) - private ThingModelEvent event; + private ThinkModelEvent event; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java index d8f6e4704..22d5dda6d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java @@ -12,7 +12,7 @@ public interface IotDeviceDataConvert { // default List convert(Map deviceData, IotDeviceDO device){ // List list = new ArrayList<>(); // deviceData.forEach((identifier, value) -> { -//// ThingModelProperty property = ThingModelService.INSTANCE.getProperty(device.getProductId(), identifier); +//// ThinkModelProperty property = ThinkModelService.INSTANCE.getProperty(device.getProductId(), identifier); //// if (Objects.isNull(property)) { //// return; //// } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/productthingmodel/IotProductThingModelConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/productthingmodel/IotProductThingModelConvert.java deleted file mode 100644 index 1d57982d5..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/productthingmodel/IotProductThingModelConvert.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.iot.convert.productthingmodel; - -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.mapstruct.factory.Mappers; - -import java.util.List; -import java.util.Objects; - -@Mapper -public interface IotProductThingModelConvert { - - IotProductThingModelConvert INSTANCE = Mappers.getMapper(IotProductThingModelConvert.class); - - // 将 SaveReqVO 转换为 DO - @Mapping(target = "property", expression = "java(convertToProperty(bean))") - @Mapping(target = "event", expression = "java(convertToEvent(bean))") - @Mapping(target = "service", expression = "java(convertToService(bean))") - IotProductThingModelDO convert(IotProductThingModelSaveReqVO bean); - - // 将 DO 转换为 RespVO - @Mapping(target = "property", source = "property") - @Mapping(target = "event", source = "event") - @Mapping(target = "service", source = "service") - IotProductThingModelRespVO convert(IotProductThingModelDO bean); - - // 批量转换 - List convertList(List list); - - @Named("convertToProperty") - default ThingModelProperty convertToProperty(IotProductThingModelSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { - return bean.getProperty(); - } - return null; - } - - @Named("convertToEvent") - default ThingModelEvent convertToEvent(IotProductThingModelSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.EVENT.getType())) { - return bean.getEvent(); - } - return null; - } - - @Named("convertToService") - default ThingModelService convertToService(IotProductThingModelSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.SERVICE.getType())) { - return bean.getService(); - } - return null; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodel/IotProductThinkModelConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodel/IotProductThinkModelConvert.java new file mode 100644 index 000000000..bb5c22b35 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodel/IotProductThinkModelConvert.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.iot.convert.thinkmodel; + +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Objects; + +@Mapper +public interface IotProductThinkModelConvert { + + IotProductThinkModelConvert INSTANCE = Mappers.getMapper(IotProductThinkModelConvert.class); + + // 将 SaveReqVO 转换为 DO + @Mapping(target = "property", expression = "java(convertToProperty(bean))") + @Mapping(target = "event", expression = "java(convertToEvent(bean))") + @Mapping(target = "service", expression = "java(convertToService(bean))") + IotProductThinkModelDO convert(IotProductThinkModelSaveReqVO bean); + + // 将 DO 转换为 RespVO + @Mapping(target = "property", source = "property") + @Mapping(target = "event", source = "event") + @Mapping(target = "service", source = "service") + IotProductThinkModelRespVO convert(IotProductThinkModelDO bean); + + // 批量转换 + List convertList(List list); + + @Named("convertToProperty") + default ThinkModelProperty convertToProperty(IotProductThinkModelSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotProductThinkModelTypeEnum.PROPERTY.getType())) { + return bean.getProperty(); + } + return null; + } + + @Named("convertToEvent") + default ThinkModelEvent convertToEvent(IotProductThinkModelSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotProductThinkModelTypeEnum.EVENT.getType())) { + return bean.getEvent(); + } + return null; + } + + @Named("convertToService") + default ThinkModelService convertToService(IotProductThinkModelSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotProductThinkModelTypeEnum.SERVICE.getType())) { + return bean.getService(); + } + return null; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java index 73e7ee34d..8ff9b1352 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -30,7 +30,7 @@ public class IotDeviceDataDO { /** * 物模型编号 *

- * 关联 {@link IotProductThingModelDO#getId()} + * 关联 {@link IotProductThinkModelDO#getId()} */ private Long thinkModelFunctionId; @@ -51,21 +51,21 @@ public class IotDeviceDataDO { /** * 属性标识符 *

- * 关联 {@link IotProductThingModelDO#getIdentifier()} + * 关联 {@link IotProductThinkModelDO#getIdentifier()} */ private String identifier; /** * 属性名称 *

- * 关联 {@link IotProductThingModelDO#getName()} + * 关联 {@link IotProductThinkModelDO#getName()} */ private String name; /** * 数据类型 *

- * 关联 {@link IotProductThingModelDO#getProperty()#getDataType()} + * 关联 {@link IotProductThinkModelDO#getProperty()#getDataType()} */ private String dataType; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index 6dfe54c07..065d9bfed 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -1,8 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelRespVO; import java.util.HashMap; import java.util.List; @@ -34,10 +33,10 @@ public class FieldParser { * @param property 物模型属性 * @return TdField对象 */ - public static TdFieldDO parse(ThingModelProperty property) { + public static TdFieldDO parse(ThinkModelProperty property) { String fieldName = property.getIdentifier().toLowerCase(); //// TODO @puhui999: 需要重构 - //ThingModelDataSpecs type = property.getDataType(); + //ThinkModelDataSpecs type = property.getDataType(); // //// 将物模型字段类型映射为td字段类型 //String fType = TYPE_MAPPING.get(type.getDataType().toUpperCase()); @@ -57,7 +56,7 @@ public class FieldParser { * @param thingModel 物模型响应对象 * @return 字段列表 */ - public static List parse(ThingModelRespVO thingModel) { + public static List parse(ThinkModelRespVO thingModel) { return thingModel.getModel().getProperties().stream() .map(FieldParser::parse) .collect(Collectors.toList()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessage.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessage.java index d5009dc24..22cf9e2ef 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessage.java @@ -15,7 +15,7 @@ import java.util.Map; @NoArgsConstructor @AllArgsConstructor @Builder -public class ThingModelMessage { +public class ThinkModelMessage { /** * 消息ID diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodel/IotProductThinkModelDO.java similarity index 66% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodel/IotProductThinkModelDO.java index 1cececc0c..76b2a63e7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/productthingmodel/IotProductThingModelDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodel/IotProductThinkModelDO.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel; +package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -19,17 +19,17 @@ import lombok.NoArgsConstructor; /** * IoT 产品物模型功能 DO *

- * 每个 {@link IotProductDO} 和 {@link IotProductThingModelDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 + * 每个 {@link IotProductDO} 和 {@link IotProductThinkModelDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 * * @author 芋道源码 */ -@TableName(value = "iot_product_thing_model", autoResultMap = true) -@KeySequence("iot_product_thing_model_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName(value = "iot_product_think_model", autoResultMap = true) +@KeySequence("iot_product_think_model_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor @AllArgsConstructor -public class IotProductThingModelDO extends BaseDO { +public class IotProductThinkModelDO extends BaseDO { /** * 物模型功能编号 @@ -66,7 +66,7 @@ public class IotProductThingModelDO extends BaseDO { /** * 功能类型 *

- * 枚举 {@link IotProductThingModelTypeEnum} + * 枚举 {@link IotProductThinkModelTypeEnum} */ private Integer type; @@ -74,18 +74,18 @@ public class IotProductThingModelDO extends BaseDO { * 属性 */ @TableField(typeHandler = JacksonTypeHandler.class) - private ThingModelProperty property; + private ThinkModelProperty property; /** * 事件 */ @TableField(typeHandler = JacksonTypeHandler.class) - private ThingModelEvent event; + private ThinkModelEvent event; /** * 服务 */ @TableField(typeHandler = JacksonTypeHandler.class) - private ThingModelService service; + private ThinkModelService service; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodel/IotProductThinkModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodel/IotProductThinkModelMapper.java new file mode 100644 index 000000000..de76aa633 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodel/IotProductThinkModelMapper.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodel; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * IoT 产品物模型 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotProductThinkModelMapper extends BaseMapperX { + + default PageResult selectPage(IotProductThinkModelPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotProductThinkModelDO::getIdentifier, reqVO.getIdentifier()) + .likeIfPresent(IotProductThinkModelDO::getName, reqVO.getName()) + .eqIfPresent(IotProductThinkModelDO::getType, reqVO.getType()) + .eqIfPresent(IotProductThinkModelDO::getProductId, reqVO.getProductId()) + .notIn(IotProductThinkModelDO::getIdentifier, "get", "set", "post") + .orderByDesc(IotProductThinkModelDO::getId)); + } + + default IotProductThinkModelDO selectByProductIdAndIdentifier(Long productId, String identifier) { + return selectOne(IotProductThinkModelDO::getProductId, productId, + IotProductThinkModelDO::getIdentifier, identifier); + } + + default List selectListByProductId(Long productId) { + return selectList(IotProductThinkModelDO::getProductId, productId); + } + + default List selectListByProductIdAndType(Long productId, Integer type) { + return selectList(IotProductThinkModelDO::getProductId, productId, + IotProductThinkModelDO::getType, type); + } + + default List selectListByProductIdAndIdentifiersAndTypes(Long productId, + List identifiers, + List types) { + return selectList(new LambdaQueryWrapperX() + .eq(IotProductThinkModelDO::getProductId, productId) + .in(IotProductThinkModelDO::getIdentifier, identifiers) + .in(IotProductThinkModelDO::getType, types)); + } + + default IotProductThinkModelDO selectByProductIdAndName(Long productId, String name) { + return selectOne(IotProductThinkModelDO::getProductId, productId, + IotProductThinkModelDO::getName, name); + } + + default List selectListByProductKey(String productKey) { + return selectList(IotProductThinkModelDO::getProductKey, productKey); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotProductThingModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotProductThingModelMapper.java deleted file mode 100644 index 6ec0d4846..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotProductThingModelMapper.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * IoT 产品物模型 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface IotProductThingModelMapper extends BaseMapperX { - - default PageResult selectPage(IotProductThingModelPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(IotProductThingModelDO::getIdentifier, reqVO.getIdentifier()) - .likeIfPresent(IotProductThingModelDO::getName, reqVO.getName()) - .eqIfPresent(IotProductThingModelDO::getType, reqVO.getType()) - .eqIfPresent(IotProductThingModelDO::getProductId, reqVO.getProductId()) - .notIn(IotProductThingModelDO::getIdentifier, "get", "set", "post") - .orderByDesc(IotProductThingModelDO::getId)); - } - - default IotProductThingModelDO selectByProductIdAndIdentifier(Long productId, String identifier) { - return selectOne(IotProductThingModelDO::getProductId, productId, - IotProductThingModelDO::getIdentifier, identifier); - } - - default List selectListByProductId(Long productId) { - return selectList(IotProductThingModelDO::getProductId, productId); - } - - default List selectListByProductIdAndType(Long productId, Integer type) { - return selectList(IotProductThingModelDO::getProductId, productId, - IotProductThingModelDO::getType, type); - } - - default List selectListByProductIdAndIdentifiersAndTypes(Long productId, - List identifiers, - List types) { - return selectList(new LambdaQueryWrapperX() - .eq(IotProductThingModelDO::getProductId, productId) - .in(IotProductThingModelDO::getIdentifier, identifiers) - .in(IotProductThingModelDO::getType, types)); - } - - default IotProductThingModelDO selectByProductIdAndName(Long productId, String name) { - return selectOne(IotProductThingModelDO::getProductId, productId, - IotProductThingModelDO::getName, name); - } - - default List selectListByProductKey(String productKey) { - return selectList(IotProductThingModelDO::getProductKey, productKey); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 6dbcf0ab7..ed2e32f2d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -7,15 +7,15 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; -import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; -import cn.iocoder.yudao.module.iot.service.productthingmodel.IotProductThingModelService; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; +import cn.iocoder.yudao.module.iot.service.tdengine.IotThinkModelMessageService; +import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; @@ -38,9 +38,9 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { @Resource private IotDeviceService deviceService; @Resource - private IotThingModelMessageService thingModelMessageService; + private IotThinkModelMessageService thingModelMessageService; @Resource - private IotProductThingModelService thinkModelFunctionService; + private IotProductThinkModelService thinkModelFunctionService; @Resource private TdEngineDMLMapper tdEngineDMLMapper; @@ -54,7 +54,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { // 2. 解析消息,保存数据 JSONObject jsonObject = new JSONObject(message); log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", productKey, deviceName, jsonObject); - ThingModelMessage thingModelMessage = ThingModelMessage.builder() + ThinkModelMessage thingModelMessage = ThinkModelMessage.builder() .id(jsonObject.getStr("id")) .sys(jsonObject.get("sys")) .method(jsonObject.getStr("method")) @@ -64,7 +64,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { .deviceName(deviceName) .deviceKey(device.getDeviceKey()) .build(); - thingModelMessageService.saveThingModelMessage(device, thingModelMessage); + thingModelMessageService.saveThinkModelMessage(device, thingModelMessage); } @Override @@ -73,9 +73,9 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { // 1. 获取设备信息 IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); // 2. 获取设备属性最新数据 - List thinkModelFunctionList = thinkModelFunctionService.getProductThingModelListByProductKey(device.getProductKey()); + List thinkModelFunctionList = thinkModelFunctionService.getProductThinkModelListByProductKey(device.getProductKey()); thinkModelFunctionList = thinkModelFunctionList.stream() - .filter(function -> IotProductThingModelTypeEnum.PROPERTY.getType() + .filter(function -> IotProductThinkModelTypeEnum.PROPERTY.getType() .equals(function.getType())).toList(); // 3. 过滤标识符和属性名称 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index dabc9ad4a..b26c2c123 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.service.productthingmodel.IotProductThingModelService; +import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; @@ -34,7 +34,7 @@ public class IotProductServiceImpl implements IotProductService { @Resource @Lazy - private IotProductThingModelService thinkModelFunctionService; + private IotProductThinkModelService thinkModelFunctionService; @Override public Long createProduct(IotProductSaveReqVO createReqVO) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java index e66278ccd..bf76ae1c3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import java.util.List; @@ -14,5 +14,5 @@ public interface IotSuperTableService { /** * 创建超级表数据模型 */ - void createSuperTableDataModel(IotProductDO product, List functionList); + void createSuperTableDataModel(IotProductDO product, List functionList); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java index 84e98296e..59fa9d0f3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java @@ -2,15 +2,15 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -33,8 +33,8 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { private String url; @Override - public void createSuperTableDataModel(IotProductDO product, List functionList) { - ThingModelRespVO thingModel = buildThingModel(product, functionList); + public void createSuperTableDataModel(IotProductDO product, List functionList) { + ThinkModelRespVO thingModel = buildThinkModel(product, functionList); if (thingModel.getModel() == null || CollUtil.isEmpty(thingModel.getModel().getProperties())) { log.warn("物模型属性列表为空,不创建超级表"); @@ -56,7 +56,7 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 创建超级表 */ - private void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { + private void createSuperTable(ThinkModelRespVO thingModel, Integer deviceType) { // 解析物模型,获取字段列表 List schemaFields = new ArrayList<>(); schemaFields.add(TdFieldDO.builder() @@ -84,7 +84,7 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 更新超级表 */ - private void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { + private void updateSuperTable(ThinkModelRespVO thingModel, Integer deviceType) { String superTableName = getSuperTableName(deviceType, thingModel.getProductKey()); try { List oldFields = getTableFields(superTableName); @@ -210,18 +210,18 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 构建物模型 */ - private ThingModelRespVO buildThingModel(IotProductDO product, List functionList) { - ThingModelRespVO thingModel = new ThingModelRespVO(); + private ThinkModelRespVO buildThinkModel(IotProductDO product, List functionList) { + ThinkModelRespVO thingModel = new ThinkModelRespVO(); thingModel.setId(product.getId()); thingModel.setProductKey(product.getProductKey()); - List properties = functionList.stream() - .filter(function -> IotProductThingModelTypeEnum.PROPERTY.equals( - IotProductThingModelTypeEnum.valueOfType(function.getType()))) - .map(this::buildThingModelProperty) + List properties = functionList.stream() + .filter(function -> IotProductThinkModelTypeEnum.PROPERTY.equals( + IotProductThinkModelTypeEnum.valueOfType(function.getType()))) + .map(this::buildThinkModelProperty) .collect(Collectors.toList()); - ThingModelRespVO.Model model = new ThingModelRespVO.Model(); + ThinkModelRespVO.Model model = new ThinkModelRespVO.Model(); model.setProperties(properties); thingModel.setModel(model); @@ -231,8 +231,8 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 构建物模型属性 */ - private ThingModelProperty buildThingModelProperty(IotProductThingModelDO function) { - ThingModelProperty property = BeanUtil.copyProperties(function, ThingModelProperty.class); + private ThinkModelProperty buildThinkModelProperty(IotProductThinkModelDO function) { + ThinkModelProperty property = BeanUtil.copyProperties(function, ThinkModelProperty.class); property.setDataType(function.getProperty().getDataType()); return property; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java similarity index 66% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java index ffcb3063c..67ee2b99a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java @@ -1,12 +1,12 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; /** * 物模型消息 Service */ -public interface IotThingModelMessageService { +public interface IotThinkModelMessageService { /** * 保存物模型消息 @@ -14,5 +14,5 @@ public interface IotThingModelMessageService { * @param device 设备 * @param thingModelMessage 物模型消息 */ - void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); + void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java similarity index 86% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java index fdb0ca9e4..eaaa3efeb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java @@ -10,16 +10,16 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.productthingmodel.IotProductThingModelService; +import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -33,7 +33,7 @@ import java.util.stream.Collectors; */ @Slf4j @Service -public class IotThingModelMessageServiceImpl implements IotThingModelMessageService { +public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageService { private static final String TAG_NOTE = "TAG"; private static final String NOTE = "note"; @@ -47,7 +47,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ private String url; @Resource - private IotProductThingModelService iotProductThingModelService; + private IotProductThinkModelService iotProductThinkModelService; @Resource private IotDeviceService iotDeviceService; @Resource @@ -61,7 +61,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 @Override @TenantIgnore - public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) { + public void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage) { // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); @@ -71,7 +71,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 Map params = thingModelMessage.dataToMap(); - List functionList = getValidFunctionList(thingModelMessage.getProductKey()); + List functionList = getValidFunctionList(thingModelMessage.getProductKey()); if (functionList.isEmpty()) { return; } @@ -90,21 +90,21 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ .build()); } - private List getValidFunctionList(String productKey) { - return iotProductThingModelService - .getProductThingModelListByProductKey(productKey) + private List getValidFunctionList(String productKey) { + return iotProductThinkModelService + .getProductThinkModelListByProductKey(productKey) .stream() - .filter(function -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(function.getType())) + .filter(function -> IotProductThinkModelTypeEnum.PROPERTY.getType().equals(function.getType())) .toList(); } - private List filterAndCollectValidFields(Map params, List functionList, IotDeviceDO device, Long time) { + private List filterAndCollectValidFields(Map params, List functionList, IotDeviceDO device, Long time) { // 1. 获取属性标识符集合 - Set propertyIdentifiers = CollectionUtils.convertSet(functionList, IotProductThingModelDO::getIdentifier); + Set propertyIdentifiers = CollectionUtils.convertSet(functionList, IotProductThinkModelDO::getIdentifier); // 2. 构建属性标识符和属性的映射 - Map functionMap = functionList.stream() - .collect(Collectors.toMap(IotProductThingModelDO::getIdentifier, function -> function)); + Map functionMap = functionList.stream() + .collect(Collectors.toMap(IotProductThinkModelDO::getIdentifier, function -> function)); // 3. 过滤并收集有效的属性字段 List schemaFieldValues = new ArrayList<>(); @@ -124,22 +124,22 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * 缓存设备属性 * * @param device 设备信息 - * @param iotProductThingModelDO 物模型属性 + * @param iotProductThinkModelDO 物模型属性 * @param val 属性值 * @param time 时间 */ - private void setDeviceDataCache(IotDeviceDO device, IotProductThingModelDO iotProductThingModelDO, Object val, Long time) { + private void setDeviceDataCache(IotDeviceDO device, IotProductThinkModelDO iotProductThinkModelDO, Object val, Long time) { // TODO @puhui999: 需要重构 IotDeviceDataDO deviceData = IotDeviceDataDO.builder() .productKey(device.getProductKey()) .deviceName(device.getDeviceName()) - .identifier(iotProductThingModelDO.getIdentifier()) + .identifier(iotProductThinkModelDO.getIdentifier()) .value(val != null ? val.toString() : null) .updateTime(DateUtil.toLocalDateTime(new Date(time))) .deviceId(device.getId()) - .thinkModelFunctionId(iotProductThingModelDO.getId()) - .name(iotProductThingModelDO.getName()) - //.dataType(iotProductThingModelDO.getProperty().getDataType().getDataType()) + .thinkModelFunctionId(iotProductThinkModelDO.getId()) + .name(iotProductThinkModelDO.getName()) + //.dataType(iotProductThinkModelDO.getProperty().getDataType().getDataType()) .build(); deviceDataRedisDAO.set(deviceData); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelService.java similarity index 58% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelService.java index 413b6b014..34e7fc149 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelService.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.module.iot.service.productthingmodel; +package cn.iocoder.yudao.module.iot.service.thinkmodel; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import jakarta.validation.Valid; import java.util.List; @@ -13,7 +13,7 @@ import java.util.List; * * @author 芋道源码 */ -public interface IotProductThingModelService { +public interface IotProductThinkModelService { /** * 创建产品物模型 @@ -21,21 +21,21 @@ public interface IotProductThingModelService { * @param createReqVO 创建信息 * @return 编号 */ - Long createProductThingModel(@Valid IotProductThingModelSaveReqVO createReqVO); + Long createProductThinkModel(@Valid IotProductThinkModelSaveReqVO createReqVO); /** * 更新产品物模型 * * @param updateReqVO 更新信息 */ - void updateProductThingModel(@Valid IotProductThingModelSaveReqVO updateReqVO); + void updateProductThinkModel(@Valid IotProductThinkModelSaveReqVO updateReqVO); /** * 删除产品物模型 * * @param id 编号 */ - void deleteProductThingModel(Long id); + void deleteProductThinkModel(Long id); /** * 获得产品物模型 @@ -43,7 +43,7 @@ public interface IotProductThingModelService { * @param id 编号 * @return 产品物模型 */ - IotProductThingModelDO getProductThingModel(Long id); + IotProductThinkModelDO getProductThinkModel(Long id); /** * 获得产品物模型列表 @@ -51,7 +51,7 @@ public interface IotProductThingModelService { * @param productId 产品编号 * @return 产品物模型列表 */ - List getProductThingModelListByProductId(Long productId); + List getProductThinkModelListByProductId(Long productId); /** * 获得产品物模型分页 @@ -59,7 +59,7 @@ public interface IotProductThingModelService { * @param pageReqVO 分页查询 * @return 产品物模型分页 */ - PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO); + PageResult getProductThinkModelPage(IotProductThinkModelPageReqVO pageReqVO); /** * 创建超级表数据模型 @@ -74,6 +74,6 @@ public interface IotProductThingModelService { * @param productKey 产品 Key * @return 产品物模型列表 */ - List getProductThingModelListByProductKey(String productKey); + List getProductThinkModelListByProductKey(String productKey); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java similarity index 66% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java index f5efd37bc..862d8b95c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/productthingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java @@ -1,23 +1,23 @@ -package cn.iocoder.yudao.module.iot.service.productthingmodel; +package cn.iocoder.yudao.module.iot.service.thinkmodel; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArgument; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelArrayDataSpecs; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.thingmodel.dataType.ThingModelDateOrTextDataSpecs; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.productthingmodel.vo.IotProductThingModelSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.productthingmodel.IotProductThingModelConvert; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelArrayDataSpecs; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelDateOrTextDataSpecs; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.thinkmodel.IotProductThinkModelConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.productthingmodel.IotProductThingModelDO; -import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotProductThingModelMapper; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodel.IotProductThinkModelMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotSuperTableService; import jakarta.annotation.Resource; @@ -41,10 +41,10 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @Service @Validated @Slf4j -public class IotProductThingModelServiceImpl implements IotProductThingModelService { +public class IotProductThinkModelServiceImpl implements IotProductThinkModelService { @Resource - private IotProductThingModelMapper productThingModelMapper; + private IotProductThinkModelMapper productThinkModelMapper; @Resource private IotProductService productService; @@ -53,7 +53,7 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @Override @Transactional(rollbackFor = Exception.class) - public Long createProductThingModel(IotProductThingModelSaveReqVO createReqVO) { + public Long createProductThinkModel(IotProductThinkModelSaveReqVO createReqVO) { // 1. 校验功能标识符在同一产品下是否唯一 validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); @@ -67,11 +67,11 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ validateProductStatus(createReqVO.getProductId()); // 5. 插入数据库 - IotProductThingModelDO function = IotProductThingModelConvert.INSTANCE.convert(createReqVO); - productThingModelMapper.insert(function); + IotProductThinkModelDO function = IotProductThinkModelConvert.INSTANCE.convert(createReqVO); + productThinkModelMapper.insert(function); // 6. 如果创建的是属性,需要更新默认的事件和服务 - if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(createReqVO.getType(), IotProductThinkModelTypeEnum.PROPERTY.getType())) { //createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } return function.getId(); @@ -95,14 +95,14 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } private void validateNameUnique(Long productId, String name) { - IotProductThingModelDO function = productThingModelMapper.selectByProductIdAndName(productId, name); + IotProductThinkModelDO function = productThinkModelMapper.selectByProductIdAndName(productId, name); if (function != null) { throw exception(THINK_MODEL_FUNCTION_NAME_EXISTS); } } private void validateIdentifierUnique(Long productId, String identifier) { - IotProductThingModelDO function = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); + IotProductThinkModelDO function = productThinkModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (function != null) { throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS); } @@ -110,9 +110,9 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @Override @Transactional(rollbackFor = Exception.class) - public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { + public void updateProductThinkModel(IotProductThinkModelSaveReqVO updateReqVO) { // 1. 校验功能是否存在 - validateproductThingModelMapperExists(updateReqVO.getId()); + validateproductThinkModelMapperExists(updateReqVO.getId()); // 2. 校验功能标识符是否唯一 validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); @@ -121,17 +121,17 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ validateProductStatus(updateReqVO.getProductId()); // 4. 更新数据库 - IotProductThingModelDO productThingModelDO = IotProductThingModelConvert.INSTANCE.convert(updateReqVO); - productThingModelMapper.updateById(productThingModelDO); + IotProductThinkModelDO productThinkModelDO = IotProductThinkModelConvert.INSTANCE.convert(updateReqVO); + productThinkModelMapper.updateById(productThinkModelDO); // 5. 如果更新的是属性,需要更新默认的事件和服务 - if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(updateReqVO.getType(), IotProductThinkModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } } private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { - IotProductThingModelDO function = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); + IotProductThinkModelDO function = productThinkModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (function != null && ObjectUtil.notEqual(function.getId(), id)) { throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS); } @@ -139,9 +139,9 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @Override @Transactional(rollbackFor = Exception.class) - public void deleteProductThingModel(Long id) { + public void deleteProductThinkModel(Long id) { // 1. 校验功能是否存在 - IotProductThingModelDO functionDO = productThingModelMapper.selectById(id); + IotProductThinkModelDO functionDO = productThinkModelMapper.selectById(id); if (functionDO == null) { throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); } @@ -150,10 +150,10 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ validateProductStatus(functionDO.getProductId()); // 2. 删除功能 - productThingModelMapper.deleteById(id); + productThinkModelMapper.deleteById(id); // 3. 如果删除的是属性,需要更新默认的事件和服务 - if (Objects.equals(functionDO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(functionDO.getType(), IotProductThinkModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey()); } } @@ -163,25 +163,25 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ * * @param id 功能编号 */ - private void validateproductThingModelMapperExists(Long id) { - if (productThingModelMapper.selectById(id) == null) { + private void validateproductThinkModelMapperExists(Long id) { + if (productThinkModelMapper.selectById(id) == null) { throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); } } @Override - public IotProductThingModelDO getProductThingModel(Long id) { - return productThingModelMapper.selectById(id); + public IotProductThinkModelDO getProductThinkModel(Long id) { + return productThinkModelMapper.selectById(id); } @Override - public List getProductThingModelListByProductId(Long productId) { - return productThingModelMapper.selectListByProductId(productId); + public List getProductThinkModelListByProductId(Long productId) { + return productThinkModelMapper.selectListByProductId(productId); } @Override - public PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) { - return productThingModelMapper.selectPage(pageReqVO); + public PageResult getProductThinkModelPage(IotProductThinkModelPageReqVO pageReqVO) { + return productThinkModelMapper.selectPage(pageReqVO); } @Override @@ -190,15 +190,15 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ IotProductDO product = productService.getProduct(productId); // 2. 查询产品的物模型功能列表 - List functionList = productThingModelMapper.selectListByProductId(productId); + List functionList = productThinkModelMapper.selectListByProductId(productId); // 3. 生成 TDengine 的数据模型 dbStructureDataService.createSuperTableDataModel(product, functionList); } @Override - public List getProductThingModelListByProductKey(String productKey) { - return productThingModelMapper.selectListByProductKey(productKey); + public List getProductThinkModelListByProductKey(String productKey) { + return productThinkModelMapper.selectListByProductKey(productKey); } // TODO @puhui999: 需要重构 @@ -207,82 +207,82 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ */ public void createDefaultEventsAndServices(Long productId, String productKey) { // 1. 获取当前属性列表 - List propertyList = productThingModelMapper - .selectListByProductIdAndType(productId, IotProductThingModelTypeEnum.PROPERTY.getType()); + List propertyList = productThinkModelMapper + .selectListByProductIdAndType(productId, IotProductThinkModelTypeEnum.PROPERTY.getType()); // 2. 生成新的事件和服务列表 - List newFunctionList = new ArrayList<>(); + List newFunctionList = new ArrayList<>(); // 生成属性上报事件 - ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); + ThinkModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); if (propertyPostEvent != null) { - IotProductThingModelDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent); + IotProductThinkModelDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent); newFunctionList.add(eventFunction); } // 生成属性设置服务 - ThingModelService propertySetService = generatePropertySetService(propertyList); + ThinkModelService propertySetService = generatePropertySetService(propertyList); if (propertySetService != null) { - IotProductThingModelDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService); + IotProductThinkModelDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService); newFunctionList.add(setServiceFunction); } // 生成属性获取服务 - ThingModelService propertyGetService = generatePropertyGetService(propertyList); + ThinkModelService propertyGetService = generatePropertyGetService(propertyList); if (propertyGetService != null) { - IotProductThingModelDO getServiceFunction = buildServiceFunctionDO(productId, productKey, propertyGetService); + IotProductThinkModelDO getServiceFunction = buildServiceFunctionDO(productId, productKey, propertyGetService); newFunctionList.add(getServiceFunction); } // 3. 获取数据库中的默认的旧事件和服务列表 - List oldFunctionList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( + List oldFunctionList = productThinkModelMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), - Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) + Arrays.asList(IotProductThinkModelTypeEnum.EVENT.getType(), IotProductThinkModelTypeEnum.SERVICE.getType()) ); // 3.1 使用 diffList 方法比较新旧列表 - List> diffResult = diffList(oldFunctionList, newFunctionList, + List> diffResult = diffList(oldFunctionList, newFunctionList, // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier()) && Objects.equals(oldFunc.getType(), newFunc.getType())); - List createList = diffResult.get(0); // 需要新增的 - List updateList = diffResult.get(1); // 需要更新的 - List deleteList = diffResult.get(2); // 需要删除的 + List createList = diffResult.get(0); // 需要新增的 + List updateList = diffResult.get(1); // 需要更新的 + List deleteList = diffResult.get(2); // 需要删除的 // 3.2 批量执行数据库操作 // 新增数据库中的新事件和服务列表 if (CollUtil.isNotEmpty(createList)) { - productThingModelMapper.insertBatch(createList); + productThinkModelMapper.insertBatch(createList); } // 更新数据库中的事件和服务列表 if (CollUtil.isNotEmpty(updateList)) { // 首先,为每个需要更新的对象设置其对应的 ID updateList.forEach(updateFunc -> { - IotProductThingModelDO oldFunc = findFunctionByIdentifierAndType( + IotProductThinkModelDO oldFunc = findFunctionByIdentifierAndType( oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType()); if (oldFunc != null) { updateFunc.setId(oldFunc.getId()); } }); // 过滤掉没有设置 ID 的对象 - List validUpdateList = updateList.stream() + List validUpdateList = updateList.stream() .filter(func -> func.getId() != null) .collect(Collectors.toList()); // 执行批量更新 if (CollUtil.isNotEmpty(validUpdateList)) { - productThingModelMapper.updateBatch(validUpdateList); + productThinkModelMapper.updateBatch(validUpdateList); } } // 删除数据库中的旧事件和服务列表 if (CollUtil.isNotEmpty(deleteList)) { - Set idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThingModelDO::getId); - productThingModelMapper.deleteByIds(idsToDelete); + Set idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThinkModelDO::getId); + productThinkModelMapper.deleteByIds(idsToDelete); } } /** * 根据标识符和类型查找功能对象 */ - private IotProductThingModelDO findFunctionByIdentifierAndType(List functionList, + private IotProductThinkModelDO findFunctionByIdentifierAndType(List functionList, String identifier, Integer type) { return CollUtil.findOne(functionList, func -> Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)); @@ -291,40 +291,40 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ /** * 构建事件功能对象 */ - private IotProductThingModelDO buildEventFunctionDO(Long productId, String productKey, ThingModelEvent event) { - return new IotProductThingModelDO() + private IotProductThinkModelDO buildEventFunctionDO(Long productId, String productKey, ThinkModelEvent event) { + return new IotProductThinkModelDO() .setProductId(productId) .setProductKey(productKey) .setIdentifier(event.getIdentifier()) .setName(event.getName()) .setDescription(event.getDescription()) - .setType(IotProductThingModelTypeEnum.EVENT.getType()) + .setType(IotProductThinkModelTypeEnum.EVENT.getType()) .setEvent(event); } /** * 构建服务功能对象 */ - private IotProductThingModelDO buildServiceFunctionDO(Long productId, String productKey, ThingModelService service) { - return new IotProductThingModelDO() + private IotProductThinkModelDO buildServiceFunctionDO(Long productId, String productKey, ThinkModelService service) { + return new IotProductThinkModelDO() .setProductId(productId) .setProductKey(productKey) .setIdentifier(service.getIdentifier()) .setName(service.getName()) .setDescription(service.getDescription()) - .setType(IotProductThingModelTypeEnum.SERVICE.getType()) + .setType(IotProductThinkModelTypeEnum.SERVICE.getType()) .setService(service); } /** * 生成属性上报事件 */ - private ThingModelEvent generatePropertyPostEvent(List propertyList) { + private ThinkModelEvent generatePropertyPostEvent(List propertyList) { if (CollUtil.isEmpty(propertyList)) { return null; } - ThingModelEvent event = new ThingModelEvent() + ThinkModelEvent event = new ThinkModelEvent() .setIdentifier("post") .setName("属性上报") .setType("info") @@ -332,11 +332,11 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ .setMethod("thing.event.property.post"); // 将属性列表转换为事件的输出参数 - List outputData = new ArrayList<>(); + List outputData = new ArrayList<>(); // TODO @puhui999: 需要重构 - for (IotProductThingModelDO functionDO : propertyList) { - ThingModelProperty property = functionDO.getProperty(); - ThingModelArgument arg = new ThingModelArgument() + for (IotProductThinkModelDO functionDO : propertyList) { + ThinkModelProperty property = functionDO.getProperty(); + ThinkModelArgument arg = new ThinkModelArgument() .setIdentifier(property.getIdentifier()) .setName(property.getName()) //.setDataType(property.getDataType()) @@ -351,17 +351,17 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ /** * 生成属性设置服务 */ - private ThingModelService generatePropertySetService(List propertyList) { + private ThinkModelService generatePropertySetService(List propertyList) { if (propertyList == null || propertyList.isEmpty()) { return null; } - List inputData = new ArrayList<>(); + List inputData = new ArrayList<>(); // TODO @puhui999: 需要重构 - for (IotProductThingModelDO functionDO : propertyList) { - ThingModelProperty property = functionDO.getProperty(); - //if (IotProductThingModelAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { - // ThingModelArgument arg = new ThingModelArgument() + for (IotProductThinkModelDO functionDO : propertyList) { + ThinkModelProperty property = functionDO.getProperty(); + //if (IotProductThinkModelAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotProductThinkModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { + // ThinkModelArgument arg = new ThinkModelArgument() // .setIdentifier(property.getIdentifier()) // .setName(property.getName()) // .setDataType(property.getDataType()) @@ -376,7 +376,7 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } // 属性设置服务一般不需要输出参数 - return new ThingModelService() + return new ThinkModelService() .setIdentifier("set") .setName("属性设置") .setCallType("async") @@ -390,17 +390,17 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ /** * 生成属性获取服务 */ - private ThingModelService generatePropertyGetService(List propertyList) { + private ThinkModelService generatePropertyGetService(List propertyList) { if (propertyList == null || propertyList.isEmpty()) { return null; } // TODO @puhui999: 需要重构 - List outputData = new ArrayList<>(); - for (IotProductThingModelDO functionDO : propertyList) { - ThingModelProperty property = functionDO.getProperty(); + List outputData = new ArrayList<>(); + for (IotProductThinkModelDO functionDO : propertyList) { + ThinkModelProperty property = functionDO.getProperty(); //if (ObjectUtils.equalsAny(property.getAccessMode(), - // IotProductThingModelAccessModeEnum.READ.getMode(), IotProductThingModelAccessModeEnum.READ_WRITE.getMode())) { - // ThingModelArgument arg = new ThingModelArgument() + // IotProductThinkModelAccessModeEnum.READ.getMode(), IotProductThinkModelAccessModeEnum.READ_WRITE.getMode())) { + // ThinkModelArgument arg = new ThinkModelArgument() // .setIdentifier(property.getIdentifier()) // .setName(property.getName()) // .setDataType(property.getDataType()) @@ -414,7 +414,7 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ return null; } - ThingModelService service = new ThingModelService() + ThinkModelService service = new ThinkModelService() .setIdentifier("get") .setName("属性获取") .setCallType("async") @@ -422,17 +422,17 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ .setMethod("thing.service.property.get"); // 定义输入参数:属性标识符列表 - ThingModelArgument inputArg = new ThingModelArgument() + ThinkModelArgument inputArg = new ThinkModelArgument() .setIdentifier("properties") .setName("属性标识符列表") .setDescription("需要获取的属性标识符列表") .setDirection("input"); // 设置为输入参数 // 创建数组类型,元素类型为文本类型(字符串) - ThingModelArrayDataSpecs arrayType = new ThingModelArrayDataSpecs(); + ThinkModelArrayDataSpecs arrayType = new ThinkModelArrayDataSpecs(); arrayType.setDataType("array"); - //ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs(); - ThingModelDateOrTextDataSpecs textType = new ThingModelDateOrTextDataSpecs(); + //ThinkModelArraySpecs arraySpecs = new ThinkModelArraySpecs(); + ThinkModelDateOrTextDataSpecs textType = new ThinkModelDateOrTextDataSpecs(); textType.setDataType("text"); //arraySpecs.setItem(textType); //arrayType.setSpecs(arraySpecs); From 0352dda469095b49555badf76fe33593a57c3974 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 18 Dec 2024 18:07:49 +0800 Subject: [PATCH 037/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IOT:=20=E4=BC=98=E5=8C=96=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=20TODO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/dataType/ThinkModelArgument.java | 6 +- .../dataobject/device/IotDeviceDataDO.java | 2 +- .../dal/dataobject/tdengine/FieldParser.java | 23 +++--- .../device/IotDeviceDataServiceImpl.java | 34 ++++---- .../IotThinkModelMessageServiceImpl.java | 5 +- .../IotProductThinkModelServiceImpl.java | 77 +++++++++---------- 6 files changed, 72 insertions(+), 75 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java index 9192fc28d..6a223286a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; import lombok.Data; @Data @@ -7,7 +8,10 @@ public class ThinkModelArgument { private String identifier; private String name; - private ThinkModelDataSpecs dataType; + /** + * 物模型中的属性 + */ + private ThinkModelProperty property; /** * 用于区分输入或输出参数,"input" 或 "output" */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java index 8ff9b1352..c3ed4863e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java @@ -32,7 +32,7 @@ public class IotDeviceDataDO { *

* 关联 {@link IotProductThinkModelDO#getId()} */ - private Long thinkModelFunctionId; + private Long thinkModelId; /** * 产品标识 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index 065d9bfed..81bfed068 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -35,19 +35,16 @@ public class FieldParser { */ public static TdFieldDO parse(ThinkModelProperty property) { String fieldName = property.getIdentifier().toLowerCase(); - //// TODO @puhui999: 需要重构 - //ThinkModelDataSpecs type = property.getDataType(); - // - //// 将物模型字段类型映射为td字段类型 - //String fType = TYPE_MAPPING.get(type.getDataType().toUpperCase()); - // - //// 如果字段类型为NCHAR,默认长度为64 - //int dataLength = 0; - //if ("NCHAR".equals(fType)) { - // dataLength = 64; - //} - //return new TdFieldDO(fieldName, fType, dataLength); - return null; + + // 将物模型字段类型映射为td字段类型 + String fType = TYPE_MAPPING.get(property.getDataType().toUpperCase()); + + // 如果字段类型为NCHAR,默认长度为64 + int dataLength = 0; + if ("NCHAR".equals(fType)) { + dataLength = 64; + } + return new TdFieldDO(fieldName, fType, dataLength); } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index ed2e32f2d..71780824a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -7,9 +7,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; @@ -28,6 +28,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; + @Slf4j @Service public class IotDeviceDataServiceImpl implements IotDeviceDataService { @@ -73,35 +75,31 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { // 1. 获取设备信息 IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); // 2. 获取设备属性最新数据 - List thinkModelFunctionList = thinkModelFunctionService.getProductThinkModelListByProductKey(device.getProductKey()); - thinkModelFunctionList = thinkModelFunctionList.stream() - .filter(function -> IotProductThinkModelTypeEnum.PROPERTY.getType() - .equals(function.getType())).toList(); + List thinkModelList = thinkModelFunctionService.getProductThinkModelListByProductKey(device.getProductKey()); + thinkModelList = filterList(thinkModelList, thinkModel -> IotProductThinkModelTypeEnum.PROPERTY.getType() + .equals(thinkModel.getType())); // 3. 过滤标识符和属性名称 if (deviceDataReqVO.getIdentifier() != null) { - thinkModelFunctionList = thinkModelFunctionList.stream() - .filter(function -> function.getIdentifier().toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())) - .toList(); + thinkModelList = filterList(thinkModelList, thinkModel -> thinkModel.getIdentifier() + .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())); } if (deviceDataReqVO.getName() != null) { - thinkModelFunctionList = thinkModelFunctionList.stream() - .filter(function -> function.getName().toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())) - .toList(); + thinkModelList = filterList(thinkModelList, thinkModel -> thinkModel.getName() + .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())); } // 4. 获取设备属性最新数据 - // TODO @puhui999: 需要重构 - thinkModelFunctionList.forEach(function -> { - IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), function.getIdentifier()); + thinkModelList.forEach(thinkModel -> { + IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thinkModel.getIdentifier()); if (deviceData == null) { deviceData = new IotDeviceDataDO(); deviceData.setProductKey(device.getProductKey()); deviceData.setDeviceName(device.getDeviceName()); - deviceData.setIdentifier(function.getIdentifier()); + deviceData.setIdentifier(thinkModel.getIdentifier()); deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); - deviceData.setThinkModelFunctionId(function.getId()); - deviceData.setName(function.getName()); - //deviceData.setDataType(function.getProperty().getDataType().getDataType()); + deviceData.setThinkModelId(thinkModel.getId()); + deviceData.setName(thinkModel.getName()); + deviceData.setDataType(thinkModel.getProperty().getDataType()); } list.add(deviceData); }); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java index eaaa3efeb..3c2debfa4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java @@ -129,7 +129,6 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ * @param time 时间 */ private void setDeviceDataCache(IotDeviceDO device, IotProductThinkModelDO iotProductThinkModelDO, Object val, Long time) { - // TODO @puhui999: 需要重构 IotDeviceDataDO deviceData = IotDeviceDataDO.builder() .productKey(device.getProductKey()) .deviceName(device.getDeviceName()) @@ -137,9 +136,9 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ .value(val != null ? val.toString() : null) .updateTime(DateUtil.toLocalDateTime(new Date(time))) .deviceId(device.getId()) - .thinkModelFunctionId(iotProductThinkModelDO.getId()) + .thinkModelId(iotProductThinkModelDO.getId()) .name(iotProductThinkModelDO.getName()) - //.dataType(iotProductThinkModelDO.getProperty().getDataType().getDataType()) + .dataType(iotProductThinkModelDO.getProperty().getDataType()) .build(); deviceDataRedisDAO.set(deviceData); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java index 862d8b95c..fa15083f0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; @@ -17,6 +18,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodel.IotProductThinkModelMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; +import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelAccessModeEnum; import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotSuperTableService; @@ -72,7 +74,7 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ // 6. 如果创建的是属性,需要更新默认的事件和服务 if (Objects.equals(createReqVO.getType(), IotProductThinkModelTypeEnum.PROPERTY.getType())) { - //createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); + createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } return function.getId(); } @@ -112,7 +114,7 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ @Transactional(rollbackFor = Exception.class) public void updateProductThinkModel(IotProductThinkModelSaveReqVO updateReqVO) { // 1. 校验功能是否存在 - validateproductThinkModelMapperExists(updateReqVO.getId()); + validateProductThinkModelMapperExists(updateReqVO.getId()); // 2. 校验功能标识符是否唯一 validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); @@ -163,7 +165,7 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ * * @param id 功能编号 */ - private void validateproductThinkModelMapperExists(Long id) { + private void validateProductThinkModelMapperExists(Long id) { if (productThinkModelMapper.selectById(id) == null) { throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); } @@ -201,7 +203,6 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ return productThinkModelMapper.selectListByProductKey(productKey); } - // TODO @puhui999: 需要重构 /** * 创建默认的事件和服务 */ @@ -333,14 +334,12 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ // 将属性列表转换为事件的输出参数 List outputData = new ArrayList<>(); - // TODO @puhui999: 需要重构 - for (IotProductThinkModelDO functionDO : propertyList) { - ThinkModelProperty property = functionDO.getProperty(); + for (IotProductThinkModelDO thinkModel : propertyList) { ThinkModelArgument arg = new ThinkModelArgument() - .setIdentifier(property.getIdentifier()) - .setName(property.getName()) - //.setDataType(property.getDataType()) - .setDescription(property.getDescription()) + .setIdentifier(thinkModel.getIdentifier()) + .setName(thinkModel.getName()) + .setProperty(thinkModel.getProperty()) + .setDescription(thinkModel.getDescription()) .setDirection("output"); // 设置为输出参数 outputData.add(arg); } @@ -357,18 +356,17 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ } List inputData = new ArrayList<>(); - // TODO @puhui999: 需要重构 - for (IotProductThinkModelDO functionDO : propertyList) { - ThinkModelProperty property = functionDO.getProperty(); - //if (IotProductThinkModelAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotProductThinkModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { - // ThinkModelArgument arg = new ThinkModelArgument() - // .setIdentifier(property.getIdentifier()) - // .setName(property.getName()) - // .setDataType(property.getDataType()) - // .setDescription(property.getDescription()) - // .setDirection("input"); // 设置为输入参数 - // inputData.add(arg); - //} + for (IotProductThinkModelDO thinkModel : propertyList) { + ThinkModelProperty property = thinkModel.getProperty(); + if (IotProductThinkModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { + ThinkModelArgument arg = new ThinkModelArgument() + .setIdentifier(property.getIdentifier()) + .setName(property.getName()) + .setProperty(property) + .setDescription(property.getDescription()) + .setDirection("input"); // 设置为输入参数 + inputData.add(arg); + } } if (inputData.isEmpty()) { // 如果没有可写属性,不生成属性设置服务 @@ -394,20 +392,20 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ if (propertyList == null || propertyList.isEmpty()) { return null; } - // TODO @puhui999: 需要重构 + List outputData = new ArrayList<>(); for (IotProductThinkModelDO functionDO : propertyList) { ThinkModelProperty property = functionDO.getProperty(); - //if (ObjectUtils.equalsAny(property.getAccessMode(), - // IotProductThinkModelAccessModeEnum.READ.getMode(), IotProductThinkModelAccessModeEnum.READ_WRITE.getMode())) { - // ThinkModelArgument arg = new ThinkModelArgument() - // .setIdentifier(property.getIdentifier()) - // .setName(property.getName()) - // .setDataType(property.getDataType()) - // .setDescription(property.getDescription()) - // .setDirection("output"); // 设置为输出参数 - // outputData.add(arg); - //} + if (ObjectUtils.equalsAny(property.getAccessMode(), + IotProductThinkModelAccessModeEnum.READ_ONLY.getMode(), IotProductThinkModelAccessModeEnum.READ_WRITE.getMode())) { + ThinkModelArgument arg = new ThinkModelArgument() + .setIdentifier(property.getIdentifier()) + .setName(property.getName()) + .setProperty(property) + .setDescription(property.getDescription()) + .setDirection("output"); // 设置为输出参数 + outputData.add(arg); + } } if (outputData.isEmpty()) { // 如果没有可读属性,不生成属性获取服务 @@ -428,15 +426,16 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ .setDescription("需要获取的属性标识符列表") .setDirection("input"); // 设置为输入参数 - // 创建数组类型,元素类型为文本类型(字符串) + // 创建数组类型,元素类型为文本类型(字符串)TODO @puhui999: 还得研究研究 ThinkModelArrayDataSpecs arrayType = new ThinkModelArrayDataSpecs(); arrayType.setDataType("array"); - //ThinkModelArraySpecs arraySpecs = new ThinkModelArraySpecs(); + inputArg.setProperty(new ThinkModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) + .setDescription(inputArg.getDescription()).setDataSpecs(arrayType)); + ThinkModelDateOrTextDataSpecs textType = new ThinkModelDateOrTextDataSpecs(); textType.setDataType("text"); - //arraySpecs.setItem(textType); - //arrayType.setSpecs(arraySpecs); - inputArg.setDataType(arrayType); + inputArg.setProperty(new ThinkModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) + .setDescription(inputArg.getDescription()).setDataSpecs(textType)); service.setInputData(Collections.singletonList(inputArg)); service.setOutputData(outputData); From de78cc9258b03557b8c8246705f60365f7d11643 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 18 Dec 2024 20:41:31 +0800 Subject: [PATCH 038/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E8=AF=84=E5=AE=A1=20ThingModel?= =?UTF-8?q?=20=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java | 1 - .../admin/thinkmodel/model/dataType/ThinkModelArgument.java | 3 +++ .../thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java index 7c7562e27..0ed00d08f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java @@ -6,7 +6,6 @@ import lombok.Getter; import java.util.Arrays; -// TODO @芋艿:纠结下,到底叫 thinkmodel 好,还是 function 好 /** * IOT 产品功能(物模型)类型枚举类 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java index 6a223286a..7b293ca79 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java @@ -6,6 +6,9 @@ import lombok.Data; @Data public class ThinkModelArgument { + public static final String DIRECTION_INPUT = "input"; + public static final String DIRECTION_OUTPUT = "output"; + private String identifier; private String name; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java index 5f3e2e8b4..ebc69f640 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java @@ -6,6 +6,7 @@ import lombok.EqualsAndHashCode; import java.util.List; +// TODO @puhui999:thingmodel 哈 = = 之前我写错单词了 /** * 物模型数据类型为数组的 DataSpec 定义 * From 8454a10cea33f74c1c82fa74f4e5fac9cd654e31 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Thu, 19 Dec 2024 11:19:10 +0800 Subject: [PATCH 039/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IOT:=20ThingModel=20=E8=AF=84=E5=AE=A1?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 12 +- .../IotProductThingModelAccessModeEnum.java} | 4 +- .../IotProductThingModelTypeEnum.java} | 10 +- .../vo/deviceData/IotDeviceDataRespVO.java | 2 +- .../IotProductThingModelController.http | 28 +- .../IotProductThingModelController.java | 84 ++++++ .../model/ThingModelEvent.java} | 8 +- .../model/ThingModelProperty.java} | 14 +- .../model/ThingModelRespVO.java} | 10 +- .../model/ThingModelService.java} | 10 +- .../model/dataType/ThingModelArgument.java} | 8 +- .../dataType/ThingModelArrayDataSpecs.java} | 7 +- .../ThingModelBoolOrEnumDataSpecs.java} | 4 +- .../model/dataType/ThingModelDataSpecs.java} | 24 +- .../ThingModelDateOrTextDataSpecs.java} | 4 +- .../dataType/ThingModelNumericDataSpec.java} | 4 +- .../dataType/ThingModelStructDataSpecs.java} | 12 +- .../vo/IotProductThingModelPageReqVO.java} | 8 +- .../vo/IotProductThingModelRespVO.java} | 16 +- .../vo/IotProductThingModelSaveReqVO.java} | 20 +- .../IotProductThinkModelController.java | 84 ------ .../convert/device/IotDeviceDataConvert.java | 2 +- .../IotProductThingModelConvert.java | 62 +++++ .../IotProductThinkModelConvert.java | 62 ----- .../dataobject/device/IotDeviceDataDO.java | 12 +- .../dal/dataobject/tdengine/FieldParser.java | 8 +- ...delMessage.java => ThingModelMessage.java} | 2 +- .../IotProductThingModelDO.java} | 26 +- .../IotProductThingModelMapper.java | 62 +++++ .../IotProductThinkModelMapper.java | 62 ----- .../device/IotDeviceDataServiceImpl.java | 40 +-- .../product/IotProductServiceImpl.java | 6 +- .../tdengine/IotSuperTableService.java | 5 +- .../tdengine/IotSuperTableServiceImpl.java | 36 +-- ....java => IotThingModelMessageService.java} | 6 +- ...a => IotThingModelMessageServiceImpl.java} | 58 ++--- .../IotProductThingModelService.java} | 24 +- .../IotProductThingModelServiceImpl.java} | 243 +++++++++--------- 38 files changed, 542 insertions(+), 547 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/{thinkmodel/IotProductThinkModelAccessModeEnum.java => thingmodel/IotProductThingModelAccessModeEnum.java} (68%) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/{thinkmodel/IotProductThinkModelTypeEnum.java => thingmodel/IotProductThingModelTypeEnum.java} (71%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel => thingmodel}/IotProductThingModelController.http (82%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/ThinkModelEvent.java => thingmodel/model/ThingModelEvent.java} (61%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/ThinkModelProperty.java => thingmodel/model/ThingModelProperty.java} (69%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/ThinkModelRespVO.java => thingmodel/model/ThingModelRespVO.java} (68%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/ThinkModelService.java => thingmodel/model/ThingModelService.java} (56%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/dataType/ThinkModelArgument.java => thingmodel/model/dataType/ThingModelArgument.java} (64%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java => thingmodel/model/dataType/ThingModelArrayDataSpecs.java} (77%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/dataType/ThinkModelBoolOrEnumDataSpecs.java => thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java} (85%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/dataType/ThinkModelDataSpecs.java => thingmodel/model/dataType/ThingModelDataSpecs.java} (51%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/dataType/ThinkModelDateOrTextDataSpecs.java => thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java} (84%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/dataType/ThinkModelNumericDataSpec.java => thingmodel/model/dataType/ThingModelNumericDataSpec.java} (91%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/model/dataType/ThinkModelStructDataSpecs.java => thingmodel/model/dataType/ThingModelStructDataSpecs.java} (76%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/vo/IotProductThinkModelPageReqVO.java => thingmodel/vo/IotProductThingModelPageReqVO.java} (76%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/vo/IotProductThinkModelRespVO.java => thingmodel/vo/IotProductThingModelRespVO.java} (77%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{thinkmodel/vo/IotProductThinkModelSaveReqVO.java => thingmodel/vo/IotProductThingModelSaveReqVO.java} (72%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThinkModelController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotProductThingModelConvert.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodel/IotProductThinkModelConvert.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/{ThinkModelMessage.java => ThingModelMessage.java} (97%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/{thinkmodel/IotProductThinkModelDO.java => thingmodel/IotProductThingModelDO.java} (67%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotProductThingModelMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodel/IotProductThinkModelMapper.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/{IotThinkModelMessageService.java => IotThingModelMessageService.java} (66%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/{IotThinkModelMessageServiceImpl.java => IotThingModelMessageServiceImpl.java} (79%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{thinkmodel/IotProductThinkModelService.java => thingmodel/IotProductThingModelService.java} (59%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{thinkmodel/IotProductThinkModelServiceImpl.java => thingmodel/IotProductThingModelServiceImpl.java} (56%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 633b3cb4f..4539f1259 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -13,14 +13,14 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在"); ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); - ErrorCode PRODUCT_STATUS_NOT_ALLOW_FUNCTION = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); + ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); // ========== 产品物模型 1-050-002-000 ============ - ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); - ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在"); - ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。"); - ErrorCode THINK_MODEL_FUNCTION_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。"); - ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效"); + ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); + ErrorCode THING_MODEL_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在"); + ErrorCode THING_MODEL_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。"); + ErrorCode THING_MODEL_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。"); + ErrorCode THING_MODEL_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效"); // ========== 设备 1-050-003-000 ============ ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在"); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java similarity index 68% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelAccessModeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java index b7f6ca312..a75501803 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.enums.thinkmodel; +package cn.iocoder.yudao.module.iot.enums.thingmodel; import lombok.AllArgsConstructor; import lombok.Getter; @@ -10,7 +10,7 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotProductThinkModelAccessModeEnum { +public enum IotProductThingModelAccessModeEnum { READ_ONLY("r"), READ_WRITE("rw"); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java similarity index 71% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java index 0ed00d08f..153e93ecc 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thinkmodel/IotProductThinkModelTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.enums.thinkmodel; +package cn.iocoder.yudao.module.iot.enums.thingmodel; import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; @@ -13,13 +13,13 @@ import java.util.Arrays; */ @AllArgsConstructor @Getter -public enum IotProductThinkModelTypeEnum implements IntArrayValuable { +public enum IotProductThingModelTypeEnum implements IntArrayValuable { PROPERTY(1, "属性"), SERVICE(2, "服务"), EVENT(3, "事件"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductThinkModelTypeEnum::getType).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductThingModelTypeEnum::getType).toArray(); /** * 类型 @@ -30,8 +30,8 @@ public enum IotProductThinkModelTypeEnum implements IntArrayValuable { */ private final String description; - public static IotProductThinkModelTypeEnum valueOfType(Integer type) { - for (IotProductThinkModelTypeEnum value : values()) { + public static IotProductThingModelTypeEnum valueOfType(Integer type) { + for (IotProductThingModelTypeEnum value : values()) { if (value.getType().equals(type)) { return value; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java index ad32fb5f9..f25377e2f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataRespVO.java @@ -13,7 +13,7 @@ public class IotDeviceDataRespVO { private Long deviceId; @Schema(description = "物模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") - private Long thinkModelFunctionId; + private Long thingModelId; @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) private String productKey; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThingModelController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThingModelController.http rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http index 2343eed38..7742705ef 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThingModelController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http @@ -1,5 +1,5 @@ -### 请求 /iot/product-think-model/create 接口 => 成功 -POST {{baseUrl}}/iot/product-think-model/create +### 请求 /iot/product-thing-model/create 接口 => 成功 +POST {{baseUrl}}/iot/product-thing-model/create Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -30,8 +30,8 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/product-think-model/create 接口 => 成功 -POST {{baseUrl}}/iot/product-think-model/create +### 请求 /iot/product-thing-model/create 接口 => 成功 +POST {{baseUrl}}/iot/product-thing-model/create Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -65,8 +65,8 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/product-think-model/create 接口 => 成功 -POST {{baseUrl}}/iot/product-think-model/create +### 请求 /iot/product-thing-model/create 接口 => 成功 +POST {{baseUrl}}/iot/product-thing-model/create Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -134,8 +134,8 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/product-think-model/update 接口 => 成功 -PUT {{baseUrl}}/iot/product-think-model/update +### 请求 /iot/product-thing-model/update 接口 => 成功 +PUT {{baseUrl}}/iot/product-thing-model/update Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -170,18 +170,18 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/product-think-model/delete 接口 => 成功 -DELETE {{baseUrl}}/iot/product-think-model/delete?id=36 +### 请求 /iot/product-thing-model/delete 接口 => 成功 +DELETE {{baseUrl}}/iot/product-thing-model/delete?id=36 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} -### 请求 /iot/product-think-model/get 接口 => 成功 -GET {{baseUrl}}/iot/product-think-model/get?id=40 +### 请求 /iot/product-thing-model/get 接口 => 成功 +GET {{baseUrl}}/iot/product-thing-model/get?id=40 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} -### 请求 /iot/product-think-model/list-by-product-id 接口 => 成功 -GET {{baseUrl}}/iot/product-think-model/list-by-product-id?productId=1001 +### 请求 /iot/product-thing-model/list-by-product-id 接口 => 成功 +GET {{baseUrl}}/iot/product-thing-model/list-by-product-id?productId=1001 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.java new file mode 100644 index 000000000..9b94def42 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 产品物模型") +@RestController +@RequestMapping("/iot/product-thing-model") +@Validated +public class IotProductThingModelController { + + @Resource + private IotProductThingModelService thingModelService; + + @PostMapping("/create") + @Operation(summary = "创建产品物模型") + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:create')") + public CommonResult createProductThingModel(@Valid @RequestBody IotProductThingModelSaveReqVO createReqVO) { + return success(thingModelService.createProductThingModel(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品物模型") + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:update')") + public CommonResult updateProductThingModel(@Valid @RequestBody IotProductThingModelSaveReqVO updateReqVO) { + thingModelService.updateProductThingModel(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品物模型") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:delete')") + public CommonResult deleteProductThingModel(@RequestParam("id") Long id) { + thingModelService.deleteProductThingModel(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品物模型") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") + public CommonResult getProductThingModel(@RequestParam("id") Long id) { + IotProductThingModelDO thingModel = thingModelService.getProductThingModel(id); + return success(IotProductThingModelConvert.INSTANCE.convert(thingModel)); + } + + @GetMapping("/list-by-product-id") + @Operation(summary = "获得产品物模型") + @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") + public CommonResult> getProductThingModelListByProductId(@RequestParam("productId") Long productId) { + List list = thingModelService.getProductThingModelListByProductId(productId); + return success(IotProductThingModelConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品物模型分页") + @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") + public CommonResult> getProductThingModelPage(@Valid IotProductThingModelPageReqVO pageReqVO) { + PageResult pageResult = thingModelService.getProductThingModelPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotProductThingModelRespVO.class)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java similarity index 61% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelEvent.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index 7d16aa50b..718c7b60e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; import lombok.Data; import java.util.List; @Data -public class ThinkModelEvent { +public class ThingModelEvent { /** * 事件标识符 @@ -26,7 +26,7 @@ public class ThinkModelEvent { * "info"、"alert"、"error" */ private String type; - private List outputData; + private List outputData; private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java similarity index 69% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelProperty.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index a4d2e9892..0c9105a8b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelDataSpecs; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelAccessModeEnum; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; import lombok.Data; import java.util.List; @@ -14,7 +14,7 @@ import java.util.List; * @author HUIHUI */ @Data -public class ThinkModelProperty { +public class ThingModelProperty { /** * 属性标识符 @@ -30,7 +30,7 @@ public class ThinkModelProperty { private String description; /** * 云端可以对该属性进行的操作类型 - * 关联枚举 {@link IotProductThinkModelAccessModeEnum} + * 关联枚举 {@link IotProductThingModelAccessModeEnum} */ private String accessMode; /** @@ -47,10 +47,10 @@ public class ThinkModelProperty { /** * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 */ - private ThinkModelDataSpecs dataSpecs; + private ThingModelDataSpecs dataSpecs; /** * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 */ - private List dataSpecsList; + private List dataSpecsList; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelRespVO.java similarity index 68% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelRespVO.java index 7eb06ce39..44fd24c0a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; import lombok.*; @@ -9,7 +9,7 @@ import java.util.List; @NoArgsConstructor @AllArgsConstructor @ToString -public class ThinkModelRespVO { +public class ThingModelRespVO { /** * 产品编号 @@ -35,16 +35,16 @@ public class ThinkModelRespVO { /** * 属性列表 */ - private List properties; + private List properties; /** * 服务列表 */ - private List services; + private List services; /** * 事件列表 */ - private List events; + private List events; } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java similarity index 56% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index 851df3656..ec4bd34e9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/ThinkModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; import lombok.Data; import java.util.List; @Data -public class ThinkModelService { +public class ThingModelService { /** * 服务标识符 @@ -26,8 +26,8 @@ public class ThinkModelService { * "sync"、"async" */ private String callType; - private List inputData; - private List outputData; + private List inputData; + private List outputData; private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java similarity index 64% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java index 7b293ca79..7b3fb097c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; import lombok.Data; @Data -public class ThinkModelArgument { +public class ThingModelArgument { public static final String DIRECTION_INPUT = "input"; public static final String DIRECTION_OUTPUT = "output"; @@ -14,7 +14,7 @@ public class ThinkModelArgument { /** * 物模型中的属性 */ - private ThinkModelProperty property; + private ThingModelProperty property; /** * 用于区分输入或输出参数,"input" 或 "output" */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java similarity index 77% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java index ebc69f640..b8b1a2975 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArrayDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @@ -6,7 +6,6 @@ import lombok.EqualsAndHashCode; import java.util.List; -// TODO @puhui999:thingmodel 哈 = = 之前我写错单词了 /** * 物模型数据类型为数组的 DataSpec 定义 * @@ -15,7 +14,7 @@ import java.util.List; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThinkModelArrayDataSpecs extends ThinkModelDataSpecs { +public class ThingModelArrayDataSpecs extends ThingModelDataSpecs { /** * 数组中的元素个数。 @@ -29,7 +28,7 @@ public class ThinkModelArrayDataSpecs extends ThinkModelDataSpecs { * 数据类型(childDataType)为列表型 struct 的数据规范存储在 dataSpecsList 中。 * 此时 struct 取值范围为:int、float、double、text、date、enum、bool */ - private List dataSpecsList; + private List dataSpecsList; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelBoolOrEnumDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelBoolOrEnumDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java index 8a44b584c..3ab624cab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelBoolOrEnumDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @@ -14,7 +14,7 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThinkModelBoolOrEnumDataSpecs extends ThinkModelDataSpecs { +public class ThingModelBoolOrEnumDataSpecs extends ThingModelDataSpecs { /** * 枚举项的名称。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java similarity index 51% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java index 2d0174765..78bfd02dd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Data; /** - * 抽象类 ThinkModelDataSpecs + * 抽象类 ThingModelDataSpecs * * 用于表示物模型数据的通用类型,根据具体的 "dataType" 字段动态映射到对应的子类。 * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 @@ -15,17 +15,17 @@ import lombok.Data; @Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "dataType", visible = true) @JsonSubTypes({ - @JsonSubTypes.Type(value = ThinkModelNumericDataSpec.class, name = "int"), - @JsonSubTypes.Type(value = ThinkModelNumericDataSpec.class, name = "float"), - @JsonSubTypes.Type(value = ThinkModelNumericDataSpec.class, name = "double"), - @JsonSubTypes.Type(value = ThinkModelDateOrTextDataSpecs.class, name = "text"), - @JsonSubTypes.Type(value = ThinkModelDateOrTextDataSpecs.class, name = "date"), - @JsonSubTypes.Type(value = ThinkModelBoolOrEnumDataSpecs.class, name = "bool"), - @JsonSubTypes.Type(value = ThinkModelBoolOrEnumDataSpecs.class, name = "enum"), - @JsonSubTypes.Type(value = ThinkModelArrayDataSpecs.class, name = "array"), - @JsonSubTypes.Type(value = ThinkModelStructDataSpecs.class, name = "struct") + @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "int"), + @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "float"), + @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "double"), + @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "text"), + @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "date"), + @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "bool"), + @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "enum"), + @JsonSubTypes.Type(value = ThingModelArrayDataSpecs.class, name = "array"), + @JsonSubTypes.Type(value = ThingModelStructDataSpecs.class, name = "struct") }) -public abstract class ThinkModelDataSpecs { +public abstract class ThingModelDataSpecs { /** * 数据类型 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDateOrTextDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java similarity index 84% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDateOrTextDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java index 640316b47..8d5ddff62 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelDateOrTextDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @@ -14,7 +14,7 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThinkModelDateOrTextDataSpecs extends ThinkModelDataSpecs { +public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs { /** * 数据长度,单位为字节。取值不能超过 2048。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelNumericDataSpec.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java similarity index 91% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelNumericDataSpec.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java index 714b57bd6..b65d606ac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelNumericDataSpec.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @@ -14,7 +14,7 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThinkModelNumericDataSpec extends ThinkModelDataSpecs { +public class ThingModelNumericDataSpec extends ThingModelDataSpecs { /** * 最大值,需转为字符串类型。值必须与 dataType 类型一致。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelStructDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java similarity index 76% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelStructDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java index 8cbb9afe5..e0f5bb539 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelStructDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelAccessModeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import lombok.EqualsAndHashCode; @@ -15,7 +15,7 @@ import java.util.List; @Data @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 -public class ThinkModelStructDataSpecs extends ThinkModelDataSpecs { +public class ThingModelStructDataSpecs extends ThingModelDataSpecs { /** * 属性标识符 @@ -31,7 +31,7 @@ public class ThinkModelStructDataSpecs extends ThinkModelDataSpecs { private String description; /** * 云端可以对该属性进行的操作类型 - * 关联枚举 {@link IotProductThinkModelAccessModeEnum} + * 关联枚举 {@link IotProductThingModelAccessModeEnum} */ private String accessMode; /** @@ -48,11 +48,11 @@ public class ThinkModelStructDataSpecs extends ThinkModelDataSpecs { /** * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 */ - private ThinkModelDataSpecs dataSpecs; + private ThingModelDataSpecs dataSpecs; /** * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 */ - private List dataSpecsList; + private List dataSpecsList; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelPageReqVO.java similarity index 76% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelPageReqVO.java index afb412228..a15ae98a1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelPageReqVO.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -13,7 +13,7 @@ import lombok.ToString; @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class IotProductThinkModelPageReqVO extends PageParam { +public class IotProductThingModelPageReqVO extends PageParam { @Schema(description = "功能标识") private String identifier; @@ -22,7 +22,7 @@ public class IotProductThinkModelPageReqVO extends PageParam { private String name; @Schema(description = "功能类型", example = "1") - @InEnum(IotProductThinkModelTypeEnum.class) + @InEnum(IotProductThingModelTypeEnum.class) private Integer type; @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelRespVO.java similarity index 77% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelRespVO.java index a79cd2677..8d9c370d9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelRespVO.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -13,7 +13,7 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - IoT 产品物模型 Response VO") @Data @ExcelIgnoreUnannotated -public class IotProductThinkModelRespVO { +public class IotProductThingModelRespVO { @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") @ExcelProperty("产品ID") @@ -39,13 +39,13 @@ public class IotProductThinkModelRespVO { private Integer type; @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) - private ThinkModelProperty property; + private ThingModelProperty property; @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED) - private ThinkModelEvent event; + private ThingModelEvent event; @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED) - private ThinkModelService service; + private ThingModelService service; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelSaveReqVO.java similarity index 72% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelSaveReqVO.java index 3cce60427..5f2be4847 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/vo/IotProductThinkModelSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelSaveReqVO.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo; +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -12,7 +12,7 @@ import lombok.Data; @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") @Data -public class IotProductThinkModelSaveReqVO { +public class IotProductThingModelSaveReqVO { @Schema(description = "编号", example = "1") private Long id; @@ -38,16 +38,16 @@ public class IotProductThinkModelSaveReqVO { @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "功能类型不能为空") - @InEnum(IotProductThinkModelTypeEnum.class) + @InEnum(IotProductThingModelTypeEnum.class) private Integer type; @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) - private ThinkModelProperty property; + private ThingModelProperty property; @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED) - private ThinkModelService service; + private ThingModelService service; @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED) - private ThinkModelEvent event; + private ThingModelEvent event; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThinkModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThinkModelController.java deleted file mode 100644 index 03408b59d..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/IotProductThinkModelController.java +++ /dev/null @@ -1,84 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.thinkmodel.IotProductThinkModelConvert; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; -import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - IoT 产品物模型") -@RestController -@RequestMapping("/iot/product-think-model") -@Validated -public class IotProductThinkModelController { - - @Resource - private IotProductThinkModelService thinkModelFunctionService; - - @PostMapping("/create") - @Operation(summary = "创建产品物模型") - @PreAuthorize("@ss.hasPermission('iot:product-think-model:create')") - public CommonResult createProductThinkModel(@Valid @RequestBody IotProductThinkModelSaveReqVO createReqVO) { - return success(thinkModelFunctionService.createProductThinkModel(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新产品物模型") - @PreAuthorize("@ss.hasPermission('iot:product-think-model:update')") - public CommonResult updateProductThinkModel(@Valid @RequestBody IotProductThinkModelSaveReqVO updateReqVO) { - thinkModelFunctionService.updateProductThinkModel(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除产品物模型") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:product-think-model:delete')") - public CommonResult deleteProductThinkModel(@RequestParam("id") Long id) { - thinkModelFunctionService.deleteProductThinkModel(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得产品物模型") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:product-think-model:query')") - public CommonResult getProductThinkModel(@RequestParam("id") Long id) { - IotProductThinkModelDO function = thinkModelFunctionService.getProductThinkModel(id); - return success(IotProductThinkModelConvert.INSTANCE.convert(function)); - } - - @GetMapping("/list-by-product-id") - @Operation(summary = "获得产品物模型") - @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('iot:product-think-model:query')") - public CommonResult> getProductThinkModelListByProductId(@RequestParam("productId") Long productId) { - List list = thinkModelFunctionService.getProductThinkModelListByProductId(productId); - return success(IotProductThinkModelConvert.INSTANCE.convertList(list)); - } - - @GetMapping("/page") - @Operation(summary = "获得产品物模型分页") - @PreAuthorize("@ss.hasPermission('iot:product-think-model:query')") - public CommonResult> getProductThinkModelPage(@Valid IotProductThinkModelPageReqVO pageReqVO) { - PageResult pageResult = thinkModelFunctionService.getProductThinkModelPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotProductThinkModelRespVO.class)); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java index 22d5dda6d..d8f6e4704 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java @@ -12,7 +12,7 @@ public interface IotDeviceDataConvert { // default List convert(Map deviceData, IotDeviceDO device){ // List list = new ArrayList<>(); // deviceData.forEach((identifier, value) -> { -//// ThinkModelProperty property = ThinkModelService.INSTANCE.getProperty(device.getProductId(), identifier); +//// ThingModelProperty property = ThingModelService.INSTANCE.getProperty(device.getProductId(), identifier); //// if (Objects.isNull(property)) { //// return; //// } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotProductThingModelConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotProductThingModelConvert.java new file mode 100644 index 000000000..cb10c62b5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotProductThingModelConvert.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.iot.convert.thingmodel; + +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Objects; + +@Mapper +public interface IotProductThingModelConvert { + + IotProductThingModelConvert INSTANCE = Mappers.getMapper(IotProductThingModelConvert.class); + + // 将 SaveReqVO 转换为 DO + @Mapping(target = "property", expression = "java(convertToProperty(bean))") + @Mapping(target = "event", expression = "java(convertToEvent(bean))") + @Mapping(target = "service", expression = "java(convertToService(bean))") + IotProductThingModelDO convert(IotProductThingModelSaveReqVO bean); + + // 将 DO 转换为 RespVO + @Mapping(target = "property", source = "property") + @Mapping(target = "event", source = "event") + @Mapping(target = "service", source = "service") + IotProductThingModelRespVO convert(IotProductThingModelDO bean); + + // 批量转换 + List convertList(List list); + + @Named("convertToProperty") + default ThingModelProperty convertToProperty(IotProductThingModelSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + return bean.getProperty(); + } + return null; + } + + @Named("convertToEvent") + default ThingModelEvent convertToEvent(IotProductThingModelSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.EVENT.getType())) { + return bean.getEvent(); + } + return null; + } + + @Named("convertToService") + default ThingModelService convertToService(IotProductThingModelSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.SERVICE.getType())) { + return bean.getService(); + } + return null; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodel/IotProductThinkModelConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodel/IotProductThinkModelConvert.java deleted file mode 100644 index bb5c22b35..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodel/IotProductThinkModelConvert.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.iot.convert.thinkmodel; - -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.mapstruct.factory.Mappers; - -import java.util.List; -import java.util.Objects; - -@Mapper -public interface IotProductThinkModelConvert { - - IotProductThinkModelConvert INSTANCE = Mappers.getMapper(IotProductThinkModelConvert.class); - - // 将 SaveReqVO 转换为 DO - @Mapping(target = "property", expression = "java(convertToProperty(bean))") - @Mapping(target = "event", expression = "java(convertToEvent(bean))") - @Mapping(target = "service", expression = "java(convertToService(bean))") - IotProductThinkModelDO convert(IotProductThinkModelSaveReqVO bean); - - // 将 DO 转换为 RespVO - @Mapping(target = "property", source = "property") - @Mapping(target = "event", source = "event") - @Mapping(target = "service", source = "service") - IotProductThinkModelRespVO convert(IotProductThinkModelDO bean); - - // 批量转换 - List convertList(List list); - - @Named("convertToProperty") - default ThinkModelProperty convertToProperty(IotProductThinkModelSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductThinkModelTypeEnum.PROPERTY.getType())) { - return bean.getProperty(); - } - return null; - } - - @Named("convertToEvent") - default ThinkModelEvent convertToEvent(IotProductThinkModelSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductThinkModelTypeEnum.EVENT.getType())) { - return bean.getEvent(); - } - return null; - } - - @Named("convertToService") - default ThinkModelService convertToService(IotProductThinkModelSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductThinkModelTypeEnum.SERVICE.getType())) { - return bean.getService(); - } - return null; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java index c3ed4863e..ab1934edb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -30,9 +30,9 @@ public class IotDeviceDataDO { /** * 物模型编号 *

- * 关联 {@link IotProductThinkModelDO#getId()} + * 关联 {@link IotProductThingModelDO#getId()} */ - private Long thinkModelId; + private Long thingModelId; /** * 产品标识 @@ -51,21 +51,21 @@ public class IotDeviceDataDO { /** * 属性标识符 *

- * 关联 {@link IotProductThinkModelDO#getIdentifier()} + * 关联 {@link IotProductThingModelDO#getIdentifier()} */ private String identifier; /** * 属性名称 *

- * 关联 {@link IotProductThinkModelDO#getName()} + * 关联 {@link IotProductThingModelDO#getName()} */ private String name; /** * 数据类型 *

- * 关联 {@link IotProductThinkModelDO#getProperty()#getDataType()} + * 关联 {@link IotProductThingModelDO#getProperty()#getDataType()} */ private String dataType; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index 81bfed068..637b2228b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelRespVO; import java.util.HashMap; import java.util.List; @@ -33,7 +33,7 @@ public class FieldParser { * @param property 物模型属性 * @return TdField对象 */ - public static TdFieldDO parse(ThinkModelProperty property) { + public static TdFieldDO parse(ThingModelProperty property) { String fieldName = property.getIdentifier().toLowerCase(); // 将物模型字段类型映射为td字段类型 @@ -53,7 +53,7 @@ public class FieldParser { * @param thingModel 物模型响应对象 * @return 字段列表 */ - public static List parse(ThinkModelRespVO thingModel) { + public static List parse(ThingModelRespVO thingModel) { return thingModel.getModel().getProperties().stream() .map(FieldParser::parse) .collect(Collectors.toList()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessage.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessage.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java index 22cf9e2ef..d5009dc24 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessage.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java @@ -15,7 +15,7 @@ import java.util.Map; @NoArgsConstructor @AllArgsConstructor @Builder -public class ThinkModelMessage { +public class ThingModelMessage { /** * 消息ID diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodel/IotProductThinkModelDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java similarity index 67% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodel/IotProductThinkModelDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java index 76b2a63e7..3d9e5e5fe 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodel/IotProductThinkModelDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -19,17 +19,17 @@ import lombok.NoArgsConstructor; /** * IoT 产品物模型功能 DO *

- * 每个 {@link IotProductDO} 和 {@link IotProductThinkModelDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 + * 每个 {@link IotProductDO} 和 {@link IotProductThingModelDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 * * @author 芋道源码 */ -@TableName(value = "iot_product_think_model", autoResultMap = true) -@KeySequence("iot_product_think_model_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName(value = "iot_product_thing_model", autoResultMap = true) +@KeySequence("iot_product_thing_model_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor @AllArgsConstructor -public class IotProductThinkModelDO extends BaseDO { +public class IotProductThingModelDO extends BaseDO { /** * 物模型功能编号 @@ -66,7 +66,7 @@ public class IotProductThinkModelDO extends BaseDO { /** * 功能类型 *

- * 枚举 {@link IotProductThinkModelTypeEnum} + * 枚举 {@link IotProductThingModelTypeEnum} */ private Integer type; @@ -74,18 +74,18 @@ public class IotProductThinkModelDO extends BaseDO { * 属性 */ @TableField(typeHandler = JacksonTypeHandler.class) - private ThinkModelProperty property; + private ThingModelProperty property; /** * 事件 */ @TableField(typeHandler = JacksonTypeHandler.class) - private ThinkModelEvent event; + private ThingModelEvent event; /** * 服务 */ @TableField(typeHandler = JacksonTypeHandler.class) - private ThinkModelService service; + private ThingModelService service; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotProductThingModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotProductThingModelMapper.java new file mode 100644 index 000000000..175f66f40 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotProductThingModelMapper.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.thingmodel; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * IoT 产品物模型 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotProductThingModelMapper extends BaseMapperX { + + default PageResult selectPage(IotProductThingModelPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotProductThingModelDO::getIdentifier, reqVO.getIdentifier()) + .likeIfPresent(IotProductThingModelDO::getName, reqVO.getName()) + .eqIfPresent(IotProductThingModelDO::getType, reqVO.getType()) + .eqIfPresent(IotProductThingModelDO::getProductId, reqVO.getProductId()) + .notIn(IotProductThingModelDO::getIdentifier, "get", "set", "post") + .orderByDesc(IotProductThingModelDO::getId)); + } + + default IotProductThingModelDO selectByProductIdAndIdentifier(Long productId, String identifier) { + return selectOne(IotProductThingModelDO::getProductId, productId, + IotProductThingModelDO::getIdentifier, identifier); + } + + default List selectListByProductId(Long productId) { + return selectList(IotProductThingModelDO::getProductId, productId); + } + + default List selectListByProductIdAndType(Long productId, Integer type) { + return selectList(IotProductThingModelDO::getProductId, productId, + IotProductThingModelDO::getType, type); + } + + default List selectListByProductIdAndIdentifiersAndTypes(Long productId, + List identifiers, + List types) { + return selectList(new LambdaQueryWrapperX() + .eq(IotProductThingModelDO::getProductId, productId) + .in(IotProductThingModelDO::getIdentifier, identifiers) + .in(IotProductThingModelDO::getType, types)); + } + + default IotProductThingModelDO selectByProductIdAndName(Long productId, String name) { + return selectOne(IotProductThingModelDO::getProductId, productId, + IotProductThingModelDO::getName, name); + } + + default List selectListByProductKey(String productKey) { + return selectList(IotProductThingModelDO::getProductKey, productKey); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodel/IotProductThinkModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodel/IotProductThinkModelMapper.java deleted file mode 100644 index de76aa633..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodel/IotProductThinkModelMapper.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodel; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * IoT 产品物模型 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface IotProductThinkModelMapper extends BaseMapperX { - - default PageResult selectPage(IotProductThinkModelPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(IotProductThinkModelDO::getIdentifier, reqVO.getIdentifier()) - .likeIfPresent(IotProductThinkModelDO::getName, reqVO.getName()) - .eqIfPresent(IotProductThinkModelDO::getType, reqVO.getType()) - .eqIfPresent(IotProductThinkModelDO::getProductId, reqVO.getProductId()) - .notIn(IotProductThinkModelDO::getIdentifier, "get", "set", "post") - .orderByDesc(IotProductThinkModelDO::getId)); - } - - default IotProductThinkModelDO selectByProductIdAndIdentifier(Long productId, String identifier) { - return selectOne(IotProductThinkModelDO::getProductId, productId, - IotProductThinkModelDO::getIdentifier, identifier); - } - - default List selectListByProductId(Long productId) { - return selectList(IotProductThinkModelDO::getProductId, productId); - } - - default List selectListByProductIdAndType(Long productId, Integer type) { - return selectList(IotProductThinkModelDO::getProductId, productId, - IotProductThinkModelDO::getType, type); - } - - default List selectListByProductIdAndIdentifiersAndTypes(Long productId, - List identifiers, - List types) { - return selectList(new LambdaQueryWrapperX() - .eq(IotProductThinkModelDO::getProductId, productId) - .in(IotProductThinkModelDO::getIdentifier, identifiers) - .in(IotProductThinkModelDO::getType, types)); - } - - default IotProductThinkModelDO selectByProductIdAndName(Long productId, String name) { - return selectOne(IotProductThinkModelDO::getProductId, productId, - IotProductThinkModelDO::getName, name); - } - - default List selectListByProductKey(String productKey) { - return selectList(IotProductThinkModelDO::getProductKey, productKey); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java index 71780824a..4cb39c0bc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java @@ -8,14 +8,14 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDevi import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; -import cn.iocoder.yudao.module.iot.service.tdengine.IotThinkModelMessageService; -import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; @@ -40,9 +40,9 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { @Resource private IotDeviceService deviceService; @Resource - private IotThinkModelMessageService thingModelMessageService; + private IotThingModelMessageService thingModelMessageService; @Resource - private IotProductThinkModelService thinkModelFunctionService; + private IotProductThingModelService thingModelService; @Resource private TdEngineDMLMapper tdEngineDMLMapper; @@ -56,7 +56,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { // 2. 解析消息,保存数据 JSONObject jsonObject = new JSONObject(message); log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", productKey, deviceName, jsonObject); - ThinkModelMessage thingModelMessage = ThinkModelMessage.builder() + ThingModelMessage thingModelMessage = ThingModelMessage.builder() .id(jsonObject.getStr("id")) .sys(jsonObject.get("sys")) .method(jsonObject.getStr("method")) @@ -66,7 +66,7 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { .deviceName(deviceName) .deviceKey(device.getDeviceKey()) .build(); - thingModelMessageService.saveThinkModelMessage(device, thingModelMessage); + thingModelMessageService.saveThingModelMessage(device, thingModelMessage); } @Override @@ -75,31 +75,31 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { // 1. 获取设备信息 IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); // 2. 获取设备属性最新数据 - List thinkModelList = thinkModelFunctionService.getProductThinkModelListByProductKey(device.getProductKey()); - thinkModelList = filterList(thinkModelList, thinkModel -> IotProductThinkModelTypeEnum.PROPERTY.getType() - .equals(thinkModel.getType())); + List thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey()); + thingModelList = filterList(thingModelList, thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType() + .equals(thingModel.getType())); // 3. 过滤标识符和属性名称 if (deviceDataReqVO.getIdentifier() != null) { - thinkModelList = filterList(thinkModelList, thinkModel -> thinkModel.getIdentifier() + thingModelList = filterList(thingModelList, thingModel -> thingModel.getIdentifier() .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())); } if (deviceDataReqVO.getName() != null) { - thinkModelList = filterList(thinkModelList, thinkModel -> thinkModel.getName() + thingModelList = filterList(thingModelList, thingModel -> thingModel.getName() .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())); } // 4. 获取设备属性最新数据 - thinkModelList.forEach(thinkModel -> { - IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thinkModel.getIdentifier()); + thingModelList.forEach(thingModel -> { + IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thingModel.getIdentifier()); if (deviceData == null) { deviceData = new IotDeviceDataDO(); deviceData.setProductKey(device.getProductKey()); deviceData.setDeviceName(device.getDeviceName()); - deviceData.setIdentifier(thinkModel.getIdentifier()); + deviceData.setIdentifier(thingModel.getIdentifier()); deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); - deviceData.setThinkModelId(thinkModel.getId()); - deviceData.setName(thinkModel.getName()); - deviceData.setDataType(thinkModel.getProperty().getDataType()); + deviceData.setThingModelId(thingModel.getId()); + deviceData.setName(thingModel.getName()); + deviceData.setDataType(thingModel.getProperty().getDataType()); } list.add(deviceData); }); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index b26c2c123..4fd6cfff0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; @@ -34,7 +34,7 @@ public class IotProductServiceImpl implements IotProductService { @Resource @Lazy - private IotProductThinkModelService thinkModelFunctionService; + private IotProductThingModelService thingModelService; @Override public Long createProduct(IotProductSaveReqVO createReqVO) { @@ -115,7 +115,7 @@ public class IotProductServiceImpl implements IotProductService { // 3. 产品是发布状态 if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { // 3.1 创建超级表数据模型 - thinkModelFunctionService.createSuperTableDataModel(id); + thingModelService.createSuperTableDataModel(id); } productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java index bf76ae1c3..bb6d8c077 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import java.util.List; @@ -14,5 +14,6 @@ public interface IotSuperTableService { /** * 创建超级表数据模型 */ - void createSuperTableDataModel(IotProductDO product, List functionList); + void createSuperTableDataModel(IotProductDO product, List thingModelList); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java index 59fa9d0f3..1727fae62 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java @@ -2,15 +2,15 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -33,8 +33,8 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { private String url; @Override - public void createSuperTableDataModel(IotProductDO product, List functionList) { - ThinkModelRespVO thingModel = buildThinkModel(product, functionList); + public void createSuperTableDataModel(IotProductDO product, List thingModelList) { + ThingModelRespVO thingModel = buildThingModel(product, thingModelList); if (thingModel.getModel() == null || CollUtil.isEmpty(thingModel.getModel().getProperties())) { log.warn("物模型属性列表为空,不创建超级表"); @@ -56,7 +56,7 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 创建超级表 */ - private void createSuperTable(ThinkModelRespVO thingModel, Integer deviceType) { + private void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { // 解析物模型,获取字段列表 List schemaFields = new ArrayList<>(); schemaFields.add(TdFieldDO.builder() @@ -84,7 +84,7 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 更新超级表 */ - private void updateSuperTable(ThinkModelRespVO thingModel, Integer deviceType) { + private void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { String superTableName = getSuperTableName(deviceType, thingModel.getProductKey()); try { List oldFields = getTableFields(superTableName); @@ -210,18 +210,18 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 构建物模型 */ - private ThinkModelRespVO buildThinkModel(IotProductDO product, List functionList) { - ThinkModelRespVO thingModel = new ThinkModelRespVO(); + private ThingModelRespVO buildThingModel(IotProductDO product, List thingModelList) { + ThingModelRespVO thingModel = new ThingModelRespVO(); thingModel.setId(product.getId()); thingModel.setProductKey(product.getProductKey()); - List properties = functionList.stream() - .filter(function -> IotProductThinkModelTypeEnum.PROPERTY.equals( - IotProductThinkModelTypeEnum.valueOfType(function.getType()))) - .map(this::buildThinkModelProperty) + List properties = thingModelList.stream() + .filter(item -> IotProductThingModelTypeEnum.PROPERTY.equals( + IotProductThingModelTypeEnum.valueOfType(item.getType()))) + .map(this::buildThingModelProperty) .collect(Collectors.toList()); - ThinkModelRespVO.Model model = new ThinkModelRespVO.Model(); + ThingModelRespVO.Model model = new ThingModelRespVO.Model(); model.setProperties(properties); thingModel.setModel(model); @@ -231,9 +231,9 @@ public class IotSuperTableServiceImpl implements IotSuperTableService { /** * 构建物模型属性 */ - private ThinkModelProperty buildThinkModelProperty(IotProductThinkModelDO function) { - ThinkModelProperty property = BeanUtil.copyProperties(function, ThinkModelProperty.class); - property.setDataType(function.getProperty().getDataType()); + private ThingModelProperty buildThingModelProperty(IotProductThingModelDO thingModel) { + ThingModelProperty property = BeanUtil.copyProperties(thingModel, ThingModelProperty.class); + property.setDataType(thingModel.getProperty().getDataType()); return property; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java similarity index 66% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java index 67ee2b99a..ffcb3063c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java @@ -1,12 +1,12 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; /** * 物模型消息 Service */ -public interface IotThinkModelMessageService { +public interface IotThingModelMessageService { /** * 保存物模型消息 @@ -14,5 +14,5 @@ public interface IotThinkModelMessageService { * @param device 设备 * @param thingModelMessage 物模型消息 */ - void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage); + void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java similarity index 79% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 3c2debfa4..f5d589287 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -10,16 +10,16 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -28,12 +28,14 @@ import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; + /** * 物模型消息 Service 实现类 */ @Slf4j @Service -public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageService { +public class IotThingModelMessageServiceImpl implements IotThingModelMessageService { private static final String TAG_NOTE = "TAG"; private static final String NOTE = "note"; @@ -47,7 +49,7 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ private String url; @Resource - private IotProductThinkModelService iotProductThinkModelService; + private IotProductThingModelService iotProductThingModelService; @Resource private IotDeviceService iotDeviceService; @Resource @@ -61,7 +63,7 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 @Override @TenantIgnore - public void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage) { + public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) { // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); @@ -71,13 +73,13 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 Map params = thingModelMessage.dataToMap(); - List functionList = getValidFunctionList(thingModelMessage.getProductKey()); - if (functionList.isEmpty()) { + List thingModelList = getValidThingModelList(thingModelMessage.getProductKey()); + if (thingModelList.isEmpty()) { return; } // 3. 过滤并收集有效的属性字段,缓存设备属性 - List schemaFieldValues = filterAndCollectValidFields(params, functionList, device, thingModelMessage.getTime()); + List schemaFieldValues = filterAndCollectValidFields(params, thingModelList, device, thingModelMessage.getTime()); if (schemaFieldValues.size() == 1) { // 仅有时间字段,无需保存 return; } @@ -90,21 +92,17 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ .build()); } - private List getValidFunctionList(String productKey) { - return iotProductThinkModelService - .getProductThinkModelListByProductKey(productKey) - .stream() - .filter(function -> IotProductThinkModelTypeEnum.PROPERTY.getType().equals(function.getType())) - .toList(); + private List getValidThingModelList(String productKey) { + return filterList(iotProductThingModelService.getProductThingModelListByProductKey(productKey), + thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); } - private List filterAndCollectValidFields(Map params, List functionList, IotDeviceDO device, Long time) { + private List filterAndCollectValidFields(Map params, List thingModelList, IotDeviceDO device, Long time) { // 1. 获取属性标识符集合 - Set propertyIdentifiers = CollectionUtils.convertSet(functionList, IotProductThinkModelDO::getIdentifier); + Set propertyIdentifiers = convertSet(thingModelList, IotProductThingModelDO::getIdentifier); // 2. 构建属性标识符和属性的映射 - Map functionMap = functionList.stream() - .collect(Collectors.toMap(IotProductThinkModelDO::getIdentifier, function -> function)); + Map thingModelMap = convertMap(thingModelList, IotProductThingModelDO::getIdentifier); // 3. 过滤并收集有效的属性字段 List schemaFieldValues = new ArrayList<>(); @@ -114,7 +112,7 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val)); // 缓存设备属性 // TODO @haohao:这个缓存的写入,可以使用的时候 cache 么?被动读 - setDeviceDataCache(device, functionMap.get(key), val, time); + setDeviceDataCache(device, thingModelMap.get(key), val, time); } }); return schemaFieldValues; @@ -123,22 +121,22 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ /** * 缓存设备属性 * - * @param device 设备信息 - * @param iotProductThinkModelDO 物模型属性 - * @param val 属性值 - * @param time 时间 + * @param device 设备信息 + * @param iotProductThingModelDO 物模型属性 + * @param val 属性值 + * @param time 时间 */ - private void setDeviceDataCache(IotDeviceDO device, IotProductThinkModelDO iotProductThinkModelDO, Object val, Long time) { + private void setDeviceDataCache(IotDeviceDO device, IotProductThingModelDO iotProductThingModelDO, Object val, Long time) { IotDeviceDataDO deviceData = IotDeviceDataDO.builder() .productKey(device.getProductKey()) .deviceName(device.getDeviceName()) - .identifier(iotProductThinkModelDO.getIdentifier()) + .identifier(iotProductThingModelDO.getIdentifier()) .value(val != null ? val.toString() : null) .updateTime(DateUtil.toLocalDateTime(new Date(time))) .deviceId(device.getId()) - .thinkModelId(iotProductThinkModelDO.getId()) - .name(iotProductThinkModelDO.getName()) - .dataType(iotProductThinkModelDO.getProperty().getDataType()) + .thingModelId(iotProductThingModelDO.getId()) + .name(iotProductThingModelDO.getName()) + .dataType(iotProductThingModelDO.getProperty().getDataType()) .build(); deviceDataRedisDAO.set(deviceData); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java similarity index 59% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java index 34e7fc149..04086d0a7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java @@ -1,9 +1,9 @@ -package cn.iocoder.yudao.module.iot.service.thinkmodel; +package cn.iocoder.yudao.module.iot.service.thingmodel; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import jakarta.validation.Valid; import java.util.List; @@ -13,7 +13,7 @@ import java.util.List; * * @author 芋道源码 */ -public interface IotProductThinkModelService { +public interface IotProductThingModelService { /** * 创建产品物模型 @@ -21,21 +21,21 @@ public interface IotProductThinkModelService { * @param createReqVO 创建信息 * @return 编号 */ - Long createProductThinkModel(@Valid IotProductThinkModelSaveReqVO createReqVO); + Long createProductThingModel(@Valid IotProductThingModelSaveReqVO createReqVO); /** * 更新产品物模型 * * @param updateReqVO 更新信息 */ - void updateProductThinkModel(@Valid IotProductThinkModelSaveReqVO updateReqVO); + void updateProductThingModel(@Valid IotProductThingModelSaveReqVO updateReqVO); /** * 删除产品物模型 * * @param id 编号 */ - void deleteProductThinkModel(Long id); + void deleteProductThingModel(Long id); /** * 获得产品物模型 @@ -43,7 +43,7 @@ public interface IotProductThinkModelService { * @param id 编号 * @return 产品物模型 */ - IotProductThinkModelDO getProductThinkModel(Long id); + IotProductThingModelDO getProductThingModel(Long id); /** * 获得产品物模型列表 @@ -51,7 +51,7 @@ public interface IotProductThinkModelService { * @param productId 产品编号 * @return 产品物模型列表 */ - List getProductThinkModelListByProductId(Long productId); + List getProductThingModelListByProductId(Long productId); /** * 获得产品物模型分页 @@ -59,7 +59,7 @@ public interface IotProductThinkModelService { * @param pageReqVO 分页查询 * @return 产品物模型分页 */ - PageResult getProductThinkModelPage(IotProductThinkModelPageReqVO pageReqVO); + PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO); /** * 创建超级表数据模型 @@ -74,6 +74,6 @@ public interface IotProductThinkModelService { * @param productKey 产品 Key * @return 产品物模型列表 */ - List getProductThinkModelListByProductKey(String productKey); + List getProductThingModelListByProductKey(String productKey); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java similarity index 56% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java index fa15083f0..b5c2d4eee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodel/IotProductThinkModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java @@ -1,25 +1,25 @@ -package cn.iocoder.yudao.module.iot.service.thinkmodel; +package cn.iocoder.yudao.module.iot.service.thingmodel; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelArgument; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelArrayDataSpecs; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType.ThinkModelDateOrTextDataSpecs; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.vo.IotProductThinkModelSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.thinkmodel.IotProductThinkModelConvert; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArrayDataSpecs; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; -import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodel.IotProductThinkModelMapper; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelAccessModeEnum; -import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotSuperTableService; import jakarta.annotation.Resource; @@ -43,10 +43,10 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @Service @Validated @Slf4j -public class IotProductThinkModelServiceImpl implements IotProductThinkModelService { +public class IotProductThingModelServiceImpl implements IotProductThingModelService { @Resource - private IotProductThinkModelMapper productThinkModelMapper; + private IotProductThingModelMapper productThingModelMapper; @Resource private IotProductService productService; @@ -55,7 +55,7 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ @Override @Transactional(rollbackFor = Exception.class) - public Long createProductThinkModel(IotProductThinkModelSaveReqVO createReqVO) { + public Long createProductThingModel(IotProductThingModelSaveReqVO createReqVO) { // 1. 校验功能标识符在同一产品下是否唯一 validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); @@ -69,52 +69,49 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ validateProductStatus(createReqVO.getProductId()); // 5. 插入数据库 - IotProductThinkModelDO function = IotProductThinkModelConvert.INSTANCE.convert(createReqVO); - productThinkModelMapper.insert(function); + IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(createReqVO); + productThingModelMapper.insert(thingModel); // 6. 如果创建的是属性,需要更新默认的事件和服务 - if (Objects.equals(createReqVO.getType(), IotProductThinkModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } - return function.getId(); + return thingModel.getId(); } private void validateProductStatus(Long createReqVO) { IotProductDO product = productService.getProduct(createReqVO); if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) { - throw exception(PRODUCT_STATUS_NOT_ALLOW_FUNCTION); + throw exception(PRODUCT_STATUS_NOT_ALLOW_THING_MODEL); } } private void validateNotDefaultEventAndService(String identifier) { // set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义 if (CollUtil.containsAny(Arrays.asList("set", "get", "post", "property", "event", "time", "value"), Collections.singletonList(identifier))) { - throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_INVALID); + throw exception(THING_MODEL_IDENTIFIER_INVALID); } -// if (CollUtil.containsAny(Arrays.asList("post", "set", "get"), identifier)) { -// throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_INVALID); -// } } private void validateNameUnique(Long productId, String name) { - IotProductThinkModelDO function = productThinkModelMapper.selectByProductIdAndName(productId, name); - if (function != null) { - throw exception(THINK_MODEL_FUNCTION_NAME_EXISTS); + IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndName(productId, name); + if (thingModel != null) { + throw exception(THING_MODEL_NAME_EXISTS); } } private void validateIdentifierUnique(Long productId, String identifier) { - IotProductThinkModelDO function = productThinkModelMapper.selectByProductIdAndIdentifier(productId, identifier); - if (function != null) { - throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS); + IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); + if (thingModel != null) { + throw exception(THING_MODEL_IDENTIFIER_EXISTS); } } @Override @Transactional(rollbackFor = Exception.class) - public void updateProductThinkModel(IotProductThinkModelSaveReqVO updateReqVO) { + public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { // 1. 校验功能是否存在 - validateProductThinkModelMapperExists(updateReqVO.getId()); + validateProductThingModelMapperExists(updateReqVO.getId()); // 2. 校验功能标识符是否唯一 validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); @@ -123,40 +120,40 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ validateProductStatus(updateReqVO.getProductId()); // 4. 更新数据库 - IotProductThinkModelDO productThinkModelDO = IotProductThinkModelConvert.INSTANCE.convert(updateReqVO); - productThinkModelMapper.updateById(productThinkModelDO); + IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(updateReqVO); + productThingModelMapper.updateById(thingModel); // 5. 如果更新的是属性,需要更新默认的事件和服务 - if (Objects.equals(updateReqVO.getType(), IotProductThinkModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } } private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { - IotProductThinkModelDO function = productThinkModelMapper.selectByProductIdAndIdentifier(productId, identifier); - if (function != null && ObjectUtil.notEqual(function.getId(), id)) { - throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS); + IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); + if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) { + throw exception(THING_MODEL_IDENTIFIER_EXISTS); } } @Override @Transactional(rollbackFor = Exception.class) - public void deleteProductThinkModel(Long id) { + public void deleteProductThingModel(Long id) { // 1. 校验功能是否存在 - IotProductThinkModelDO functionDO = productThinkModelMapper.selectById(id); - if (functionDO == null) { - throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); + IotProductThingModelDO thingModel = productThingModelMapper.selectById(id); + if (thingModel == null) { + throw exception(THING_MODEL_NOT_EXISTS); } // 3. 校验产品状态,发布状态下,不允许操作功能 - validateProductStatus(functionDO.getProductId()); + validateProductStatus(thingModel.getProductId()); // 2. 删除功能 - productThinkModelMapper.deleteById(id); + productThingModelMapper.deleteById(id); // 3. 如果删除的是属性,需要更新默认的事件和服务 - if (Objects.equals(functionDO.getType(), IotProductThinkModelTypeEnum.PROPERTY.getType())) { - createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey()); + if (Objects.equals(thingModel.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey()); } } @@ -165,25 +162,25 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ * * @param id 功能编号 */ - private void validateProductThinkModelMapperExists(Long id) { - if (productThinkModelMapper.selectById(id) == null) { - throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); + private void validateProductThingModelMapperExists(Long id) { + if (productThingModelMapper.selectById(id) == null) { + throw exception(THING_MODEL_NOT_EXISTS); } } @Override - public IotProductThinkModelDO getProductThinkModel(Long id) { - return productThinkModelMapper.selectById(id); + public IotProductThingModelDO getProductThingModel(Long id) { + return productThingModelMapper.selectById(id); } @Override - public List getProductThinkModelListByProductId(Long productId) { - return productThinkModelMapper.selectListByProductId(productId); + public List getProductThingModelListByProductId(Long productId) { + return productThingModelMapper.selectListByProductId(productId); } @Override - public PageResult getProductThinkModelPage(IotProductThinkModelPageReqVO pageReqVO) { - return productThinkModelMapper.selectPage(pageReqVO); + public PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) { + return productThingModelMapper.selectPage(pageReqVO); } @Override @@ -192,15 +189,15 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ IotProductDO product = productService.getProduct(productId); // 2. 查询产品的物模型功能列表 - List functionList = productThinkModelMapper.selectListByProductId(productId); + List thingModelList = productThingModelMapper.selectListByProductId(productId); // 3. 生成 TDengine 的数据模型 - dbStructureDataService.createSuperTableDataModel(product, functionList); + dbStructureDataService.createSuperTableDataModel(product, thingModelList); } @Override - public List getProductThinkModelListByProductKey(String productKey) { - return productThinkModelMapper.selectListByProductKey(productKey); + public List getProductThingModelListByProductKey(String productKey) { + return productThingModelMapper.selectListByProductKey(productKey); } /** @@ -208,124 +205,124 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ */ public void createDefaultEventsAndServices(Long productId, String productKey) { // 1. 获取当前属性列表 - List propertyList = productThinkModelMapper - .selectListByProductIdAndType(productId, IotProductThinkModelTypeEnum.PROPERTY.getType()); + List propertyList = productThingModelMapper + .selectListByProductIdAndType(productId, IotProductThingModelTypeEnum.PROPERTY.getType()); // 2. 生成新的事件和服务列表 - List newFunctionList = new ArrayList<>(); + List newThingModelList = new ArrayList<>(); // 生成属性上报事件 - ThinkModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); + ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); if (propertyPostEvent != null) { - IotProductThinkModelDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent); - newFunctionList.add(eventFunction); + IotProductThingModelDO eventThingModel = buildEventThingModelDO(productId, productKey, propertyPostEvent); + newThingModelList.add(eventThingModel); } // 生成属性设置服务 - ThinkModelService propertySetService = generatePropertySetService(propertyList); + ThingModelService propertySetService = generatePropertySetService(propertyList); if (propertySetService != null) { - IotProductThinkModelDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService); - newFunctionList.add(setServiceFunction); + IotProductThingModelDO setServiceThingModel = buildServiceThingModelDO(productId, productKey, propertySetService); + newThingModelList.add(setServiceThingModel); } // 生成属性获取服务 - ThinkModelService propertyGetService = generatePropertyGetService(propertyList); + ThingModelService propertyGetService = generatePropertyGetService(propertyList); if (propertyGetService != null) { - IotProductThinkModelDO getServiceFunction = buildServiceFunctionDO(productId, productKey, propertyGetService); - newFunctionList.add(getServiceFunction); + IotProductThingModelDO getServiceThingModel = buildServiceThingModelDO(productId, productKey, propertyGetService); + newThingModelList.add(getServiceThingModel); } // 3. 获取数据库中的默认的旧事件和服务列表 - List oldFunctionList = productThinkModelMapper.selectListByProductIdAndIdentifiersAndTypes( + List oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), - Arrays.asList(IotProductThinkModelTypeEnum.EVENT.getType(), IotProductThinkModelTypeEnum.SERVICE.getType()) + Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) ); // 3.1 使用 diffList 方法比较新旧列表 - List> diffResult = diffList(oldFunctionList, newFunctionList, + List> diffResult = diffList(oldThingModelList, newThingModelList, // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier()) && Objects.equals(oldFunc.getType(), newFunc.getType())); - List createList = diffResult.get(0); // 需要新增的 - List updateList = diffResult.get(1); // 需要更新的 - List deleteList = diffResult.get(2); // 需要删除的 + List createList = diffResult.get(0); // 需要新增的 + List updateList = diffResult.get(1); // 需要更新的 + List deleteList = diffResult.get(2); // 需要删除的 // 3.2 批量执行数据库操作 // 新增数据库中的新事件和服务列表 if (CollUtil.isNotEmpty(createList)) { - productThinkModelMapper.insertBatch(createList); + productThingModelMapper.insertBatch(createList); } // 更新数据库中的事件和服务列表 if (CollUtil.isNotEmpty(updateList)) { // 首先,为每个需要更新的对象设置其对应的 ID updateList.forEach(updateFunc -> { - IotProductThinkModelDO oldFunc = findFunctionByIdentifierAndType( - oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType()); + IotProductThingModelDO oldFunc = findThingModelByIdentifierAndType( + oldThingModelList, updateFunc.getIdentifier(), updateFunc.getType()); if (oldFunc != null) { updateFunc.setId(oldFunc.getId()); } }); // 过滤掉没有设置 ID 的对象 - List validUpdateList = updateList.stream() + List validUpdateList = updateList.stream() .filter(func -> func.getId() != null) .collect(Collectors.toList()); // 执行批量更新 if (CollUtil.isNotEmpty(validUpdateList)) { - productThinkModelMapper.updateBatch(validUpdateList); + productThingModelMapper.updateBatch(validUpdateList); } } // 删除数据库中的旧事件和服务列表 if (CollUtil.isNotEmpty(deleteList)) { - Set idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThinkModelDO::getId); - productThinkModelMapper.deleteByIds(idsToDelete); + Set idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThingModelDO::getId); + productThingModelMapper.deleteByIds(idsToDelete); } } /** * 根据标识符和类型查找功能对象 */ - private IotProductThinkModelDO findFunctionByIdentifierAndType(List functionList, - String identifier, Integer type) { - return CollUtil.findOne(functionList, func -> + private IotProductThingModelDO findThingModelByIdentifierAndType(List thingModelList, + String identifier, Integer type) { + return CollUtil.findOne(thingModelList, func -> Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)); } /** * 构建事件功能对象 */ - private IotProductThinkModelDO buildEventFunctionDO(Long productId, String productKey, ThinkModelEvent event) { - return new IotProductThinkModelDO() + private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event) { + return new IotProductThingModelDO() .setProductId(productId) .setProductKey(productKey) .setIdentifier(event.getIdentifier()) .setName(event.getName()) .setDescription(event.getDescription()) - .setType(IotProductThinkModelTypeEnum.EVENT.getType()) + .setType(IotProductThingModelTypeEnum.EVENT.getType()) .setEvent(event); } /** * 构建服务功能对象 */ - private IotProductThinkModelDO buildServiceFunctionDO(Long productId, String productKey, ThinkModelService service) { - return new IotProductThinkModelDO() + private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service) { + return new IotProductThingModelDO() .setProductId(productId) .setProductKey(productKey) .setIdentifier(service.getIdentifier()) .setName(service.getName()) .setDescription(service.getDescription()) - .setType(IotProductThinkModelTypeEnum.SERVICE.getType()) + .setType(IotProductThingModelTypeEnum.SERVICE.getType()) .setService(service); } /** * 生成属性上报事件 */ - private ThinkModelEvent generatePropertyPostEvent(List propertyList) { + private ThingModelEvent generatePropertyPostEvent(List propertyList) { if (CollUtil.isEmpty(propertyList)) { return null; } - ThinkModelEvent event = new ThinkModelEvent() + ThingModelEvent event = new ThingModelEvent() .setIdentifier("post") .setName("属性上报") .setType("info") @@ -333,13 +330,13 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ .setMethod("thing.event.property.post"); // 将属性列表转换为事件的输出参数 - List outputData = new ArrayList<>(); - for (IotProductThinkModelDO thinkModel : propertyList) { - ThinkModelArgument arg = new ThinkModelArgument() - .setIdentifier(thinkModel.getIdentifier()) - .setName(thinkModel.getName()) - .setProperty(thinkModel.getProperty()) - .setDescription(thinkModel.getDescription()) + List outputData = new ArrayList<>(); + for (IotProductThingModelDO thingModel : propertyList) { + ThingModelArgument arg = new ThingModelArgument() + .setIdentifier(thingModel.getIdentifier()) + .setName(thingModel.getName()) + .setProperty(thingModel.getProperty()) + .setDescription(thingModel.getDescription()) .setDirection("output"); // 设置为输出参数 outputData.add(arg); } @@ -350,16 +347,16 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ /** * 生成属性设置服务 */ - private ThinkModelService generatePropertySetService(List propertyList) { + private ThingModelService generatePropertySetService(List propertyList) { if (propertyList == null || propertyList.isEmpty()) { return null; } - List inputData = new ArrayList<>(); - for (IotProductThinkModelDO thinkModel : propertyList) { - ThinkModelProperty property = thinkModel.getProperty(); - if (IotProductThinkModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { - ThinkModelArgument arg = new ThinkModelArgument() + List inputData = new ArrayList<>(); + for (IotProductThingModelDO thingModel : propertyList) { + ThingModelProperty property = thingModel.getProperty(); + if (IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { + ThingModelArgument arg = new ThingModelArgument() .setIdentifier(property.getIdentifier()) .setName(property.getName()) .setProperty(property) @@ -374,7 +371,7 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ } // 属性设置服务一般不需要输出参数 - return new ThinkModelService() + return new ThingModelService() .setIdentifier("set") .setName("属性设置") .setCallType("async") @@ -388,17 +385,17 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ /** * 生成属性获取服务 */ - private ThinkModelService generatePropertyGetService(List propertyList) { + private ThingModelService generatePropertyGetService(List propertyList) { if (propertyList == null || propertyList.isEmpty()) { return null; } - List outputData = new ArrayList<>(); - for (IotProductThinkModelDO functionDO : propertyList) { - ThinkModelProperty property = functionDO.getProperty(); + List outputData = new ArrayList<>(); + for (IotProductThingModelDO thingModelDO : propertyList) { + ThingModelProperty property = thingModelDO.getProperty(); if (ObjectUtils.equalsAny(property.getAccessMode(), - IotProductThinkModelAccessModeEnum.READ_ONLY.getMode(), IotProductThinkModelAccessModeEnum.READ_WRITE.getMode())) { - ThinkModelArgument arg = new ThinkModelArgument() + IotProductThingModelAccessModeEnum.READ_ONLY.getMode(), IotProductThingModelAccessModeEnum.READ_WRITE.getMode())) { + ThingModelArgument arg = new ThingModelArgument() .setIdentifier(property.getIdentifier()) .setName(property.getName()) .setProperty(property) @@ -412,7 +409,7 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ return null; } - ThinkModelService service = new ThinkModelService() + ThingModelService service = new ThingModelService() .setIdentifier("get") .setName("属性获取") .setCallType("async") @@ -420,21 +417,21 @@ public class IotProductThinkModelServiceImpl implements IotProductThinkModelServ .setMethod("thing.service.property.get"); // 定义输入参数:属性标识符列表 - ThinkModelArgument inputArg = new ThinkModelArgument() + ThingModelArgument inputArg = new ThingModelArgument() .setIdentifier("properties") .setName("属性标识符列表") .setDescription("需要获取的属性标识符列表") .setDirection("input"); // 设置为输入参数 // 创建数组类型,元素类型为文本类型(字符串)TODO @puhui999: 还得研究研究 - ThinkModelArrayDataSpecs arrayType = new ThinkModelArrayDataSpecs(); + ThingModelArrayDataSpecs arrayType = new ThingModelArrayDataSpecs(); arrayType.setDataType("array"); - inputArg.setProperty(new ThinkModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) + inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) .setDescription(inputArg.getDescription()).setDataSpecs(arrayType)); - ThinkModelDateOrTextDataSpecs textType = new ThinkModelDateOrTextDataSpecs(); + ThingModelDateOrTextDataSpecs textType = new ThingModelDateOrTextDataSpecs(); textType.setDataType("text"); - inputArg.setProperty(new ThinkModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) + inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) .setDescription(inputArg.getDescription()).setDataSpecs(textType)); service.setInputData(Collections.singletonList(inputArg)); From 067130ecde7211d2063ba0e2a83e03daf7ab9e5e Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Thu, 19 Dec 2024 16:43:56 +0800 Subject: [PATCH 040/228] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E7=89=A9?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=97=A5=E5=BF=97=E5=BB=BA=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/enums/IotConstants.java | 7 ++ .../model/dataType/ThinkModelArgument.java | 2 + .../tdengine/ThinkModelMessageDO.java | 66 +++++++++++++++++++ .../tdengine/TdThinkModelMessageMapper.java | 29 ++++++++ .../simulatesend/SimulateSendProducer.java | 20 ++++++ .../product/IotProductServiceImpl.java | 10 ++- .../tdengine/IotThinkModelMessageService.java | 8 +++ .../IotThinkModelMessageServiceImpl.java | 61 +++++++++++++++-- .../module/iot/util/IotTdDatabaseUtils.java | 63 ++++++++++++++++++ .../tdengine/TdThinkModelMessageMapper.xml | 34 ++++++++++ 10 files changed, 292 insertions(+), 8 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java index 5927f44b9..0762ade9d 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java @@ -35,4 +35,11 @@ public interface IotConstants { */ String DEVICE_STABLE_NAME_FORMAT = "device_%s"; + /** + * 获取物模型消息记录设备名 + *

+ * 格式为 thing_model_message_{productKey}_{deviceName} + */ + String THINK_MODEL_MESSAGE_TABLE_NAME_FORMAT = "thing_model_message_%s_%s"; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java index 7b293ca79..2ed260fde 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodel/model/dataType/ThinkModelArgument.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.dataType; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @Data +@JsonIgnoreProperties(ignoreUnknown = true) public class ThinkModelArgument { public static final String DIRECTION_INPUT = "input"; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java new file mode 100644 index 000000000..13309c81e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.xmlbeans.impl.xb.xsdschema.Public; + + +/** + * TD 物模型消息日志的数据库 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ThinkModelMessageDO { + /** + * 数据库名称 + */ + private String dataBaseName; + + // TODO @haohao:superTableName 和 tableName 是不是合并。因为每个 mapper 操作的时候,有且只会使用到其中一个。 + /** + * 超级表名称 + */ + private String superTableName; + + /** + * 表名称 + */ + private String tableName; + + /** + * 消息ID + */ + private String id; + + /** + * 扩展功能的参数 + */ + private Object sys; + + /** + * 请求方法 例如:thing.event.property.post + */ + private String method; + + /** + * 请求参数 + */ + private Object params; + + /** + * 属性上报时间戳 + */ + private Long time; + + + /** + * 设备 key + */ + private String deviceKey; + + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java new file mode 100644 index 000000000..4eb59975d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessageDO; +import com.baomidou.dynamic.datasource.annotation.DS; +import org.apache.ibatis.annotations.Mapper; + +/** + * 处理 TD 中物模型消息日志的操作 + */ +@Mapper +@DS("tdengine") +public interface TdThinkModelMessageMapper { + + /** + * 创建物模型消息日志超级表超级表 + * + */ + @TenantIgnore + void createSuperTable(ThinkModelMessageDO superTable); + + /** + * 创建子表 + * + */ + @TenantIgnore + void createTableWithTag(ThinkModelMessageDO table); +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java new file mode 100644 index 000000000..76cde71be --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.mq.producer.simulatesend; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * SimulateSend 模拟设备上报的 Producer + * + * @author alwayssuper + * @since 2024/12/17 16:35 + */ +@Slf4j +@Component +public class SimulateSendProducer { + @Resource + private ApplicationContext applicationContext; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index b26c2c123..f26c96452 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; +import cn.iocoder.yudao.module.iot.service.tdengine.IotThinkModelMessageService; import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; @@ -31,11 +32,12 @@ public class IotProductServiceImpl implements IotProductService { @Resource private IotProductMapper productMapper; - @Resource @Lazy private IotProductThinkModelService thinkModelFunctionService; - + @Resource + @Lazy + private IotThinkModelMessageService thinkModelMessageService; @Override public Long createProduct(IotProductSaveReqVO createReqVO) { // 1. 生成 ProductKey @@ -114,8 +116,10 @@ public class IotProductServiceImpl implements IotProductService { IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); // 3. 产品是发布状态 if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { - // 3.1 创建超级表数据模型 + // 3.1 创建产品超级表数据模型 thinkModelFunctionService.createSuperTableDataModel(id); + // 3.2 创建物模型日志超级表数据模型 + thinkModelMessageService.createSuperTable(id); } productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java index 67ee2b99a..67df7045f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageService.java @@ -15,4 +15,12 @@ public interface IotThinkModelMessageService { * @param thingModelMessage 物模型消息 */ void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage); + + /** + * 创建物模型消息日志超级表 + * + * @param productId 产品编号 + */ + void createSuperTable(Long productId); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java index 3c2debfa4..3c6059f99 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThinkModelMessageServiceImpl.java @@ -7,19 +7,20 @@ import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdThinkModelMessageMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.thinkmodel.IotProductThinkModelTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; +import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -54,19 +55,29 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ private TdEngineDDLMapper tdEngineDDLMapper; @Resource private TdEngineDMLMapper tdEngineDMLMapper; - + @Resource + private IotProductService productService; @Resource private DeviceDataRedisDAO deviceDataRedisDAO; + @Resource + private IotTdDatabaseUtils iotTdDatabaseUtils; + + @Resource + private TdThinkModelMessageMapper tdThinkModelMessageMapper; + // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 @Override @TenantIgnore public void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage) { // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { + // 1.1 创建设备表 createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); + // 1.2 创建物模型日志设备表 + createThinkModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); } // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 @@ -90,6 +101,22 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ .build()); } + @Override + @TenantIgnore + public void createSuperTable(Long productId) { + // 1. 查询产品 + IotProductDO product = productService.getProduct(productId); + + // 2. 获取超级表的名称和数据库名称 + String databaseName = iotTdDatabaseUtils.getDatabaseName(); + String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(product.getProductKey()); + + // 3. 创建超级表 + tdThinkModelMessageMapper.createSuperTable(ThinkModelMessageDO.builder().build() + .setDataBaseName(databaseName) + .setSuperTableName(superTableName)); + } + private List getValidFunctionList(String productKey) { return iotProductThinkModelService .getProductThinkModelListByProductKey(productKey) @@ -188,6 +215,30 @@ public class IotThinkModelMessageServiceImpl implements IotThinkModelMessageServ .setTags(tagsFieldValues)); } + /** + * 创建物模型日志设备数据表 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @param deviceKey 设备 Key + * + */ + private void createThinkModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){ + + // 1. 获取超级表的名称、数据库名称、设备日志表名称 + String databaseName = iotTdDatabaseUtils.getDatabaseName(); + String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(productKey); + String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThinkModelMessageDeviceTableName(productKey, deviceName); + + // 2. 创建物模型日志设备数据表 + tdThinkModelMessageMapper.createTableWithTag(ThinkModelMessageDO.builder().build() + .setDataBaseName(databaseName) + .setSuperTableName(superTableName) + .setTableName(thinkModelMessageDeviceTableName) + .setDeviceKey(deviceKey)); + + } + /** * 获取数据库名称 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java new file mode 100644 index 000000000..b928ec716 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.iot.util; + +import cn.iocoder.yudao.module.iot.enums.IotConstants; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * TD数据库工具类 + * + * @author AlwaysSuper + */ +@Component +public class IotTdDatabaseUtils { + + @Value("${spring.datasource.dynamic.datasource.tdengine.url}") + private String url; + + /** + * 获取数据库名称 + */ + public String getDatabaseName() { + int index = url.lastIndexOf("/"); + return index != -1 ? url.substring(index + 1) : url; + } + + /** + * 获取产品超级表表名 + * + * @param deviceType 设备类型 + * @param productKey 产品 Key + * @return 产品超级表表名 + */ + public static String getProductSuperTableName(Integer deviceType, String productKey) { + return switch (deviceType) { + case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); + case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); + default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); + }; + } + + /** + * 获取物模型日志超级表表名 + * + * @param productKey 产品 Key + * @return 物模型日志超级表表名 + * + */ + public static String getThinkModelMessageSuperTableName(String productKey) { + return String.format("thing_model_message_", productKey).toLowerCase(); + } + + /** + * 获取物模型日志设备表名 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 物模型日志设备表名 + */ + public static String getThinkModelMessageDeviceTableName(String productKey, String deviceName) { + return String.format(IotConstants.THINK_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml new file mode 100644 index 000000000..476ca97ab --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + CREATE STABLE ${dataBaseName}.${superTableName}( + ts TIMESTAMP, + id VARCHAR(255), + sys VARCHAR(2048), + method VARCHAR(255), + params VARCHAR(2048) + )TAGS ( + deviceKey VARCHAR(255) + ) + + + + + CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} + USING ${dataBaseName}.${superTableName}( + ts, + id , + sys , + method , + params + )TAGS( + #{deviceKey} + ) + + \ No newline at end of file From caa7198e8a0d384df1c24c3e2d616e086d4eadfa Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 19 Dec 2024 21:02:36 +0800 Subject: [PATCH 041/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E8=AF=84=E5=AE=A1=20ThingModel?= =?UTF-8?q?=20=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/dal/dataobject/tdengine/FieldParser.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index 637b2228b..9157920e0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -34,11 +34,9 @@ public class FieldParser { * @return TdField对象 */ public static TdFieldDO parse(ThingModelProperty property) { + // 将物模型字段类型映射为 td 字段类型 String fieldName = property.getIdentifier().toLowerCase(); - - // 将物模型字段类型映射为td字段类型 String fType = TYPE_MAPPING.get(property.getDataType().toUpperCase()); - // 如果字段类型为NCHAR,默认长度为64 int dataLength = 0; if ("NCHAR".equals(fType)) { @@ -54,6 +52,7 @@ public class FieldParser { * @return 字段列表 */ public static List parse(ThingModelRespVO thingModel) { + // TODO @puhui999:是不是使用 convertList return thingModel.getModel().getProperties().stream() .map(FieldParser::parse) .collect(Collectors.toList()); @@ -66,14 +65,12 @@ public class FieldParser { * @return 转换后的 TDengine 字段对象列表 */ public static List parse(List> rows) { + // TODO @puhui999:是不是使用 convertList return rows.stream().map(row -> { String type = row.get(1).toString().toUpperCase(); + // TODO @puhui999:"NCHAR" 最好枚举下 int dataLength = "NCHAR".equals(type) ? Integer.parseInt(row.get(2).toString()) : -1; - return new TdFieldDO( - row.get(0).toString(), - type, - dataLength - ); + return new TdFieldDO(row.get(0).toString(), type, dataLength); }).collect(Collectors.toList()); } From 95067fd6c60da1f3d511bdaafc6100c4bf0e3593 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 19 Dec 2024 21:12:07 +0800 Subject: [PATCH 042/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E8=AF=84=E5=AE=A1=20ThingModel?= =?UTF-8?q?=20=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/vo/device/IotDevicePageReqVO.java | 4 ---- .../model/dataType/ThingModelArgument.java | 3 +-- .../iot/dal/tdengine/TdThinkModelMessageMapper.java | 1 - .../iot/service/product/IotProductServiceImpl.java | 12 ++++++------ .../tdengine/IotThingModelMessageService.java | 4 ++-- .../tdengine/IotThingModelMessageServiceImpl.java | 13 +++++++------ 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java index 791ee34b6..dcea2b0ba 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java @@ -6,13 +6,9 @@ import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; @Schema(description = "管理后台 - IoT 设备分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class IotDevicePageReqVO extends PageParam { @Schema(description = "设备名称", example = "王五") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java index 94c4b83d5..96f51150f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java @@ -1,13 +1,12 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodel.model.ThinkModelProperty; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) -public class ThinkModelArgument { +public class ThingModelArgument { public static final String DIRECTION_INPUT = "input"; public static final String DIRECTION_OUTPUT = "output"; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java index 4eb59975d..90f66d508 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessageDO; import com.baomidou.dynamic.datasource.annotation.DS; import org.apache.ibatis.annotations.Mapper; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index dba26352b..a53aee55d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -7,8 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.service.tdengine.IotThinkModelMessageService; -import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; +import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; @@ -35,10 +35,10 @@ public class IotProductServiceImpl implements IotProductService { @Resource @Lazy // 延迟加载,解决循环依赖 - private IotProductThinkModelService thinkModelFunctionService; + private IotProductThingModelService thingModelFunctionService; @Resource @Lazy // 延迟加载,解决循环依赖 - private IotThinkModelMessageService thinkModelMessageService; + private IotThingModelMessageService thingModelMessageService; @Override public Long createProduct(IotProductSaveReqVO createReqVO) { @@ -119,9 +119,9 @@ public class IotProductServiceImpl implements IotProductService { // 3. 产品是发布状态 if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { // 3.1 创建产品超级表数据模型 - thinkModelFunctionService.createSuperTableDataModel(id); + thingModelFunctionService.createSuperTableDataModel(id); // 3.2 创建物模型日志超级表数据模型 - thinkModelMessageService.createSuperTable(id); + thingModelMessageService.createSuperTable(id); } productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java index 76b3dfe32..ab77eb91a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.tdengine; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; /** * 物模型消息 Service @@ -14,7 +14,7 @@ public interface IotThingModelMessageService { * @param device 设备 * @param thingModelMessage 物模型消息 */ - void saveThinkModelMessage(IotDeviceDO device, ThinkModelMessage thingModelMessage); + void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); /** * 创建物模型消息日志超级表 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 587062891..9ea237ce8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -14,7 +14,6 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodel.IotProductThinkModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; @@ -25,7 +24,6 @@ import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; -import cn.iocoder.yudao.module.iot.service.thinkmodel.IotProductThinkModelService; import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -112,6 +110,8 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ private List getValidThingModelList(String productKey) { return filterList(iotProductThingModelService.getProductThingModelListByProductKey(productKey), thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); + } + @Override @TenantIgnore public void createSuperTable(Long productId) { @@ -128,11 +128,12 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ .setSuperTableName(superTableName)); } - private List getValidFunctionList(String productKey) { - return iotProductThinkModelService - .getProductThinkModelListByProductKey(productKey) + private List getValidFunctionList(String productKey) { + // TODO @puhui999:使用 convertList 会好点哈 + return iotProductThingModelService + .getProductThingModelListByProductKey(productKey) .stream() - .filter(function -> IotProductThinkModelTypeEnum.PROPERTY.getType().equals(function.getType())) + .filter(function -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(function.getType())) .toList(); } From b2434b7b41b52aefff1de1412f0ebea0064524f1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 19 Dec 2024 21:23:07 +0800 Subject: [PATCH 043/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=A8=A1=E6=8B=9F=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=8F=91=E9=80=81=E7=9A=84=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/enums/IotConstants.java | 2 +- ...lMessageDO.java => ThingModelMessageDO.java} | 14 +++++++------- .../dal/tdengine/TdThinkModelMessageMapper.java | 7 ++++--- .../simulatesend/SimulateSendProducer.java | 2 ++ .../service/product/IotProductServiceImpl.java | 2 +- .../IotThingModelMessageServiceImpl.java | 17 ++++++++++------- .../module/iot/util/IotTdDatabaseUtils.java | 11 ++++++++--- .../tdengine/TdThinkModelMessageMapper.xml | 14 +++++++------- 8 files changed, 40 insertions(+), 29 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/{ThinkModelMessageDO.java => ThingModelMessageDO.java} (85%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java index 0762ade9d..631ca24a3 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java @@ -40,6 +40,6 @@ public interface IotConstants { *

* 格式为 thing_model_message_{productKey}_{deviceName} */ - String THINK_MODEL_MESSAGE_TABLE_NAME_FORMAT = "thing_model_message_%s_%s"; + String THING_MODEL_MESSAGE_TABLE_NAME_FORMAT = "thing_model_message_%s_%s"; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java index 13309c81e..c57ec1c7b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThinkModelMessageDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java @@ -4,9 +4,8 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.apache.xmlbeans.impl.xb.xsdschema.Public; - +// TODO @芋艿:纠结下字段 /** * TD 物模型消息日志的数据库 */ @@ -14,7 +13,8 @@ import org.apache.xmlbeans.impl.xb.xsdschema.Public; @Builder @NoArgsConstructor @AllArgsConstructor -public class ThinkModelMessageDO { +public class ThingModelMessageDO { + /** * 数据库名称 */ @@ -32,7 +32,7 @@ public class ThinkModelMessageDO { private String tableName; /** - * 消息ID + * 消息 ID */ private String id; @@ -42,7 +42,9 @@ public class ThinkModelMessageDO { private Object sys; /** - * 请求方法 例如:thing.event.property.post + * 请求方法 + * + * 例如:thing.event.property.post */ private String method; @@ -56,11 +58,9 @@ public class ThinkModelMessageDO { */ private Long time; - /** * 设备 key */ private String deviceKey; - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java index 90f66d508..da9730e74 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThinkModelMessageDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessageDO; import com.baomidou.dynamic.datasource.annotation.DS; import org.apache.ibatis.annotations.Mapper; @@ -17,12 +17,13 @@ public interface TdThinkModelMessageMapper { * */ @TenantIgnore - void createSuperTable(ThinkModelMessageDO superTable); + void createSuperTable(ThingModelMessageDO superTable); /** * 创建子表 * */ @TenantIgnore - void createTableWithTag(ThinkModelMessageDO table); + void createTableWithTag(ThingModelMessageDO table); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java index 76cde71be..411ddd6f2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; +// TODO @alwayssuper:是不是还没用起来哈?Producer 最好属于某个模块; /** * SimulateSend 模拟设备上报的 Producer * @@ -14,6 +15,7 @@ import org.springframework.stereotype.Component; @Slf4j @Component public class SimulateSendProducer { + @Resource private ApplicationContext applicationContext; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index a53aee55d..628805a97 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -122,7 +122,7 @@ public class IotProductServiceImpl implements IotProductService { thingModelFunctionService.createSuperTableDataModel(id); // 3.2 创建物模型日志超级表数据模型 thingModelMessageService.createSuperTable(id); - } + }x productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 9ea237ce8..454a2e072 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -57,12 +57,14 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ private IotProductThingModelService iotProductThingModelService; @Resource private IotDeviceService iotDeviceService; + @Resource + private IotProductService productService; + @Resource private TdEngineDDLMapper tdEngineDDLMapper; @Resource private TdEngineDMLMapper tdEngineDMLMapper; - @Resource - private IotProductService productService; + @Resource private DeviceDataRedisDAO deviceDataRedisDAO; @@ -119,11 +121,12 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ IotProductDO product = productService.getProduct(productId); // 2. 获取超级表的名称和数据库名称 + // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 String databaseName = iotTdDatabaseUtils.getDatabaseName(); - String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(product.getProductKey()); + String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey()); // 3. 创建超级表 - tdThinkModelMessageMapper.createSuperTable(ThinkModelMessageDO.builder().build() + tdThinkModelMessageMapper.createSuperTable(ThingModelMessageDO.builder().build() .setDataBaseName(databaseName) .setSuperTableName(superTableName)); } @@ -238,16 +241,16 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 1. 获取超级表的名称、数据库名称、设备日志表名称 String databaseName = iotTdDatabaseUtils.getDatabaseName(); - String superTableName = IotTdDatabaseUtils.getThinkModelMessageSuperTableName(productKey); + String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(productKey); + // TODO @alwayssuper:最好 databaseName、superTableName、thinkModelMessageDeviceTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThinkModelMessageDeviceTableName(productKey, deviceName); // 2. 创建物模型日志设备数据表 - tdThinkModelMessageMapper.createTableWithTag(ThinkModelMessageDO.builder().build() + tdThinkModelMessageMapper.createTableWithTag(ThingModelMessageDO.builder().build() .setDataBaseName(databaseName) .setSuperTableName(superTableName) .setTableName(thinkModelMessageDeviceTableName) .setDeviceKey(deviceKey)); - } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java index b928ec716..8feef7bf6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java @@ -4,8 +4,10 @@ import cn.iocoder.yudao.module.iot.enums.IotConstants; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +// TODO @芋艿:可能要思索下,有没更好的处理方式 +// TODO @芋艿:怎么改成无状态 /** - * TD数据库工具类 + * TD 数据库工具类 * * @author AlwaysSuper */ @@ -19,6 +21,7 @@ public class IotTdDatabaseUtils { * 获取数据库名称 */ public String getDatabaseName() { +// TODO @alwayssuper:StrUtil.subAfter("/") int index = url.lastIndexOf("/"); return index != -1 ? url.substring(index + 1) : url; } @@ -31,6 +34,7 @@ public class IotTdDatabaseUtils { * @return 产品超级表表名 */ public static String getProductSuperTableName(Integer deviceType, String productKey) { + // TODO @alwayssuper:枚举字段,不要 1、2、3;不符合预期,抛出异常 return switch (deviceType) { case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); @@ -45,7 +49,8 @@ public class IotTdDatabaseUtils { * @return 物模型日志超级表表名 * */ - public static String getThinkModelMessageSuperTableName(String productKey) { + public static String getThingModelMessageSuperTableName(String productKey) { + // TODO @alwayssuper:是不是应该 + 拼接就好,不用 format return String.format("thing_model_message_", productKey).toLowerCase(); } @@ -57,7 +62,7 @@ public class IotTdDatabaseUtils { * @return 物模型日志设备表名 */ public static String getThinkModelMessageDeviceTableName(String productKey, String deviceName) { - return String.format(IotConstants.THINK_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); + return String.format(IotConstants.THING_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml index 476ca97ab..aeecd5dc1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml @@ -4,17 +4,17 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + CREATE STABLE ${dataBaseName}.${superTableName}( - ts TIMESTAMP, - id VARCHAR(255), - sys VARCHAR(2048), - method VARCHAR(255), - params VARCHAR(2048) + ts TIMESTAMP, + id VARCHAR(255), + sys VARCHAR(2048), + method VARCHAR(255), + params VARCHAR(2048) )TAGS ( - deviceKey VARCHAR(255) + deviceKey VARCHAR(255) ) From 767a26dd705df1bedc9aaf9001d14902d8e3791c Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 20 Dec 2024 10:18:02 +0800 Subject: [PATCH 044/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IOT:=20ThingModel=20=E8=AF=84=E5=AE=A1?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/dataobject/tdengine/FieldParser.java | 13 +++++-------- .../product/IotProductServiceImpl.java | 2 +- .../IotThingModelMessageServiceImpl.java | 19 +++++-------------- .../IotProductThingModelServiceImpl.java | 6 ++---- 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index 9157920e0..d62781779 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java @@ -5,7 +5,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelR import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; /** * FieldParser 类用于解析和转换物模型字段到 TDengine 字段 @@ -52,10 +53,7 @@ public class FieldParser { * @return 字段列表 */ public static List parse(ThingModelRespVO thingModel) { - // TODO @puhui999:是不是使用 convertList - return thingModel.getModel().getProperties().stream() - .map(FieldParser::parse) - .collect(Collectors.toList()); + return convertList(thingModel.getModel().getProperties(), FieldParser::parse); } /** @@ -65,13 +63,12 @@ public class FieldParser { * @return 转换后的 TDengine 字段对象列表 */ public static List parse(List> rows) { - // TODO @puhui999:是不是使用 convertList - return rows.stream().map(row -> { + return convertList(rows, row -> { String type = row.get(1).toString().toUpperCase(); // TODO @puhui999:"NCHAR" 最好枚举下 int dataLength = "NCHAR".equals(type) ? Integer.parseInt(row.get(2).toString()) : -1; return new TdFieldDO(row.get(0).toString(), type, dataLength); - }).collect(Collectors.toList()); + }); } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 628805a97..a53aee55d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -122,7 +122,7 @@ public class IotProductServiceImpl implements IotProductService { thingModelFunctionService.createSuperTableDataModel(id); // 3.2 创建物模型日志超级表数据模型 thingModelMessageService.createSuperTable(id); - }x + } productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 454a2e072..568cad502 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -7,13 +7,9 @@ import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; @@ -22,8 +18,8 @@ import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -132,12 +128,8 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ } private List getValidFunctionList(String productKey) { - // TODO @puhui999:使用 convertList 会好点哈 - return iotProductThingModelService - .getProductThingModelListByProductKey(productKey) - .stream() - .filter(function -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(function.getType())) - .toList(); + return filterList(iotProductThingModelService.getProductThingModelListByProductKey(productKey), + thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); } private List filterAndCollectValidFields(Map params, List thingModelList, IotDeviceDO device, Long time) { @@ -235,9 +227,8 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * @param productKey 产品 Key * @param deviceName 设备名称 * @param deviceKey 设备 Key - * */ - private void createThinkModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){ + private void createThinkModelMessageDeviceTable(String productKey, String deviceName, String deviceKey) { // 1. 获取超级表的名称、数据库名称、设备日志表名称 String databaseName = iotTdDatabaseUtils.getDatabaseName(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java index b5c2d4eee..ddb800eee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java @@ -29,10 +29,10 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; -import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; /** @@ -261,9 +261,7 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } }); // 过滤掉没有设置 ID 的对象 - List validUpdateList = updateList.stream() - .filter(func -> func.getId() != null) - .collect(Collectors.toList()); + List validUpdateList = filterList(updateList, thingModel -> thingModel.getId() != null); // 执行批量更新 if (CollUtil.isNotEmpty(validUpdateList)) { productThingModelMapper.updateBatch(validUpdateList); From 8ff09fea018acc63b107430fe4a5c7ca1ffbed5c Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Fri, 20 Dec 2024 14:44:46 +0800 Subject: [PATCH 045/228] =?UTF-8?q?[=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96]?= =?UTF-8?q?=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=97=A5=E5=BF=97=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../product/IotProductDeviceTypeEnum.java | 2 +- ...er.java => TdThingModelMessageMapper.java} | 2 +- .../simulatesend/SimulateSendConsumer.java | 8 ++++ .../IotThingModelMessageServiceImpl.java | 43 ++++++++++--------- .../module/iot/util/IotTdDatabaseUtils.java | 36 ++++++++++------ .../tdengine/TdThinkModelMessageMapper.xml | 6 +-- 7 files changed, 59 insertions(+), 39 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/{TdThinkModelMessageMapper.java => TdThingModelMessageMapper.java} (93%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 4539f1259..a763924b5 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -14,6 +14,7 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); + ErrorCode PRODUCT_DEVICE_NOT_EXISTS = new ErrorCode(1_050_001_004, "产品设备类型不存在"); // ========== 产品物模型 1-050-002-000 ============ ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java index ef1432804..8a5aaf74b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java @@ -16,7 +16,7 @@ import java.util.Arrays; public enum IotProductDeviceTypeEnum implements IntArrayValuable { DIRECT(0, "直连设备"), - GATEWAY_CHILD(1, "网关子设备"), + GATEWAY_SUB(1, "网关子设备"), GATEWAY(2, "网关设备"); /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java similarity index 93% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java index da9730e74..0a735be03 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThinkModelMessageMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java @@ -10,7 +10,7 @@ import org.apache.ibatis.annotations.Mapper; */ @Mapper @DS("tdengine") -public interface TdThinkModelMessageMapper { +public interface TdThingModelMessageMapper { /** * 创建物模型消息日志超级表超级表 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java new file mode 100644 index 000000000..dfc911df5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java @@ -0,0 +1,8 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.simulatesend; + +/** + * @author alwayssuper + * @date 2024/12/20 8:04 + */ +public class SimulateSendConsumer { +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 454a2e072..87bf01d26 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -13,11 +13,9 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdThinkModelMessageMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; @@ -68,11 +66,6 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Resource private DeviceDataRedisDAO deviceDataRedisDAO; - @Resource - private IotTdDatabaseUtils iotTdDatabaseUtils; - - @Resource - private TdThinkModelMessageMapper tdThinkModelMessageMapper; // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 @Override @@ -85,7 +78,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); // 1.2 创建物模型日志设备表 - createThinkModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); + createThingModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); } // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 @@ -122,13 +115,23 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 2. 获取超级表的名称和数据库名称 // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 - String databaseName = iotTdDatabaseUtils.getDatabaseName(); + String databaseName = IotTdDatabaseUtils.getDatabaseName(url); String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey()); + // 解析物模型,获取字段列表 + List schemaFields = List.of( + TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(), + TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(), + TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(), + TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(), + TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build() + ); + // 设置超级表的标签 + List tagsFields = List.of( + TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build() + ); // 3. 创建超级表 - tdThinkModelMessageMapper.createSuperTable(ThingModelMessageDO.builder().build() - .setDataBaseName(databaseName) - .setSuperTableName(superTableName)); + tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); } private List getValidFunctionList(String productKey) { @@ -237,20 +240,20 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * @param deviceKey 设备 Key * */ - private void createThinkModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){ + private void createThingModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){ // 1. 获取超级表的名称、数据库名称、设备日志表名称 - String databaseName = iotTdDatabaseUtils.getDatabaseName(); + String databaseName = IotTdDatabaseUtils.getDatabaseName(url); String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(productKey); // TODO @alwayssuper:最好 databaseName、superTableName、thinkModelMessageDeviceTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 - String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThinkModelMessageDeviceTableName(productKey, deviceName); + String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThingModelMessageDeviceTableName(productKey, deviceName); // 2. 创建物模型日志设备数据表 - tdThinkModelMessageMapper.createTableWithTag(ThingModelMessageDO.builder().build() - .setDataBaseName(databaseName) - .setSuperTableName(superTableName) - .setTableName(thinkModelMessageDeviceTableName) - .setDeviceKey(deviceKey)); +// tdThingModelMessageMapper.createTableWithTag(ThingModelMessageDO.builder().build() +// .setDataBaseName(databaseName) +// .setSuperTableName(superTableName) +// .setTableName(thinkModelMessageDeviceTableName) +// .setDeviceKey(deviceKey)); } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java index 8feef7bf6..e4ecf7465 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java @@ -1,9 +1,14 @@ package cn.iocoder.yudao.module.iot.util; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.enums.IotConstants; +import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_DEVICE_NOT_EXISTS; + // TODO @芋艿:可能要思索下,有没更好的处理方式 // TODO @芋艿:怎么改成无状态 /** @@ -11,19 +16,14 @@ import org.springframework.stereotype.Component; * * @author AlwaysSuper */ -@Component public class IotTdDatabaseUtils { - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") - private String url; - /** * 获取数据库名称 */ - public String getDatabaseName() { + public static String getDatabaseName(String url) { // TODO @alwayssuper:StrUtil.subAfter("/") - int index = url.lastIndexOf("/"); - return index != -1 ? url.substring(index + 1) : url; + return StrUtil.subAfter(url, "/", true); } /** @@ -35,11 +35,19 @@ public class IotTdDatabaseUtils { */ public static String getProductSuperTableName(Integer deviceType, String productKey) { // TODO @alwayssuper:枚举字段,不要 1、2、3;不符合预期,抛出异常 - return switch (deviceType) { - case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); - case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); - default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); - }; + if (deviceType == null) { + throw exception(PRODUCT_DEVICE_NOT_EXISTS); + } + if (IotProductDeviceTypeEnum.GATEWAY_SUB.getType().equals(deviceType)) { + return String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); + } else if (IotProductDeviceTypeEnum.GATEWAY.getType().equals(deviceType)) { + return String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); + } else if (IotProductDeviceTypeEnum.DIRECT.getType().equals(deviceType)){ + return String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); + } + else{ + throw exception(PRODUCT_DEVICE_NOT_EXISTS); + } } /** @@ -51,7 +59,7 @@ public class IotTdDatabaseUtils { */ public static String getThingModelMessageSuperTableName(String productKey) { // TODO @alwayssuper:是不是应该 + 拼接就好,不用 format - return String.format("thing_model_message_", productKey).toLowerCase(); + return "thing_model_message_" + productKey.toLowerCase(); } /** @@ -61,7 +69,7 @@ public class IotTdDatabaseUtils { * @param deviceName 设备名称 * @return 物模型日志设备表名 */ - public static String getThinkModelMessageDeviceTableName(String productKey, String deviceName) { + public static String getThingModelMessageDeviceTableName(String productKey, String deviceName) { return String.format(IotConstants.THING_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml index aeecd5dc1..074ae9884 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml @@ -2,7 +2,7 @@ - + @@ -14,7 +14,7 @@ method VARCHAR(255), params VARCHAR(2048) )TAGS ( - deviceKey VARCHAR(255) + device_key VARCHAR(255) ) @@ -28,7 +28,7 @@ method , params )TAGS( - #{deviceKey} + #{device_key} ) \ No newline at end of file From a2532013ec1ade71362a4361cb37aedb3b5f0519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 20 Dec 2024 18:57:40 +0800 Subject: [PATCH 046/228] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91IoT=EF=BC=9A=20HTTP=20=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/disabled.txt | 0 plugins/enabled.txt | 0 ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 0 -> 9347 bytes yudao-module-iot/pom.xml | 1 - yudao-module-iot/yudao-module-iot-api/pom.xml | 11 ++ .../yudao/module/iot/api/DeviceDataApi.java | 17 ++ .../yudao/module/iot/api/ServiceRegistry.java | 34 ++++ yudao-module-iot/yudao-module-iot-biz/pom.xml | 6 + .../iot/api/device/DeviceDataApiImpl.java | 25 +++ .../yudao/module/iot/api/package-info.java | 1 + .../admin/plugininfo/Greetings.java | 41 ----- .../admin/plugininfo/PluginController.java | 20 +-- .../admin/plugininfo/WhazzupGreeting.java | 34 ---- .../vo/PluginInstanceRespVO.java | 2 - .../vo/PluginInstanceSaveReqVO.java | 1 - .../plugin/ServiceRegistryConfiguration.java | 34 ++++ .../framework/plugin/SpringConfiguration.java | 8 +- .../service/device/IotDeviceDataService.java | 3 +- .../plugininfo/PluginInfoServiceImpl.java | 40 +++-- .../product/IotProductServiceImpl.java | 2 +- .../yudao-module-iot-plugin-api/pom.xml | 30 ---- .../yudao/module/iot/api/Greeting.java | 27 --- .../yudao/module/iot/api/package-info.java | 6 - .../yudao-module-iot-plugin/pom.xml | 24 ++- .../plugin.properties | 6 + .../yudao-module-iot-demo-plugin/pom.xml | 148 ++++++++++++++++ .../src/main/assembly/assembly.xml | 31 ++++ .../yudao/module/iot/plugin/DemoPlugin.java | 77 +++++++++ .../plugin.properties | 1 + .../yudao-module-iot-http-plugin/pom.xml | 96 +++++------ .../src/main/assembly/assembly.xml | 6 - .../yudao/module/iot/plugin/HttpHandler.java | 160 ++++++++++++++++++ .../yudao/module/iot/plugin/HttpPlugin.java | 102 +++++------ 33 files changed, 690 insertions(+), 304 deletions(-) create mode 100644 plugins/disabled.txt create mode 100644 plugins/enabled.txt create mode 100644 plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java diff --git a/plugins/disabled.txt b/plugins/disabled.txt new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/enabled.txt b/plugins/enabled.txt new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar new file mode 100644 index 0000000000000000000000000000000000000000..0300a632ae6d0bd042e974113a7193dc0e578232 GIT binary patch literal 9347 zcmb_h1yo#Fwyoe0q;Qwu?hxGF-8HzoySuxEpuyeU3JVZ4IKd$aZUGYDlSy|oJ?ZJ0 zzy7~#)qAy8oxRV!=heG!zq1vj!6D!PKZbm2vgSX&{C0qSJj;rz2+~Q)i7_br76t>5 zdkj1DpSx{;{2Bil0D$(-VX}g9l47FDD)h2qs&V6ReT=~1u8b%0|P93!ltsecL>XmAOG}VPW%*Dc(oz1f_R{ z;9EuNScbGx?(XiYv})-uWaKz@@%ZvMy?gxS@{*vw#A4^FymNLrKe0P5Ae7-%EVtmD zxtZHtjYg5u`+czhfTQ1^YXbhbSR>m%s_|>U^Pd40c1Cu_CXRm-i2Ub34;N!YyT1v? z`m1moJ7X7XlfOaX{SC^(&iS8^n2CR0D9L|7+FQGrSv(a21|a_Uw?LJJ4HJ2+fa&9G zS^ql%31??}2}4_BYZFI$BWpt^r%DZ2Z?rk=hwgFm`b8O_S`~WSoA4L&VEIB|)WITP zF9M8F2MQeOxFw<3xxb9jCh8G164+F_H@bfyz_1%2@z-i-Y_!z&%3WF#E>N{XI;`A$ z7`H|oHkG{nay(?(^>yuQ*VoPmH@??i4^uvX)Cg}#zJM|f=2z)VELGYGUCufzB%P)_ zIg^~9M3f?&n-iid9J6Ps>9FPZQ^C3gLJY+c+qN!5U-4=&mr@W{irG=;&3hJv8o$ku z8)V^zh}^oxASte%#k27k1%|Wkaw$t=C!~%jy_QlBXj*=rOe%w|n@=Cq;DaiO*eluSiiM7WMKZ*#DGa`S}OHt>~0 z7ZVn{qo|(CAztKvuRQ$M-2$W*M8`q7x}3 zua!WOkDh&t3hUt<B#N>X4_!xHV1uY|iIpvP!PM{yOuWj$2qYU-fn!xdrqK%+54g4M@sF~o|RAlsA?U14iudp2t$ zSniBN6?6nLP8qkst+#&9Q4q+!$+YVUR78VxAfHgGQCvSUTy)Vk@*HIvD~zl+Ie=_; zF{`v))@mkr)y1a{3Y!!h_i7yHIwY9MMhKk|9(8Rf?4L}}Qk|haEm9PGsaCeaSc(%J zPmPWDYyivmdD*V?`&m`z0FJO%sZ|K=yOwK`>zmV|cpTAu*M3I3sq?T>2nI4MLFh0SAd{*kxQE!mQ#9E7yukPxYTkQinoWLtqXFo;c*63W6?Ik>6;u@!wT4Upok}iR zoRBYTJBWqc$yF+h7x7)hcM+iqE{^-_(Vmmb_E)jdMKx)^<>aN6G-Gn!pE`9O(=7Pv zuxi2AE}3Q?w%xe2)tql&4WQYgQTqT#`G}o*eQ@gpgPPUL7ZCQj zDzUP0FX}_h6;AwnB3ki`iq?vzWW(D&>r?Cxdkf&M;Kq1b2pY+hA%x?~-QnZjsZGdWdwPeoQ`WeWmet`jO65uq zUS#TkEGvj{2jmWte7>N9eVTT#;@^lhs5mzm8MPY#8*# zwPU9!49YKMXl(4>hNpZzL)f{pU)$Kdp5F`cV;-+%R>nwXKK@k9m(RxLgbO*e%|@Y2 zD)8MD_R*=YqDBLy)^(7osYVveu$NOuL4w|d{3<6w4%fP3e%L1bDCXS36nI!BsJ*)s z)V|c!Toxx~F)p%ZBI=ULIpnyd`X$$7zMzZ#HvF^<@yr=leLe)yg;-40?>ODq)|_b+ zTbB_H;|Hyj+Frb-yVdgC7SeBpx**o4bJ z#`HnqqaNEt+1{!0aNX(4+k(n|Xj}Udg2g(kZ{?At>4TrtSZqKSp2B>36mjkeYLZmm zAq_aIlCpXt>nl?@+wLBUCesi|kL`&2IUuj2y!o{wR7B_*u9vi-nP zG;HPgr7_(|%ct(!U3Je@!hOcZ6@+Kzq7#m+lM`1;yAPLvQ3FGfnIS*7Hc>Q+VmTQ~ zW%QfOez=qOfHh1?FPpui0NphBm6M(x)vw(hdu0KK-1>{IpdR6u9iB5qWOa_I@GJM% zG;#X6y2RTP<+o2^d+(+0{h&*|r{Ta( z^5P3TeSN+|y>mTRzlVu*bJ*@T{LVeH%8BY5JmLjG?!>yfHHbDG7ExHJ!fvj_+@DF< zeIX$4trskgetvNl*_lp1se;W_M<}lTt^eL93B0+0o|WR@E5pIi3T`c_3dR);fi89# z%r|fXUTziiD|z}8C}rVu&S871d;F8VoNRu&2XYx|8b9E3;izwloiqpU^)+;XSD3UF zYVJp+ft~%4z7=JN!Qft#D!MJ;&&z{Mln0uIfU7OIhs1aXL!sghh(Ioe*~K__mxSbb zRQk_Drs~FqCF&Rb+f8ALc=Rwd8$$GlA&26NXgo>CXo#V=i18;0g0S2QgBettIffH) zNRDNR=lM06oKcgyq2)C(NFcLCmYvhAy`?P++VzhGu%Bx2#IH?r4(bbJcpwyZxOb3OEvXzS;Mqi@nNEoo zEKOdP>0vM3-Ssrow0@;KjuZ$Hf(1U~)7mJ!gV{oE-Vx%SS&3IaB*7(s%*)ob!fP~y z=bU)(6jZW~dP-{PjDs*MP^ksmz-k!vc3gqld}zEyKQn$7v2WL@w9raOa#eKnSm|s0 zs9Whb9aN0zn?gY}%zd_#L$ftFAmfH13kvmhN9*0nOAP6?b)8udi;lp!K#qWo0IvW- zPd!+k=hr+{)rf*SL&iHSXDbF)g=D&PWL$EV~6QMxUi>m(Vg15 z?wB5<@V)K6j6xEf0m?e=^DJd#9m*aNFHb2(Q@+woINj|b+{;0eS8tzb8$Z-%WkJqF zsN_d4pREk&>z$ICUTiV+TVk{f!KfqTwtumszhqx?==K}pzeb4P(!F2n_iYB&1j6PT z)LsLAe}DO@%FVBfS%$#?04^v1fbG9m3j{hMHp@SxT{oPw>P|gKg7(NDd>~DXtz{V#wCEP>yh*B zn$!D?RyW`8-_P)Sh}Ga5m^7NqBtKr^BWr{qgnj$abJ|%DM;=)JtUfixPaG@$w&8_X@;H3}ZQHNRp z;Uh=1X-<@QZ!(oRw!qp^*g>-7In<1Gz z)ei2mTIFWoXAUxka#rq+wtL@kD{%X3{O0!rzML6{r+pVQh+->kCv~7U@{A+24?Rk( zaMxi2TcT?i;5=8OZIEjc`Gms2yL|a&x;)!CB?7Z84b=q%?xGa|zY7I|prNmxhjh`I zFD@x}>8@fFdWlz{9!HjREBZzg*9WR?*mcG_wL&jKUdFdL5B6MnKj}@avO4sc#I$+n zIY$+-=oO9+K0H2QqWO@^N_Y<+N)413w?{M|b+KKGa;y(Xp*135n(3&?aPK&$*3q&f zBI4mlHiaS<$R9X2ur<7qtQC0%CVhdzGlU1X(Ca8se@yBpqWpgMG`U1Pc(1Xy9!MS+ zGD(jD4?{1l5TZcxyz%o#$Nhvm$Uom2?6=wWq%Z&g<>T8p%m4P)_<3XGsC)ULsbl-f z(aY3j0PDc$@)7}g)?kKOQYkfPSx}C7S@DVKFlvVf2P3A##-=$Lvf+)EHkD|U2CB)K zP17X<#6${?MgH@amqy0m50|(l#~F(&!;QN`cJDL3cFgZ}X7|5+!0rTJ$NnxY1SK3| zO5IkZ$z)5@Ig)NkrK?73VNcv9)h99NqFm~iUwtiHgmPKr;c1 z4hJ6sQXtb1?75~J-fa|q`mEcrcJKk8*YbpVra@Z)=}HVBU+>` z6A|Cm(BKmOW^Q1&ta!N$NAfi++Sddh-)t+%`MRvu)k>@EjniSKMs3x^DqG4-6HCeE z-Qse*^l|aBb0eLDtMV$Xlu7L5;a3~wu)2%<%Kog|2XpYNv#UO6E+rKy9hKx8fDh}) zuvXXv9#}y*sw9}6COnZY@U0FxKmL`06TieBL211XS7P z;LlU%Sa%dIu;z6bz*U*yYN(;-;2GpDe6H6UUroTb$#r< zPn5p5&Gogn*}n&sZ@GQMCnRX+x2I#4BX4OJWs54CXVtHyadT8AK~0oDhbHLBYY2N>dJFM$C)21xbpvJEv`w zPI^mWmVC-A%xdV&n?5MhG7HL-Xx2~N(u%;Fgn2$e&p`8{j3!VG+vXZa`1MSJvyocd zqWLB8yka*3cwN}uLnDRUWS_B&(j~Vg*Nm3bZd;x2Qc^sE03wwtu*KgeA0kdoDQT=U zCiXA54&6VoOO(&^oH`RfO(cRK6TxPeEsfAhm2Oo-jkMco9XST5bddVOl(|kuzmI)B z4v(KVj7MRrjl?jbfT6h*Py>N8!@XDHNL!iIp5*XNXq=#OX%8spHp)0D8bnM7QsC6L z8`~09RjJ72oaW3bP&ftioa%9-+>S zbpL61hUZ<7dO8Pv0p`a%oQTh+(S|H3qk*F{qPbzmn_eh-c{D~2a@Ze-kVK>}GI3OO z%q7P;uU`mz=t@f~kBEHKE=|Hz#)MMZt16O1l*#5uO-<@f}d$$XWE9*;#A3XOdI6Z3k^_C~)^{Aur)I)uhW)fUNmJH7>97_}n~G8{r_< zP%d3UH)=)uhEpfsC{vig^?6=b9OD%q@qt|5gle3cV zU*rzgaIvzm=Hg&j`jQnO33__&qgB~ZpgLc6iZ@@&MDzL&g;mRBcN6zqH)4Ijq(X`c z5)`W-@Do8HxVx?l{>X^NF!hz$H%yxKh&)W6jt$379!IRYq!U|$p3$D{yYE>MbBZVf ztsDb#48_1qVt$NPtnwG6@)+q@VzBO^I_}n-)Zv`ZSZ$K2Gvdw>4PHk~$+W7Q7Y&yS z7)Sw|-@^$g&)>*?^{G#3VACsziVOUdQ7de(JR)<*1Pf^eIQP^UnucXL5Dm8RijPA5bkT;S30-aq<{JFAzMXWLY! ztWJnXky2hYoEAvmHXgy~QWj13s|I1gM?fXf2fT_wOkV2njMonhsQH%-a9X}MO)rv@ zk&I^Of{Q`wo_tj#UZUF|PkE4*K452IS95&G^?eY2AA=ZSUm)|&%9jE9mGX{&{B=~4 zg^Yl+^&`WB*09y)6YCps_bb#2w6OOv27XXgsAMX9ky;8je7OPa8?wcF<4{Niuiz|E zJ!&&Ls6cAgf-oivviC5@#ve77+A(=FF^D%esNyVV2r7}qvV7u(cVW6ly{%Y`J_>$7 z13QkuUYaj#Gz+IbOQ}Om9zhpr=LszkuM0hSC1M?VQW?rr(qI{bzTAXFjB$W9Q0t{I zWI#YgDD(;_r!8ve@R7(X$k(`%GjkGZ0d3gRYRt7NakF zxEsWAJ35IwKkBmB$+H}ruW8bht4X|B4fNlRtovNx-T-lUPod0tV_&}Yw=Dt&=&A(E z&y3ho`%4A-AO+wTd*wr^25&qsAzAbsZ~*GMzuv~(|6oT-hn$^%x7^Szz;MX7^mXQ5 znAHP#bZ#gmoF0X=zs($=5$<*Zy<`&K7}OG2zAcSTc8hZ_F**3@JC`j`w$Pck?q1r~ zOv(V|_EW9~bUunL)Oo~BYFd^cd=ZOl*uc@|`|IcTQprR)87B|-q4Fp4%-5y!k80`R z4?X^?$Aa`II{xrjYz$pZo?7a^1{3}oY-CISo7F)7%I;4M{eN|Hc>Xi^A07nVPg8;J z(H@{Pe{9av{nF|GVHE^X?YzEzG(%V(7a;t9WVW}np?9~jo>Lo-U1kS%9V^2KRS|dc z!$gLt2_~?b`$K5H87EfP%D1T^OC+N5YVIZQ94j?PCVGqKXr=!qE#Gd2+$S1Q^lmD( z@yM0obOgtj<-6%F3Fm1+IWdx&iUs+#rh7QKp@0W9^WdJ@M)`5Bn0`oHVvq*4gQPO5 zj)iO43?$vKQv!-ICtY;HTP#dtQBLB-9%dBF*!TKfJrw4F1lFNRYlvYE>KVY>PO zSPq@y3nxVW`XPLfdX+<-onl|M;JjEf@HXceUi+yl#$wHfo+O9DwhV?0oBM7k$(MyQ zU0Gw0M&z%M&Z(X1L@4pSOH3vqee3vaIlP}UeYyP^N-W57y}9P5wY&NJvX2e2zKz#9 zpp)5ELBbhiFceISL08AtHsRSA4qaz1J3lcwLn481QMx`hf!1I~H|r>o-es9BZ0vxH z_uQl;@`E!Mk!(lnrH#(^!M3Bb-Scp~fWtdLnR1Dkk~(En?YA!QtkWdVcTB{I2z6GT z-`8XEX-ps1-1qk6$ehgRFhMG`;uh@jimwo7OB|BcFqJnFq|4Goso_Q(Z}}4qz#J^c zE-AmkAt&$<7I_CEPW2mIBs(O2%#U1ib2@rU_U_I~u9>^#cz0%Rmq4*EhWcjW<=_@9 zZS!Z?cNdYxMV)yrW(Qf{)N1;3bj}FV;prpbOjS`engSA@=L=er>Lzklw96ARW0KBy zRW^~w1D!$l=ej5U^4V~FM(0WiHf1$%X)D>8vMjVMXbn>Dg~ED+;`C=Vvw}jnlB9vQ z4Oxu-X%h{#I^6l6Ve`1)PcWEx251Ml>myDD_&o>ZSQaqH`EbAzL9E?t@}lDV*S;z$ z@nkk%yWEhGjSjx2AC?w&e&Hr>brnFdR4!hX0?Q9VPIFkw?=>Pm zj5%|`2lr$TT6trjeWj-tM71KwWe;9qsH*9GxvpoDkj# z!u1mY1*SUR0_)U7q+SG6XyLT&mv#D2Sun?QF~01AF=kF=QEW&@C;m>`*e@*eP9h9dO z$H4z(il6 yudao-module-iot-api yudao-module-iot-biz - yudao-module-iot-plugin-api yudao-module-iot-plugin 4.0.0 diff --git a/yudao-module-iot/yudao-module-iot-api/pom.xml b/yudao-module-iot/yudao-module-iot-api/pom.xml index 8a75b09bf..a37094445 100644 --- a/yudao-module-iot/yudao-module-iot-api/pom.xml +++ b/yudao-module-iot/yudao-module-iot-api/pom.xml @@ -21,6 +21,17 @@ cn.iocoder.boot yudao-common + + + org.pf4j + pf4j-spring + + + org.slf4j + slf4j-log4j12 + + + diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java new file mode 100644 index 000000000..2f3ef6047 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.iot.api; + +/** + * 设备数据 API + */ +public interface DeviceDataApi { + + /** + * 保存设备数据 + * + * @param productKey 产品 key + * @param deviceName 设备名称 + * @param message 消息 + */ + void saveDeviceData(String productKey, String deviceName, String message); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java new file mode 100644 index 000000000..5c55bd89c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.api; + +import java.util.HashMap; +import java.util.Map; + +/** + * 服务注册表 - 插架模块使用,无法使用 Spring 注入 + */ +public class ServiceRegistry { + private static final Map, Object> services = new HashMap<>(); + + /** + * 注册服务 + * + * @param serviceClass 服务类 + * @param serviceImpl 服务实现 + * @param 服务类 + */ + public static void registerService(Class serviceClass, T serviceImpl) { + services.put(serviceClass, serviceImpl); + } + + /** + * 获得服务 + * + * @param serviceClass 服务类 + * @param 服务类 + * @return 服务实现 + */ + @SuppressWarnings("unchecked") + public static T getService(Class serviceClass) { + return (T) services.get(serviceClass); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 774d35380..c0810a183 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -81,6 +81,12 @@ org.pf4j pf4j-spring + + + org.slf4j + slf4j-log4j12 + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java new file mode 100644 index 000000000..59ae850a1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.api.device; + +import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 设备数据 API 实现类 + */ +@Service +@Validated +public class DeviceDataApiImpl implements DeviceDataApi { + + @Resource + private IotDeviceDataService iotDeviceDataService; + + @Override + public void saveDeviceData(String productKey, String deviceName, String message) { + iotDeviceDataService.saveDeviceData(productKey, deviceName, message); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java new file mode 100644 index 000000000..c0f3d748a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.iot.api; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java deleted file mode 100644 index 1b29a3447..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2012-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; - -import cn.iocoder.yudao.module.iot.api.Greeting; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.List; - -/** - * 打招呼 测试用例 - */ -@Component -public class Greetings { - - @Autowired - private List greetings; - - public Integer printGreetings() { - System.out.printf("找到扩展点的 %d 个扩展 '%s'%n", greetings.size(), Greeting.class.getName()); - for (Greeting greeting : greetings) { - System.out.println(">>> " + greeting.getGreeting()); - } - return greetings.size(); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java index 4cd22bcca..321eef9b6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; import jakarta.annotation.Resource; import org.pf4j.spring.SpringPluginManager; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.ApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -25,12 +24,8 @@ import java.util.stream.Collectors; @RequestMapping("/iot/plugins") public class PluginController { - @Resource - private ApplicationContext applicationContext; @Resource private SpringPluginManager springPluginManager; - @Resource - private Greetings greetings; @Value("${pf4j.pluginsDir}") private String pluginsDir; @@ -73,10 +68,8 @@ public class PluginController { return ResponseEntity.ok("插件上传并加载成功"); } catch (IOException e) { - e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("上传插件时发生错误: " + e.getMessage()); } catch (Exception e) { - e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("加载插件时发生错误: " + e.getMessage()); } } @@ -120,15 +113,4 @@ public class PluginController { return ResponseEntity.ok(plugins); } - /** - * 打印问候语 - * - * @return 问候语数量 - */ - @PermitAll - @GetMapping("/printGreetings") - public ResponseEntity printGreetings() { - Integer count = greetings.printGreetings(); - return ResponseEntity.ok(count); - } -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java deleted file mode 100644 index b6ca7f322..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2012-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; - -import cn.iocoder.yudao.module.iot.api.Greeting; -import org.pf4j.Extension; -import org.springframework.stereotype.Component; - -/** - * 打招呼 测试用例 - */ -@Extension -@Component -public class WhazzupGreeting implements Greeting { - - @Override - public String getGreeting() { - return "Whazzup"; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java index e71ff2904..92edca821 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java @@ -2,8 +2,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; -import java.util.*; -import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; import com.alibaba.excel.annotation.*; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java index 8d927045d..95db299d1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; -import java.util.*; import jakarta.validation.constraints.*; @Schema(description = "管理后台 - IoT 插件实例新增/修改 Request VO") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java new file mode 100644 index 000000000..385c8aee5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.framework.plugin; + +import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; + +@Slf4j +@Configuration +public class ServiceRegistryConfiguration { + + @Resource + private DeviceDataApi deviceDataApi; + + @PostConstruct + public void init() { + // 将主程序中的 DeviceDataApi 实例注册到 ServiceRegistry + ServiceRegistry.registerService(DeviceDataApi.class, deviceDataApi); + log.info("[init][将 DeviceDataApi 实例注册到 ServiceRegistry 中]"); + } + + /** + * 定义一个标记用的 Bean,用于表示 ServiceRegistry 已初始化完成 + */ + @Bean("serviceRegistryInitializedMarker") + public Object serviceRegistryInitializedMarker() { + // 返回任意对象即可,这里返回null都可以,但最好返回个实际对象 + return new Object(); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java index db03332d9..d87a94f31 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.Greetings; import org.pf4j.spring.SpringPluginManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -10,14 +9,9 @@ import org.springframework.context.annotation.DependsOn; public class SpringConfiguration { @Bean + @DependsOn("serviceRegistryInitializedMarker") public SpringPluginManager pluginManager() { return new SpringPluginManager(); } - @Bean - @DependsOn("pluginManager") - public Greetings greetings() { - return new Greetings(); - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index 70fd23014..1dd4ad666 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -20,7 +20,8 @@ public interface IotDeviceDataService { * * @param productKey 产品 key * @param deviceName 设备名称 - * @param message 消息 + * @param message 消息 + *

JSON 格式,参见 ... */ void saveDeviceData(String productKey, String deviceName, String message); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java index daa76acc6..bd7efa8d0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java @@ -22,9 +22,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.web.multipart.MultipartFile; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.jar.JarEntry; @@ -220,24 +218,24 @@ public class PluginInfoServiceImpl implements PluginInfoService { pluginInfoMapper.updateById(pluginInfoDo); } - @PostConstruct - public void init() { - Executors.newSingleThreadScheduledExecutor().schedule(this::startPlugins, 3, TimeUnit.SECONDS); - } - - @SneakyThrows - private void startPlugins() { - for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { - if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { - continue; - } - log.info("start plugin:{}", pluginInfoDO.getPluginId()); - try { - pluginManager.startPlugin(pluginInfoDO.getPluginId()); - } catch (Exception e) { - log.error("start plugin error", e); - } - } - } +// @PostConstruct +// public void init() { +// Executors.newSingleThreadScheduledExecutor().schedule(this::startPlugins, 3, TimeUnit.SECONDS); +// } +// +// @SneakyThrows +// private void startPlugins() { +// for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { +// if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { +// continue; +// } +// log.info("start plugin:{}", pluginInfoDO.getPluginId()); +// try { +// pluginManager.startPlugin(pluginInfoDO.getPluginId()); +// } catch (Exception e) { +// log.error("start plugin error", e); +// } +// } +// } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 628805a97..a53aee55d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -122,7 +122,7 @@ public class IotProductServiceImpl implements IotProductService { thingModelFunctionService.createSuperTableDataModel(id); // 3.2 创建物模型日志超级表数据模型 thingModelMessageService.createSuperTable(id); - }x + } productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml b/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml deleted file mode 100644 index 6d5eb765b..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - 4.0.0 - cn.iocoder.boot - yudao-module-iot-plugin-api - 0.0.1 - jar - - ${project.artifactId} - - 物联网 模块插件 API,暴露给其它模块调用 - - - - 0.9.0 - - - - - - org.pf4j - pf4j-spring - ${pf4j-spring.version} - provided - - - - diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java deleted file mode 100644 index b28454937..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2012-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package cn.iocoder.yudao.module.iot.api; - -import org.pf4j.ExtensionPoint; - -/** - * @author Decebal Suiu - */ -public interface Greeting extends ExtensionPoint { - - String getGreeting(); - -} diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java deleted file mode 100644 index 7da0c665b..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * 占位 - * - * TODO 芋艿:后续删除 - */ -package cn.iocoder.yudao.module.iot.api; diff --git a/yudao-module-iot/yudao-module-iot-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/pom.xml index 8ec68638f..c8f0ff0fe 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/pom.xml @@ -2,19 +2,29 @@ - 4.0.0 - cn.iocoder.boot - yudao-module-iot-plugin - 0.0.1 - pom - + + + + + + + yudao-module-iot + cn.iocoder.boot + ${revision} + + yudao-module-iot-demo-plugin yudao-module-iot-http-plugin + 4.0.0 + + yudao-module-iot-plugin + pom + ${project.artifactId} - 物联网模块 - 插件模块 + 物联网 插件 模块 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties new file mode 100644 index 000000000..5a67270bb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties @@ -0,0 +1,6 @@ +plugin.id=demo-plugin +plugin.class=cn.iocoder.yudao.module.iot.plugin.DemoPlugin +plugin.version=0.0.1 +plugin.provider=ahh +plugin.dependencies= +plugin.description=demo-plugin diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml new file mode 100644 index 000000000..3d58a1a75 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml @@ -0,0 +1,148 @@ + + + + yudao-module-iot-plugin + cn.iocoder.boot + ${revision} + + 4.0.0 + jar + + yudao-module-iot-demo-plugin + + ${project.artifactId} + + 物联网 插件模块 - demo 插件 + + + + + demo-plugin + cn.iocoder.yudao.module.iot.plugin.DemoPlugin + 0.0.1 + ahh + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.6 + + + unzip jar file + package + + + + + + + run + + + + + + + maven-assembly-plugin + 2.3 + + + + src/main/assembly/assembly.xml + + + false + + + + make-assembly + package + + attached + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.dependencies} + + + + + + + maven-deploy-plugin + + true + + + + + + + + + org.springframework.boot + spring-boot-starter-web + ${spring.boot.version} + provided + + + + org.pf4j + pf4j-spring + provided + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml new file mode 100644 index 000000000..daec9e431 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml @@ -0,0 +1,31 @@ + + plugin + + zip + + false + + + false + runtime + lib + + *:jar:* + + + + + + + target/plugin-classes + classes + + + diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java new file mode 100644 index 000000000..c97a5b9b5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import com.sun.net.httpserver.HttpServer; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.pf4j.RuntimeMode; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; + +/** + * 一个启动 HTTP 服务器的简单插件。 + */ +@Slf4j +public class DemoPlugin extends Plugin { + + private HttpServer server; + + public DemoPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + log.info("Demo 插件启动"); + // for testing the development mode + if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { + log.info("DemoPlugin in DEVELOPMENT mode"); + } + startDemoServer(); + } + + @Override + public void stop() { + log.info("Demo 插件停止"); + stopDemoServer(); + } + + private void startDemoServer() { + try { + server = HttpServer.create(new InetSocketAddress(9081), 0); + server.createContext("/", exchange -> { + String response = "Hello from DemoPlugin"; + exchange.sendResponseHeaders(200, response.getBytes().length); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + }); + server.setExecutor(null); + server.start(); + log.info("HTTP 服务器启动成功,端口为 9081"); + log.info("访问地址为 http://127.0.0.1:9081/"); + } catch (IOException e) { + log.error("HTTP 服务器启动失败", e); + } + } + + private void stopDemoServer() { + if (server != null) { + server.stop(0); + log.info("HTTP 服务器停止成功"); + } + } + +// @Extension +// public static class WelcomeGreeting implements Greeting { +// +// @Override +// public String getGreeting() { +// return "Welcome to DemoPlugin"; +// } +// +// } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties index 694c97ba5..4e1199acf 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties @@ -3,3 +3,4 @@ plugin.class=cn.iocoder.yudao.module.iot.plugin.HttpPlugin plugin.version=0.0.1 plugin.provider=ahh plugin.dependencies= +plugin.description=http-plugin-0.0.1 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index eccf47feb..200a451b6 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -3,14 +3,20 @@ xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + yudao-module-iot-plugin + cn.iocoder.boot + ${revision} + 4.0.0 - cn.iocoder.boot - yudao-module-iot-http-plugin - 0.0.1 jar + yudao-module-iot-http-plugin + ${project.artifactId} - 物联网 模块 - http 插件 + + 物联网 插件模块 - http 插件 + @@ -19,50 +25,8 @@ 0.0.1 ahh - - - 17 - ${java.version} - ${java.version} - 1.6 - 2.3 - 2.4 - 0.9.0 - - 1.18.34 - 3.3.1 - UTF-8 - - - - org.springframework.boot - spring-boot-starter-web - ${spring.boot.version} - provided - - - - org.pf4j - pf4j-spring - ${pf4j-spring.version} - provided - - - - cn.iocoder.boot - yudao-module-iot-plugin-api - ${project.version} - - - org.projectlombok - lombok - ${lombok.version} - provided - - - + + org.springframework.boot + spring-boot-starter-web + + + + org.pf4j + pf4j-spring + provided + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + io.netty + netty-all + 4.1.63.Final + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml index ce2e92cf9..daec9e431 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml @@ -1,9 +1,3 @@ - plugin diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java new file mode 100644 index 000000000..c145182ed --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java @@ -0,0 +1,160 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.*; +import io.netty.util.CharsetUtil; + +/** + * 基于 Netty 的 HTTP 处理器,用于接收设备上报的数据并调用主程序的 DeviceDataApi 接口进行处理。 + *

+ * 请求格式: + * POST /sys/{productKey}/{deviceName}/thing/event/property/post + * 请求体为 JSON 格式数据。 + *

+ * 返回结果为 JSON 格式,包含统一的 code、data、id、message、method、version 字段。 + */ +public class HttpHandler extends SimpleChannelInboundHandler { + + private final DeviceDataApi deviceDataApi; + + public HttpHandler(DeviceDataApi deviceDataApi) { + this.deviceDataApi = deviceDataApi; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { + String uri = request.uri(); + + // 期望的路径格式: /sys/{productKey}/{deviceName}/thing/event/property/post + // 使用 "/" 拆分路径 + String[] parts = uri.split("/"); + + /* + 拆分结果示例: + parts[0] = "" + parts[1] = "sys" + parts[2] = productKey + parts[3] = deviceName + parts[4] = "thing" + parts[5] = "event" + parts[6] = "property" + parts[7] = "post" + */ + boolean isCorrectPath = parts.length == 8 + && "sys".equals(parts[1]) + && "thing".equals(parts[4]) + && "event".equals(parts[5]) + && "property".equals(parts[6]) + && "post".equals(parts[7]); + + if (!isCorrectPath) { + // 如果路径不匹配,返回 404 错误 + writeResponse(ctx, HttpResponseStatus.NOT_FOUND, "Not Found"); + return; + } + + String productKey = parts[2]; + String deviceName = parts[3]; + + // 从请求中获取原始数据 + String requestBody = request.content().toString(CharsetUtil.UTF_8); + + // 尝试解析请求数据为 JSON 对象 + JSONObject jsonData; + try { + jsonData = JSONUtil.parseObj(requestBody); + } catch (Exception e) { + // 数据不是合法的 JSON 格式,返回 400 错误 + JSONObject res = createResponseJson( + 400, + new JSONObject(), + null, + "请求数据不是合法的 JSON 格式: " + e.getMessage(), + "thing.event.property.post", + "1.0" + ); + writeResponse(ctx, HttpResponseStatus.BAD_REQUEST, res.toString()); + return; + } + + // 获取请求中的 id 字段,若不存在则为 null + String id = jsonData.getStr("id", null); + + try { + // 调用主程序的接口保存数据 + deviceDataApi.saveDeviceData(productKey, deviceName, jsonData.toString()); + + // 构造成功响应内容 + JSONObject successRes = createResponseJson( + 200, + new JSONObject(), + id, + "success", + "thing.event.property.post", + "1.0" + ); + writeResponse(ctx, HttpResponseStatus.OK, successRes.toString()); + } catch (Exception e) { + // 保存数据过程中出现异常,返回 500 错误 + JSONObject errorRes = createResponseJson( + 500, + new JSONObject(), + id, + "The format of result is error!", + "thing.event.property.post", + "1.0" + ); + writeResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, errorRes.toString()); + } + } + + /** + * 创建标准化的响应 JSON 对象 + * + * @param code 响应状态码(业务层面的) + * @param data 返回的数据对象(JSON) + * @param id 请求的 id(可选) + * @param message 返回的提示信息 + * @param method 返回的 method 标识 + * @param version 返回的版本号 + * @return 构造好的 JSON 对象 + */ + private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, String version) { + JSONObject res = new JSONObject(); + res.set("code", code); + res.set("data", data != null ? data : new JSONObject()); // 确保 data 不为 null + res.set("id", id); + res.set("message", message); + res.set("method", method); + res.set("version", version); + return res; + } + + /** + * 向客户端返回 HTTP 响应的辅助方法。 + * + * @param ctx 通道上下文 + * @param status HTTP 响应状态码(网络层面的) + * @param content 响应内容(JSON 字符串或其他文本) + */ + private void writeResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String content) { + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + status, + Unpooled.copiedBuffer(content, CharsetUtil.UTF_8) + ); + + // 设置响应头为 JSON 类型和正确的编码 + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8"); + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); + + // 发送响应并在发送完成后关闭连接 + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java index 32926be45..68311300e 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java @@ -1,79 +1,81 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.Greeting; -import com.sun.net.httpserver.HttpServer; +import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.*; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang.StringUtils; -import org.pf4j.Extension; -import org.pf4j.Plugin; import org.pf4j.PluginWrapper; -import org.pf4j.RuntimeMode; +import org.pf4j.Plugin; -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; -/** - * 一个启动 HTTP 服务器的简单插件。 - */ @Slf4j public class HttpPlugin extends Plugin { - private HttpServer server; + private static final int PORT = 8092; + private final ExecutorService executorService; + private DeviceDataApi deviceDataApi; // 用于保存设备数据的 API public HttpPlugin(PluginWrapper wrapper) { super(wrapper); + this.executorService = Executors.newSingleThreadExecutor(); // 创建单线程池 } @Override public void start() { log.info("HttpPlugin.start()"); - // for testing the development mode - if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { - log.info("HttpPlugin in DEVELOPMENT mode"); + + // 从 ServiceRegistry 中获取主程序暴露的 DeviceDataApi 接口实例 + deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); + if (deviceDataApi == null) { + log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); + return; } - startHttpServer(); + + // 异步启动 Netty 服务器 + executorService.submit(this::startHttpServer); } @Override public void stop() { log.info("HttpPlugin.stop()"); - stopHttpServer(); + executorService.shutdownNow(); // 停止线程池 } + // 启动 HTTP 服务 private void startHttpServer() { + EventLoopGroup bossGroup = new NioEventLoopGroup(1); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { - server = HttpServer.create(new InetSocketAddress(9081), 0); - server.createContext("/", exchange -> { - String response = "Welcome to PF4J HTTP Server"; - exchange.sendResponseHeaders(200, response.getBytes().length); - OutputStream os = exchange.getResponseBody(); - os.write(response.getBytes()); - os.close(); - }); - server.setExecutor(null); - server.start(); - log.info("HTTP server started on port 9081"); - } catch (IOException e) { - log.error("Error starting HTTP server", e); + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(Channel channel) { + channel.pipeline().addLast(new HttpServerCodec()); + channel.pipeline().addLast(new HttpObjectAggregator(65536)); + // 将从 ServiceRegistry 获取的 deviceDataApi 传入处理器 + channel.pipeline().addLast(new HttpHandler(deviceDataApi)); + } + }); + + // 绑定端口并启动服务器 + ChannelFuture future = bootstrap.bind(PORT).sync(); + log.info("HTTP 服务器启动成功,端口为: {}", PORT); + future.channel().closeFuture().sync(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("HTTP 服务启动中断", e); + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); } } - - private void stopHttpServer() { - if (server != null) { - server.stop(0); - log.info("HTTP server stopped"); - } - } - - @Extension - public static class WelcomeGreeting implements Greeting { - - @Override - public String getGreeting() { - return "Welcome to PF4J"; - } - - } - -} \ No newline at end of file +} From e998b0c7ebe0123972f9a3aaaf43aacdba0ff75d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 21 Dec 2024 16:28:25 +0800 Subject: [PATCH 047/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E8=AF=84=E5=AE=A1=20plugin=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/yudao-module-iot-api/pom.xml | 1 + .../yudao/module/iot/api/ServiceRegistry.java | 2 ++ .../iot/api/{ => device}/DeviceDataApi.java | 2 +- yudao-module-iot/yudao-module-iot-biz/pom.xml | 1 + .../iot/api/device/DeviceDataApiImpl.java | 5 ++- .../yudao/module/iot/api/package-info.java | 5 +++ .../plugin/ServiceRegistryConfiguration.java | 7 ++-- .../service/device/IotDeviceDataService.java | 2 +- .../PluginInstanceServiceImpl.java | 1 + .../yudao/module/iot/plugin/HttpHandler.java | 33 ++++++------------- .../yudao/module/iot/plugin/HttpPlugin.java | 20 +++++++---- 11 files changed, 42 insertions(+), 37 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/{ => device}/DeviceDataApi.java (86%) diff --git a/yudao-module-iot/yudao-module-iot-api/pom.xml b/yudao-module-iot/yudao-module-iot-api/pom.xml index a37094445..d2f83b785 100644 --- a/yudao-module-iot/yudao-module-iot-api/pom.xml +++ b/yudao-module-iot/yudao-module-iot-api/pom.xml @@ -22,6 +22,7 @@ yudao-common + org.pf4j pf4j-spring diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java index 5c55bd89c..5603ad8d7 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java @@ -7,6 +7,7 @@ import java.util.Map; * 服务注册表 - 插架模块使用,无法使用 Spring 注入 */ public class ServiceRegistry { + private static final Map, Object> services = new HashMap<>(); /** @@ -31,4 +32,5 @@ public class ServiceRegistry { public static T getService(Class serviceClass) { return (T) services.get(serviceClass); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java similarity index 86% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java index 2f3ef6047..cb747f505 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.api; +package cn.iocoder.yudao.module.iot.api.device; /** * 设备数据 API diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index c0810a183..19b50ec21 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -81,6 +81,7 @@ org.pf4j pf4j-spring + org.slf4j diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java index 59ae850a1..d62c20cb5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.api.device; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -15,11 +14,11 @@ import javax.annotation.Resource; public class DeviceDataApiImpl implements DeviceDataApi { @Resource - private IotDeviceDataService iotDeviceDataService; + private IotDeviceDataService deviceDataService; @Override public void saveDeviceData(String productKey, String deviceName, String message) { - iotDeviceDataService.saveDeviceData(productKey, deviceName, message); + deviceDataService.saveDeviceData(productKey, deviceName, message); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java index c0f3d748a..07852180d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java @@ -1 +1,6 @@ +/** + * 占位 + * + * TODO 芋艿:后续删除 + */ package cn.iocoder.yudao.module.iot.api; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java index 385c8aee5..3450b67fb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; @@ -26,9 +26,10 @@ public class ServiceRegistryConfiguration { /** * 定义一个标记用的 Bean,用于表示 ServiceRegistry 已初始化完成 */ - @Bean("serviceRegistryInitializedMarker") + @Bean("serviceRegistryInitializedMarker") // TODO @haohao:1)这个名字,可以搞个 public static final 常量;2)是不是 conditionBefore 啥 public Object serviceRegistryInitializedMarker() { - // 返回任意对象即可,这里返回null都可以,但最好返回个实际对象 + // 返回任意对象即可,这里返回 null 都可以,但最好返回个实际对象 return new Object(); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index 1dd4ad666..1c246e2c7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java @@ -21,7 +21,7 @@ public interface IotDeviceDataService { * @param productKey 产品 key * @param deviceName 设备名称 * @param message 消息 - *

JSON 格式,参见 ... + *

参见 JSON 格式 */ void saveDeviceData(String productKey, String deviceName, String message); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java index 405efe163..afb05ef2f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java @@ -13,6 +13,7 @@ import org.springframework.validation.annotation.Validated; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INSTANCE_NOT_EXISTS; +// TODO @haohao:可以搞个 plugin 包,然后把 plugininfo、plugininstance /** * IoT 插件实例 Service 实现类 * diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java index c145182ed..6d0908683 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; @@ -12,12 +12,9 @@ import io.netty.util.CharsetUtil; /** * 基于 Netty 的 HTTP 处理器,用于接收设备上报的数据并调用主程序的 DeviceDataApi 接口进行处理。 - *

- * 请求格式: - * POST /sys/{productKey}/{deviceName}/thing/event/property/post - * 请求体为 JSON 格式数据。 - *

- * 返回结果为 JSON 格式,包含统一的 code、data、id、message、method、version 字段。 + * + * 1. 请求格式:JSON 格式,地址为 POST /sys/{productKey}/{deviceName}/thing/event/property/post + * 2. 返回结果:JSON 格式,包含统一的 code、data、id、message、method、version 字段 */ public class HttpHandler extends SimpleChannelInboundHandler { @@ -29,10 +26,9 @@ public class HttpHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { - String uri = request.uri(); - // 期望的路径格式: /sys/{productKey}/{deviceName}/thing/event/property/post // 使用 "/" 拆分路径 + String uri = request.uri(); String[] parts = uri.split("/"); /* @@ -52,25 +48,19 @@ public class HttpHandler extends SimpleChannelInboundHandler { && "event".equals(parts[5]) && "property".equals(parts[6]) && "post".equals(parts[7]); - if (!isCorrectPath) { - // 如果路径不匹配,返回 404 错误 writeResponse(ctx, HttpResponseStatus.NOT_FOUND, "Not Found"); return; } - String productKey = parts[2]; String deviceName = parts[3]; - // 从请求中获取原始数据 + // 从请求中获取原始数据,尝试解析请求数据为 JSON 对象 String requestBody = request.content().toString(CharsetUtil.UTF_8); - - // 尝试解析请求数据为 JSON 对象 JSONObject jsonData; try { jsonData = JSONUtil.parseObj(requestBody); } catch (Exception e) { - // 数据不是合法的 JSON 格式,返回 400 错误 JSONObject res = createResponseJson( 400, new JSONObject(), @@ -82,8 +72,6 @@ public class HttpHandler extends SimpleChannelInboundHandler { writeResponse(ctx, HttpResponseStatus.BAD_REQUEST, res.toString()); return; } - - // 获取请求中的 id 字段,若不存在则为 null String id = jsonData.getStr("id", null); try { @@ -101,7 +89,6 @@ public class HttpHandler extends SimpleChannelInboundHandler { ); writeResponse(ctx, HttpResponseStatus.OK, successRes.toString()); } catch (Exception e) { - // 保存数据过程中出现异常,返回 500 错误 JSONObject errorRes = createResponseJson( 500, new JSONObject(), @@ -128,7 +115,7 @@ public class HttpHandler extends SimpleChannelInboundHandler { private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, String version) { JSONObject res = new JSONObject(); res.set("code", code); - res.set("data", data != null ? data : new JSONObject()); // 确保 data 不为 null + res.set("data", data != null ? data : new JSONObject()); res.set("id", id); res.set("message", message); res.set("method", method); @@ -137,24 +124,24 @@ public class HttpHandler extends SimpleChannelInboundHandler { } /** - * 向客户端返回 HTTP 响应的辅助方法。 + * 向客户端返回 HTTP 响应的辅助方法 * * @param ctx 通道上下文 * @param status HTTP 响应状态码(网络层面的) * @param content 响应内容(JSON 字符串或其他文本) */ private void writeResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String content) { + // 设置响应头为 JSON 类型和正确的编码 FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(content, CharsetUtil.UTF_8) ); - - // 设置响应头为 JSON 类型和正确的编码 response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8"); response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); // 发送响应并在发送完成后关闭连接 ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java index 68311300e..70da0131c 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; @@ -18,12 +18,14 @@ import java.util.concurrent.Executors; public class HttpPlugin extends Plugin { private static final int PORT = 8092; + private final ExecutorService executorService; - private DeviceDataApi deviceDataApi; // 用于保存设备数据的 API + private DeviceDataApi deviceDataApi; public HttpPlugin(PluginWrapper wrapper) { super(wrapper); - this.executorService = Executors.newSingleThreadExecutor(); // 创建单线程池 + // 创建单线程池 + this.executorService = Executors.newSingleThreadExecutor(); } @Override @@ -44,10 +46,13 @@ public class HttpPlugin extends Plugin { @Override public void stop() { log.info("HttpPlugin.stop()"); - executorService.shutdownNow(); // 停止线程池 + // 停止线程池 + executorService.shutdownNow(); } - // 启动 HTTP 服务 + /** + * 启动 HTTP 服务 + */ private void startHttpServer() { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); @@ -56,7 +61,8 @@ public class HttpPlugin extends Plugin { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { + .childHandler(new ChannelInitializer<>() { + @Override protected void initChannel(Channel channel) { channel.pipeline().addLast(new HttpServerCodec()); @@ -64,6 +70,7 @@ public class HttpPlugin extends Plugin { // 将从 ServiceRegistry 获取的 deviceDataApi 传入处理器 channel.pipeline().addLast(new HttpHandler(deviceDataApi)); } + }); // 绑定端口并启动服务器 @@ -78,4 +85,5 @@ public class HttpPlugin extends Plugin { workerGroup.shutdownGracefully(); } } + } From e01d03eefb3fbe5d50fb67c44384bb7f6c88162c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 21 Dec 2024 16:33:50 +0800 Subject: [PATCH 048/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 - .../simulatesend/SimulateSendConsumer.java | 4 ++- .../module/iot/util/IotTdDatabaseUtils.java | 25 +++++++------------ .../tdengine/TdThinkModelMessageMapper.xml | 1 - 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index a763924b5..4539f1259 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -14,7 +14,6 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); - ErrorCode PRODUCT_DEVICE_NOT_EXISTS = new ErrorCode(1_050_001_004, "产品设备类型不存在"); // ========== 产品物模型 1-050-002-000 ============ ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java index dfc911df5..111cf5007 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.iot.mq.consumer.simulatesend; /** + * TODO @alwayssuper:记得实现,还有类注释哈 + * * @author alwayssuper - * @date 2024/12/20 8:04 + * @since 2024/12/20 8:04 */ public class SimulateSendConsumer { } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java index e4ecf7465..a409c8069 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java @@ -1,13 +1,9 @@ package cn.iocoder.yudao.module.iot.util; +import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_DEVICE_NOT_EXISTS; // TODO @芋艿:可能要思索下,有没更好的处理方式 // TODO @芋艿:怎么改成无状态 @@ -34,20 +30,17 @@ public class IotTdDatabaseUtils { * @return 产品超级表表名 */ public static String getProductSuperTableName(Integer deviceType, String productKey) { - // TODO @alwayssuper:枚举字段,不要 1、2、3;不符合预期,抛出异常 - if (deviceType == null) { - throw exception(PRODUCT_DEVICE_NOT_EXISTS); - } + Assert.notNull(deviceType, "deviceType 不能为空"); if (IotProductDeviceTypeEnum.GATEWAY_SUB.getType().equals(deviceType)) { return String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); - } else if (IotProductDeviceTypeEnum.GATEWAY.getType().equals(deviceType)) { + } + if (IotProductDeviceTypeEnum.GATEWAY.getType().equals(deviceType)) { return String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); - } else if (IotProductDeviceTypeEnum.DIRECT.getType().equals(deviceType)){ + } + if (IotProductDeviceTypeEnum.DIRECT.getType().equals(deviceType)){ return String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); } - else{ - throw exception(PRODUCT_DEVICE_NOT_EXISTS); - } + throw new IllegalArgumentException("deviceType 不正确"); } /** @@ -58,7 +51,6 @@ public class IotTdDatabaseUtils { * */ public static String getThingModelMessageSuperTableName(String productKey) { - // TODO @alwayssuper:是不是应该 + 拼接就好,不用 format return "thing_model_message_" + productKey.toLowerCase(); } @@ -70,7 +62,8 @@ public class IotTdDatabaseUtils { * @return 物模型日志设备表名 */ public static String getThingModelMessageDeviceTableName(String productKey, String deviceName) { - return String.format(IotConstants.THING_MODEL_MESSAGE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); + return String.format(IotConstants.THING_MODEL_MESSAGE_TABLE_NAME_FORMAT, + productKey.toLowerCase(), deviceName.toLowerCase()); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml index 074ae9884..a0cc12712 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml @@ -5,7 +5,6 @@ - CREATE STABLE ${dataBaseName}.${superTableName}( ts TIMESTAMP, From 94cfc4a1b1560ad7dffb850d5cf96609322a01b8 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 25 Dec 2024 12:15:58 +0800 Subject: [PATCH 049/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IOT:=20ThingModel=20=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=92=8C=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotProductThingModelAccessModeEnum.java | 2 +- ...otProductThingModelParamDirectionEnum.java | 20 +++++++ ...tProductThingModelServiceCallTypeEnum.java | 20 +++++++ ...ProductThingModelServiceEventTypeEnum.java | 21 ++++++++ .../thingmodel/model/ThingModelEvent.java | 30 +++++++++-- .../model/ThingModelInputOutputParam.java | 52 +++++++++++++++++++ .../thingmodel/model/ThingModelService.java | 35 +++++++++++-- .../model/dataType/ThingModelArgument.java | 26 ---------- 8 files changed, 169 insertions(+), 37 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java index a75501803..7fca10a46 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * IOT 访问方式枚举类 + * IOT 产品物模型属性读取类型枚举 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java new file mode 100644 index 000000000..e12332b6d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.enums.thingmodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * IOT 产品物模型参数是输入参数还是输出参数枚举 + * + * @author HUIHUI + */ +@AllArgsConstructor +@Getter +public enum IotProductThingModelParamDirectionEnum { + + INPUT("input"), // 输入参数 + OUTPUT("output"); // 输出参数 + + private final String direction; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java new file mode 100644 index 000000000..81ffccc49 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.enums.thingmodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * IOT 产品物模型服务调用方式枚举 + * + * @author HUIHUI + */ +@AllArgsConstructor +@Getter +public enum IotProductThingModelServiceCallTypeEnum { + + ASYNC("async"), // 异步调用 + SYNC("sync"); // 同步调用 + + private final String type; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java new file mode 100644 index 000000000..fbf76da77 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.enums.thingmodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * IOT 产品物模型事件类型枚举 + * + * @author HUIHUI + */ +@AllArgsConstructor +@Getter +public enum IotProductThingModelServiceEventTypeEnum { + + INFO("info"), // 信息 + ALERT("alert"), // 告警 + ERROR("error"); // 故障 + + private final String type; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index 718c7b60e..315d4d036 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -1,9 +1,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceEventTypeEnum; import lombok.Data; + import java.util.List; +/** + * 物模型中的事件 + * + * @author HUIHUI + */ @Data public class ThingModelEvent { @@ -19,14 +25,28 @@ public class ThingModelEvent { * 事件描述 */ private String description; - + /** + * 是否是标准品类的必选事件。 + * + * - true:是 + * - false:否 + */ + private Boolean required; /** * 事件类型 * - * "info"、"alert"、"error" + * 关联枚举 {@link IotProductThingModelServiceEventTypeEnum} + */ + private String eventType; + /** + * 事件的输出参数 + * + * 输出参数定义事件调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 + */ + private List outputParams; + /** + * 标识设备需要执行的具体操作 */ - private String type; - private List outputData; private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java new file mode 100644 index 000000000..56a53c868 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; + +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelParamDirectionEnum; +import lombok.Data; + +import java.util.List; + +/** + * IOT 产品物模型中的服务、事件的输入输出参数 + * + * @author HUIHUI + */ +@Data +public class ThingModelInputOutputParam { + + /** + * 参数标识符 + */ + private String identifier; + /** + * 参数名称 + */ + private String name; + /** + * 参数描述 + */ + private String description; + /** + * 用于区分输入或输出参数 + * + * 关联枚举 {@link IotProductThingModelParamDirectionEnum} + */ + private String direction; + /** + * 参数的序号。从 0 开始排序,且不能重复。 + */ + private Integer paraOrder; + /** + * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致 + */ + private String dataType; + /** + * 参数值的数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 + */ + private ThingModelDataSpecs dataSpecs; + /** + * 参数值的数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 + */ + private List dataSpecsList; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index ec4bd34e9..3fec2762f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -1,9 +1,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceCallTypeEnum; import lombok.Data; + import java.util.List; +/** + * 物模型中的服务 + * + * @author HUIHUI + */ @Data public class ThingModelService { @@ -19,15 +25,34 @@ public class ThingModelService { * 服务描述 */ private String description; - + /** + * 是否是标准品类的必选服务。 + * + * - true:是 + * - false:否 + */ + private Boolean required; /** * 调用类型 * - * "sync"、"async" + * 关联枚举 {@link IotProductThingModelServiceCallTypeEnum} */ private String callType; - private List inputData; - private List outputData; + /** + * 服务的输入参数 + * + * 输入参数定义服务调用时所需提供的信息,用于控制设备行为或执行特定任务 + */ + private List inputParams; + /** + * 服务的输出参数 + * + * 输出参数定义服务调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 + */ + private List outputParams; + /** + * 标识设备需要执行的具体操作 + */ private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java deleted file mode 100644 index 96f51150f..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; - -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class ThingModelArgument { - - public static final String DIRECTION_INPUT = "input"; - public static final String DIRECTION_OUTPUT = "output"; - - private String identifier; - private String name; - /** - * 物模型中的属性 - */ - private ThingModelProperty property; - /** - * 用于区分输入或输出参数,"input" 或 "output" - */ - private String direction; - private String description; - -} From f4e9a586e3a0805d8d2834ae027908033ec5f99a Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 25 Dec 2024 15:47:24 +0800 Subject: [PATCH 050/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IOT:=20ThingModel=20=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=92=8C=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/ThingModelInputOutputParam.java | 2 + .../IotProductThingModelService.java | 14 +- .../IotProductThingModelServiceImpl.java | 447 +++++++----------- 3 files changed, 183 insertions(+), 280 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java index 56a53c868..60e37f73f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java @@ -34,6 +34,8 @@ public class ThingModelInputOutputParam { private String direction; /** * 参数的序号。从 0 开始排序,且不能重复。 + * + * TODO 考虑要不要序号,感觉是要的, 先留一手看看 */ private Integer paraOrder; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java index 04086d0a7..2eac5e1ad 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java @@ -23,6 +23,13 @@ public interface IotProductThingModelService { */ Long createProductThingModel(@Valid IotProductThingModelSaveReqVO createReqVO); + /** + * 创建超级表数据模型 + * + * @param productId 产品编号 + */ + void createSuperTableDataModel(Long productId); + /** * 更新产品物模型 * @@ -61,13 +68,6 @@ public interface IotProductThingModelService { */ PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO); - /** - * 创建超级表数据模型 - * - * @param productId 产品编号 - */ - void createSuperTableDataModel(Long productId); - /** * 获得产品物模型列表 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java index ddb800eee..e195464f9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java @@ -3,14 +3,10 @@ package cn.iocoder.yudao.module.iot.service.thingmodel; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelInputOutputParam; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArrayDataSpecs; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert; @@ -18,8 +14,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.*; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotSuperTableService; import jakarta.annotation.Resource; @@ -31,8 +26,7 @@ import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; /** @@ -51,7 +45,7 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @Resource private IotProductService productService; @Resource - private IotSuperTableService dbStructureDataService; + private IotSuperTableService superTableService; @Override @Transactional(rollbackFor = Exception.class) @@ -79,6 +73,99 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ return thingModel.getId(); } + @Override + public void createSuperTableDataModel(Long productId) { + // 1. 查询产品 + IotProductDO product = productService.getProduct(productId); + + // 2. 查询产品的物模型功能列表 + List thingModelList = productThingModelMapper.selectListByProductId(productId); + + // 3. 生成 TDengine 的数据模型 + superTableService.createSuperTableDataModel(product, thingModelList); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { + // 1. 校验功能是否存在 + validateProductThingModelMapperExists(updateReqVO.getId()); + + // 2. 校验功能标识符是否唯一 + validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); + + // 3. 校验产品状态,发布状态下,不允许操作功能 + validateProductStatus(updateReqVO.getProductId()); + + // 4. 更新数据库 + IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(updateReqVO); + productThingModelMapper.updateById(thingModel); + + // 5. 如果更新的是属性,需要更新默认的事件和服务 + if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteProductThingModel(Long id) { + // 1. 校验功能是否存在 + IotProductThingModelDO thingModel = productThingModelMapper.selectById(id); + if (thingModel == null) { + throw exception(THING_MODEL_NOT_EXISTS); + } + + // 3. 校验产品状态,发布状态下,不允许操作功能 + validateProductStatus(thingModel.getProductId()); + + // 2. 删除功能 + productThingModelMapper.deleteById(id); + + // 3. 如果删除的是属性,需要更新默认的事件和服务 + if (Objects.equals(thingModel.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey()); + } + } + + @Override + public IotProductThingModelDO getProductThingModel(Long id) { + return productThingModelMapper.selectById(id); + } + + @Override + public List getProductThingModelListByProductId(Long productId) { + return productThingModelMapper.selectListByProductId(productId); + } + + @Override + public PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) { + return productThingModelMapper.selectPage(pageReqVO); + } + + @Override + public List getProductThingModelListByProductKey(String productKey) { + return productThingModelMapper.selectListByProductKey(productKey); + } + + /** + * 校验功能是否存在 + * + * @param id 功能编号 + */ + private void validateProductThingModelMapperExists(Long id) { + if (productThingModelMapper.selectById(id) == null) { + throw exception(THING_MODEL_NOT_EXISTS); + } + } + + private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { + IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); + if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) { + throw exception(THING_MODEL_IDENTIFIER_EXISTS); + } + } + private void validateProductStatus(Long createReqVO) { IotProductDO product = productService.getProduct(createReqVO); if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) { @@ -107,99 +194,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } } - @Override - @Transactional(rollbackFor = Exception.class) - public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { - // 1. 校验功能是否存在 - validateProductThingModelMapperExists(updateReqVO.getId()); - - // 2. 校验功能标识符是否唯一 - validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); - - // 3. 校验产品状态,发布状态下,不允许操作功能 - validateProductStatus(updateReqVO.getProductId()); - - // 4. 更新数据库 - IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(updateReqVO); - productThingModelMapper.updateById(thingModel); - - // 5. 如果更新的是属性,需要更新默认的事件和服务 - if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { - createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); - } - } - - private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { - IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); - if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) { - throw exception(THING_MODEL_IDENTIFIER_EXISTS); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deleteProductThingModel(Long id) { - // 1. 校验功能是否存在 - IotProductThingModelDO thingModel = productThingModelMapper.selectById(id); - if (thingModel == null) { - throw exception(THING_MODEL_NOT_EXISTS); - } - - // 3. 校验产品状态,发布状态下,不允许操作功能 - validateProductStatus(thingModel.getProductId()); - - // 2. 删除功能 - productThingModelMapper.deleteById(id); - - // 3. 如果删除的是属性,需要更新默认的事件和服务 - if (Objects.equals(thingModel.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { - createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey()); - } - } - - /** - * 校验功能是否存在 - * - * @param id 功能编号 - */ - private void validateProductThingModelMapperExists(Long id) { - if (productThingModelMapper.selectById(id) == null) { - throw exception(THING_MODEL_NOT_EXISTS); - } - } - - @Override - public IotProductThingModelDO getProductThingModel(Long id) { - return productThingModelMapper.selectById(id); - } - - @Override - public List getProductThingModelListByProductId(Long productId) { - return productThingModelMapper.selectListByProductId(productId); - } - - @Override - public PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) { - return productThingModelMapper.selectPage(pageReqVO); - } - - @Override - public void createSuperTableDataModel(Long productId) { - // 1. 查询产品 - IotProductDO product = productService.getProduct(productId); - - // 2. 查询产品的物模型功能列表 - List thingModelList = productThingModelMapper.selectListByProductId(productId); - - // 3. 生成 TDengine 的数据模型 - dbStructureDataService.createSuperTableDataModel(product, thingModelList); - } - - @Override - public List getProductThingModelListByProductKey(String productKey) { - return productThingModelMapper.selectListByProductKey(productKey); - } - /** * 创建默认的事件和服务 */ @@ -210,231 +204,138 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ // 2. 生成新的事件和服务列表 List newThingModelList = new ArrayList<>(); - // 生成属性上报事件 + // 2.1 生成属性上报事件 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); if (propertyPostEvent != null) { - IotProductThingModelDO eventThingModel = buildEventThingModelDO(productId, productKey, propertyPostEvent); - newThingModelList.add(eventThingModel); + newThingModelList.add(buildEventThingModelDO(productId, productKey, propertyPostEvent)); } - // 生成属性设置服务 + // 2.2 生成属性设置服务 ThingModelService propertySetService = generatePropertySetService(propertyList); if (propertySetService != null) { - IotProductThingModelDO setServiceThingModel = buildServiceThingModelDO(productId, productKey, propertySetService); - newThingModelList.add(setServiceThingModel); + newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertySetService)); } - // 生成属性获取服务 + // 2.3 生成属性获取服务 ThingModelService propertyGetService = generatePropertyGetService(propertyList); if (propertyGetService != null) { - IotProductThingModelDO getServiceThingModel = buildServiceThingModelDO(productId, productKey, propertyGetService); - newThingModelList.add(getServiceThingModel); + newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertyGetService)); } - // 3. 获取数据库中的默认的旧事件和服务列表 + // 3.1 获取数据库中的默认的旧事件和服务列表 List oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) ); - - // 3.1 使用 diffList 方法比较新旧列表 - List> diffResult = diffList(oldThingModelList, newThingModelList, - // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 - (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier()) - && Objects.equals(oldFunc.getType(), newFunc.getType())); - List createList = diffResult.get(0); // 需要新增的 - List updateList = diffResult.get(1); // 需要更新的 - List deleteList = diffResult.get(2); // 需要删除的 - - // 3.2 批量执行数据库操作 - // 新增数据库中的新事件和服务列表 - if (CollUtil.isNotEmpty(createList)) { - productThingModelMapper.insertBatch(createList); - } - // 更新数据库中的事件和服务列表 - if (CollUtil.isNotEmpty(updateList)) { - // 首先,为每个需要更新的对象设置其对应的 ID - updateList.forEach(updateFunc -> { - IotProductThingModelDO oldFunc = findThingModelByIdentifierAndType( - oldThingModelList, updateFunc.getIdentifier(), updateFunc.getType()); - if (oldFunc != null) { - updateFunc.setId(oldFunc.getId()); - } - }); - // 过滤掉没有设置 ID 的对象 - List validUpdateList = filterList(updateList, thingModel -> thingModel.getId() != null); - // 执行批量更新 - if (CollUtil.isNotEmpty(validUpdateList)) { - productThingModelMapper.updateBatch(validUpdateList); - } - } - - // 删除数据库中的旧事件和服务列表 - if (CollUtil.isNotEmpty(deleteList)) { - Set idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThingModelDO::getId); - productThingModelMapper.deleteByIds(idsToDelete); - } + // 3.2 创建默认的事件和服务 + createDefaultEventsAndServices(oldThingModelList, newThingModelList); } /** - * 根据标识符和类型查找功能对象 + * 创建默认的事件和服务 */ - private IotProductThingModelDO findThingModelByIdentifierAndType(List thingModelList, - String identifier, Integer type) { - return CollUtil.findOne(thingModelList, func -> - Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)); + private void createDefaultEventsAndServices(List oldThingModelList, List newThingModelList) { + // 1.1 使用 diffList 方法比较新旧列表 + List> diffResult = diffList(oldThingModelList, newThingModelList, + (oldVal, newVal) -> { + // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 + boolean same = Objects.equals(oldVal.getIdentifier(), newVal.getIdentifier()) + && Objects.equals(oldVal.getType(), newVal.getType()); + if (same) { + newVal.setId(oldVal.getId()); // 设置编号 + } + return same; + }); + // 1.2 批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffResult.get(0))) { + productThingModelMapper.insertBatch(diffResult.get(0)); + } + if (CollUtil.isNotEmpty(diffResult.get(1))) { + productThingModelMapper.updateBatch(diffResult.get(1)); + } + if (CollUtil.isNotEmpty(diffResult.get(2))) { + productThingModelMapper.deleteByIds(convertSet(diffResult.get(2), IotProductThingModelDO::getId)); + } } /** * 构建事件功能对象 */ private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event) { - return new IotProductThingModelDO() - .setProductId(productId) - .setProductKey(productKey) - .setIdentifier(event.getIdentifier()) - .setName(event.getName()) - .setDescription(event.getDescription()) - .setType(IotProductThingModelTypeEnum.EVENT.getType()) - .setEvent(event); + return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) + .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(event.getDescription()) + .setType(IotProductThingModelTypeEnum.EVENT.getType()).setEvent(event); } /** * 构建服务功能对象 */ private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service) { - return new IotProductThingModelDO() - .setProductId(productId) - .setProductKey(productKey) - .setIdentifier(service.getIdentifier()) - .setName(service.getName()) - .setDescription(service.getDescription()) - .setType(IotProductThingModelTypeEnum.SERVICE.getType()) - .setService(service); + return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) + .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(service.getDescription()) + .setType(IotProductThingModelTypeEnum.SERVICE.getType()).setService(service); } /** * 生成属性上报事件 */ - private ThingModelEvent generatePropertyPostEvent(List propertyList) { - if (CollUtil.isEmpty(propertyList)) { + private ThingModelEvent generatePropertyPostEvent(List thingModelList) { + // 1.1 没有属性则不生成 + if (CollUtil.isEmpty(thingModelList)) { return null; } - ThingModelEvent event = new ThingModelEvent() - .setIdentifier("post") - .setName("属性上报") - .setType("info") - .setDescription("属性上报事件") - .setMethod("thing.event.property.post"); - - // 将属性列表转换为事件的输出参数 - List outputData = new ArrayList<>(); - for (IotProductThingModelDO thingModel : propertyList) { - ThingModelArgument arg = new ThingModelArgument() - .setIdentifier(thingModel.getIdentifier()) - .setName(thingModel.getName()) - .setProperty(thingModel.getProperty()) - .setDescription(thingModel.getDescription()) - .setDirection("output"); // 设置为输出参数 - outputData.add(arg); - } - event.setOutputData(outputData); - return event; + // 1.2 生成属性上报事件 + return new ThingModelEvent().setIdentifier("post").setName("属性上报").setDescription("属性上报事件") + .setEventType(IotProductThingModelServiceEventTypeEnum.INFO.getType()).setMethod("thing.event.property.post") + .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); } /** * 生成属性设置服务 */ - private ThingModelService generatePropertySetService(List propertyList) { - if (propertyList == null || propertyList.isEmpty()) { + private ThingModelService generatePropertySetService(List thingModelList) { + // 1.1 过滤出所有可写属性 + thingModelList = filterList(thingModelList, thingModel -> + IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(thingModel.getProperty().getAccessMode())); + // 1.2 没有可写属性则不生成 + if (CollUtil.isEmpty(thingModelList)) { return null; } - List inputData = new ArrayList<>(); - for (IotProductThingModelDO thingModel : propertyList) { - ThingModelProperty property = thingModel.getProperty(); - if (IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { - ThingModelArgument arg = new ThingModelArgument() - .setIdentifier(property.getIdentifier()) - .setName(property.getName()) - .setProperty(property) - .setDescription(property.getDescription()) - .setDirection("input"); // 设置为输入参数 - inputData.add(arg); - } - } - if (inputData.isEmpty()) { - // 如果没有可写属性,不生成属性设置服务 - return null; - } - - // 属性设置服务一般不需要输出参数 - return new ThingModelService() - .setIdentifier("set") - .setName("属性设置") - .setCallType("async") - .setDescription("属性设置服务") - .setMethod("thing.service.property.set") - .setInputData(inputData) - // 属性设置服务一般不需要输出参数 - .setOutputData(new ArrayList<>()); + // 2. 生成属性设置服务 + return new ThingModelService().setIdentifier("set").setName("属性设置").setDescription("属性设置服务") + .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()).setMethod("thing.service.property.set") + .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) + .setOutputParams(Collections.emptyList()); // 属性设置服务一般不需要输出参数 } /** * 生成属性获取服务 */ - private ThingModelService generatePropertyGetService(List propertyList) { - if (propertyList == null || propertyList.isEmpty()) { + private ThingModelService generatePropertyGetService(List thingModelList) { + // 1.1 没有属性则不生成 + if (CollUtil.isEmpty(thingModelList)) { return null; } - List outputData = new ArrayList<>(); - for (IotProductThingModelDO thingModelDO : propertyList) { - ThingModelProperty property = thingModelDO.getProperty(); - if (ObjectUtils.equalsAny(property.getAccessMode(), - IotProductThingModelAccessModeEnum.READ_ONLY.getMode(), IotProductThingModelAccessModeEnum.READ_WRITE.getMode())) { - ThingModelArgument arg = new ThingModelArgument() - .setIdentifier(property.getIdentifier()) - .setName(property.getName()) - .setProperty(property) - .setDescription(property.getDescription()) - .setDirection("output"); // 设置为输出参数 - outputData.add(arg); - } - } - if (outputData.isEmpty()) { - // 如果没有可读属性,不生成属性获取服务 - return null; - } + // 1.2 生成属性获取服务 + return new ThingModelService().setIdentifier("get").setName("属性获取").setDescription("属性获取服务") + .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()).setMethod("thing.service.property.get") + .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) + .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); + } - ThingModelService service = new ThingModelService() - .setIdentifier("get") - .setName("属性获取") - .setCallType("async") - .setDescription("属性获取服务") - .setMethod("thing.service.property.get"); - - // 定义输入参数:属性标识符列表 - ThingModelArgument inputArg = new ThingModelArgument() - .setIdentifier("properties") - .setName("属性标识符列表") - .setDescription("需要获取的属性标识符列表") - .setDirection("input"); // 设置为输入参数 - - // 创建数组类型,元素类型为文本类型(字符串)TODO @puhui999: 还得研究研究 - ThingModelArrayDataSpecs arrayType = new ThingModelArrayDataSpecs(); - arrayType.setDataType("array"); - inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) - .setDescription(inputArg.getDescription()).setDataSpecs(arrayType)); - - ThingModelDateOrTextDataSpecs textType = new ThingModelDateOrTextDataSpecs(); - textType.setDataType("text"); - inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) - .setDescription(inputArg.getDescription()).setDataSpecs(textType)); - - service.setInputData(Collections.singletonList(inputArg)); - service.setOutputData(outputData); - return service; + /** + * 构建输入/输出参数列表 + * + * @param thingModelList 属性列表 + * @return 输入/输出参数列表 + */ + private List buildInputOutputParam(List thingModelList, + IotProductThingModelParamDirectionEnum directionEnum) { + return convertList(thingModelList, thingModel -> + BeanUtils.toBean(thingModel.getProperty(), ThingModelInputOutputParam.class).setParaOrder(0) // TODO @puhui999: 先搞个默认值看看怎么个事 + .setDirection(directionEnum.getDirection())); } } From 38796cc4d4aa0c6e485c861c4cdff0792890c6e8 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 25 Dec 2024 18:36:22 +0800 Subject: [PATCH 051/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IOT:=20ThingModel=20=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=92=8C=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/controller/admin/thingmodel/model/ThingModelEvent.java | 2 +- .../iot/service/thingmodel/IotProductThingModelServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index 315d4d036..0e30ad81a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -37,7 +37,7 @@ public class ThingModelEvent { * * 关联枚举 {@link IotProductThingModelServiceEventTypeEnum} */ - private String eventType; + private String type; /** * 事件的输出参数 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java index e195464f9..059263289 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java @@ -286,7 +286,7 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ // 1.2 生成属性上报事件 return new ThingModelEvent().setIdentifier("post").setName("属性上报").setDescription("属性上报事件") - .setEventType(IotProductThingModelServiceEventTypeEnum.INFO.getType()).setMethod("thing.event.property.post") + .setType(IotProductThingModelServiceEventTypeEnum.INFO.getType()).setMethod("thing.event.property.post") .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); } From 1f9af15e7163c754c1a17386e15654ca7cde0d5f Mon Sep 17 00:00:00 2001 From: puhui999 Date: Thu, 26 Dec 2024 00:15:57 +0800 Subject: [PATCH 052/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IOT:=20ThingModel=20=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=92=8C=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/controller/admin/thingmodel/model/ThingModelEvent.java | 1 + .../admin/thingmodel/model/ThingModelInputOutputParam.java | 3 ++- .../controller/admin/thingmodel/model/ThingModelProperty.java | 1 + .../controller/admin/thingmodel/model/ThingModelService.java | 1 + .../service/thingmodel/IotProductThingModelServiceImpl.java | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index 0e30ad81a..55a64a268 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -24,6 +24,7 @@ public class ThingModelEvent { /** * 事件描述 */ + // TODO @puhui999: 考虑移除 private String description; /** * 是否是标准品类的必选事件。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java index 60e37f73f..d50c6343b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java @@ -7,7 +7,7 @@ import lombok.Data; import java.util.List; /** - * IOT 产品物模型中的服务、事件的输入输出参数 + * IOT 产品物模型中的参数 // TODO @puhui999 考虑要不改成 ThingModelParam ? * * @author HUIHUI */ @@ -25,6 +25,7 @@ public class ThingModelInputOutputParam { /** * 参数描述 */ + // TODO @puhui999: 考虑移除 private String description; /** * 用于区分输入或输出参数 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index 0c9105a8b..3a7fcbaaf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -27,6 +27,7 @@ public class ThingModelProperty { /** * 属性描述 */ + // TODO @puhui999: 考虑移除 private String description; /** * 云端可以对该属性进行的操作类型 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index 3fec2762f..8100537e1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -24,6 +24,7 @@ public class ThingModelService { /** * 服务描述 */ + // TODO @puhui999: 考虑移除 private String description; /** * 是否是标准品类的必选服务。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java index 059263289..c87d0d5b4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java @@ -70,6 +70,7 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } + // TODO @puhui999: 服务和事件的情况 method 怎么设置?在前端设置还是后端设置? return thingModel.getId(); } From 064b3381df854d0613f0dac1cbc6bd45fcb0db1c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 26 Dec 2024 07:55:15 +0800 Subject: [PATCH 053/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E3=80=91IoT=EF=BC=9A=E5=BC=B1=E5=8C=96=20TdEngineDDLM?= =?UTF-8?q?apper=20=E5=B0=81=E8=A3=85=EF=BC=8C=E7=94=B1=E6=AF=8F=E4=B8=AA?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E7=8B=AC=E7=AB=8B=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thingmodel/IotDataSpecsDataTypeEnum.java | 27 ++ .../iot/api/device/DeviceDataApiImpl.java | 4 +- .../admin/device/IotDeviceDataController.java | 4 +- .../thingmodel/model/ThingModelProperty.java | 5 +- .../ThingModelDateOrTextDataSpecs.java | 2 +- .../dal/dataobject/tdengine/FieldParser.java | 2 + .../iot/dal/dataobject/tdengine/SelectDO.java | 3 +- .../dataobject/tdengine/SelectVisualDO.java | 1 + .../dal/dataobject/tdengine/TagsSelectDO.java | 1 + .../dal/dataobject/tdengine/TdFieldDO.java | 2 + .../dal/dataobject/tdengine/TdResponse.java | 1 + .../dal/dataobject/tdengine/TdRestApi.java | 1 + .../dal/dataobject/tdengine/TdTableDO.java | 1 + .../thingmodel/IotProductThingModelDO.java | 1 + .../tdengine/IotDevicePropertyDataMapper.java | 55 ++++ .../iot/dal/tdengine/TdEngineDDLMapper.java | 1 - .../iot/emq/service/EmqxServiceImpl.java | 5 +- .../tdengine/core/TDengineTableField.java | 63 +++++ .../tdengine/core/annotation/TDengineDS.java | 17 ++ .../iot/framework/tdengine/package-info.java | 4 + ...java => IotDevicePropertyDataService.java} | 12 +- ... => IotDevicePropertyDataServiceImpl.java} | 82 +++++- .../product/IotProductServiceImpl.java | 8 +- .../tdengine/IotSuperTableService.java | 19 -- .../tdengine/IotSuperTableServiceImpl.java | 260 ------------------ .../IotProductThingModelService.java | 7 - .../IotProductThingModelServiceImpl.java | 15 - .../device/IotDevicePropertyDataMapper.xml | 45 +++ 28 files changed, 329 insertions(+), 319 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/annotation/TDengineDS.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/package-info.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/{IotDeviceDataService.java => IotDevicePropertyDataService.java} (84%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/{IotDeviceDataServiceImpl.java => IotDevicePropertyDataServiceImpl.java} (60%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java new file mode 100644 index 000000000..5133b0038 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.enums.thingmodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * IoT 数据定义的数据类型枚举类 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum IotDataSpecsDataTypeEnum { + + INT("int"), + FLOAT("float"), + DOUBLE("double"), + ENUM("enum"), + BOOL("bool"), + TEXT("text"), + DATE("date"), + STRUCT("struct"), + ARRAY("array"); + + private final String dataType; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java index d62c20cb5..b4a2a62db 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.api.device; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; +import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -14,7 +14,7 @@ import javax.annotation.Resource; public class DeviceDataApiImpl implements DeviceDataApi { @Resource - private IotDeviceDataService deviceDataService; + private IotDevicePropertyDataService deviceDataService; @Override public void saveDeviceData(String productKey, String deviceName, String message) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 77bc78c66..a626951ed 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/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 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotTimeDataRespVO; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; +import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -29,7 +29,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; public class IotDeviceDataController { @Resource - private IotDeviceDataService deviceDataService; + private IotDevicePropertyDataService deviceDataService; // TODO @浩浩:这里的 /latest-list,包括方法名。 @GetMapping("/latest") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index 0c9105a8b..f296cecd6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -30,7 +30,8 @@ public class ThingModelProperty { private String description; /** * 云端可以对该属性进行的操作类型 - * 关联枚举 {@link IotProductThingModelAccessModeEnum} + * + * 枚举 {@link IotProductThingModelAccessModeEnum} */ private String accessMode; /** @@ -42,6 +43,8 @@ public class ThingModelProperty { private Boolean required; /** * 数据类型,与 dataSpecs 的 dataType 保持一致 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum} */ private String dataType; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java index 8d5ddff62..9d2c88ae1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java @@ -20,7 +20,7 @@ public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs { * 数据长度,单位为字节。取值不能超过 2048。 * 当 dataType 为 text 时,需传入该参数。 */ - private Long length; + private Integer length; /** * 默认值,可选参数,用于存储默认值。 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java index d62781779..2e4e0f507 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ b/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 { /** * 物模型到td数据类型映射 */ + @Deprecated private static final HashMap TYPE_MAPPING = new HashMap<>() { { put("INT", "INT"); @@ -74,6 +75,7 @@ public class FieldParser { /** * 获取字段字义 */ + @Deprecated public static String getFieldDefine(TdFieldDO field) { return "`" + field.getFieldName() + "`" + " " + (field.getDataLength() > 0 ? String.format("%s(%d)", field.getDataType(), field.getDataLength()) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java index 542dd1e7b..fb4cd459a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java +++ b/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; import lombok.Data; -import java.util.Set; - // TODO @haohao:类似这个,其实可以参考 mybatis plus,querywrapper,搞个 TdEngineQueryWrapper。这样看起来会更好懂。 /** * 查询DO */ @Data +@Deprecated public class SelectDO { // TODO @haoha:database 是个单词 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java index 44acc3ac5..584562bfa 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java @@ -6,6 +6,7 @@ import java.util.Map; // TODO @haohao:类似 SelectDO 的想法,只是它是返回。ps:貌似可以在 tdengine 里面,创建一个 query 包,放这种比较特殊的查询和结果对象。dataobject 更多还是实际存储的结构化的 do @Data +@Deprecated public class SelectVisualDO { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java index 9fae91599..353830824 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java @@ -6,6 +6,7 @@ import lombok.Data; * tags查询DO */ @Data +@Deprecated public class TagsSelectDO { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java index 2e1751509..10c9b9fe7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java +++ b/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; import lombok.Data; import lombok.NoArgsConstructor; +// TODO 芋艿:看看是不是后续简化掉。 /** * TD 引擎的字段 */ @@ -12,6 +13,7 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Builder +@Deprecated public class TdFieldDO { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java index aca5cece5..8b64f6854 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java @@ -12,6 +12,7 @@ import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor +@Deprecated public class TdResponse { public static final int CODE_SUCCESS = 0; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java index b2d1ac029..1bb793a45 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java @@ -13,6 +13,7 @@ import org.springframework.stereotype.Service; */ @Slf4j @Service +@Deprecated // TODO 芋艿:貌似没用到 public class TdRestApi { @Value("${spring.datasource.dynamic.datasource.tdengine.url}") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java index 3b30352e4..3265c3ebe 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java @@ -7,6 +7,7 @@ import lombok.NoArgsConstructor; import java.util.List; +@Deprecated /** * TD 引擎的数据库 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java index 3d9e5e5fe..f2edc5db7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java @@ -16,6 +16,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +// TODO @huihui:IotProductThingModelDO => IotThingModelDO /** * IoT 产品物模型功能 DO *

diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java new file mode 100644 index 000000000..540918928 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; +import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.stream.Collectors; + +@Mapper +@TDengineDS +@InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 +public interface IotDevicePropertyDataMapper { + + List getProductPropertySTableFieldList(@Param("productKey") String productKey); + + void createProductPropertySTable(@Param("productKey") String productKey, + @Param("fields") List fields); + + @SuppressWarnings("SimplifyStreamApiCallChains") // 保持 JDK8 兼容性 + default void alterProductPropertySTable(String productKey, + List oldFields, + List newFields) { + oldFields.removeIf(field -> TDengineTableField.FIELD_TS.equals(field.getField()) + || TDengineTableField.FIELD_DEVICE_KEY.equals(field.getField())); + List addFields = newFields.stream().filter( // 新增的字段 + newField -> oldFields.stream().noneMatch(oldField -> oldField.getField().equals(newField.getField()))) + .collect(Collectors.toList()); + List modifyFields = newFields.stream().filter( // 更新的字段 + newField -> oldFields.stream().anyMatch(oldField -> oldField.getField().equals(newField.getField()) + && (ObjectUtil.notEqual(oldField.getType(), newField.getType()) + || (newField.getLength() != null && ObjectUtil.notEqual(oldField.getLength(), newField.getLength()))))) + .collect(Collectors.toList()); + List dropFields = oldFields.stream().filter( // 删除的字段 + oldField -> newFields.stream().noneMatch(n -> n.getField().equals(oldField.getField()))) + .collect(Collectors.toList()); + addFields.forEach(field -> alterProductPropertySTableAddField(productKey, field)); + // TODO 芋艿:tdengine 只允许 modify 长度;如果 type 变化,只能 drop + add + modifyFields.forEach(field -> alterProductPropertySTableModifyField(productKey, field)); + dropFields.forEach(field -> alterProductPropertySTableDropField(productKey, field)); + } + + void alterProductPropertySTableAddField(@Param("productKey") String productKey, + @Param("field") TDengineTableField field); + + void alterProductPropertySTableModifyField(@Param("productKey") String productKey, + @Param("field") TDengineTableField field); + + void alterProductPropertySTableDropField(@Param("productKey") String productKey, + @Param("field") TDengineTableField field); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java index 3d7aa84dd..eeb061cc5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java @@ -96,7 +96,6 @@ public interface TdEngineDDLMapper { @TenantIgnore void modifyColumnWidthForSuperTable(TdTableDO superTable); - /** * 修改超级表 - 为超级表添加标签 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index 343f9ba21..46217a22b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.emq.service; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; +import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttClient; @@ -21,7 +20,7 @@ import org.springframework.stereotype.Service; public class EmqxServiceImpl implements EmqxService { @Resource - private IotDeviceDataService iotDeviceDataService; + private IotDevicePropertyDataService iotDeviceDataService; // TODO 多线程处理消息 @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java new file mode 100644 index 000000000..427c68189 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.iot.framework.tdengine.core; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * TDEngine 表字段 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class TDengineTableField { + + /** + * 字段名 - TDengine 默认 ts 字段,默认会被 TDengine 创建 + */ + public static final String FIELD_TS = "ts"; + + /** + * 字段名 - 我们系统定义的 device_key 字段,非 TDengine 默认字段 + */ + public static final String FIELD_DEVICE_KEY = "device_key"; + + public static final String TYPE_TINYINT = "TINYINT"; + public static final String TYPE_INT = "INT"; + public static final String TYPE_FLOAT = "FLOAT"; + public static final String TYPE_DOUBLE = "DOUBLE"; + public static final String TYPE_BOOL = "BOOL"; + public static final String TYPE_NCHAR = "NCHAR"; + public static final String TYPE_TIMESTAMP = "TIMESTAMP"; + + /** + * 注释 - TAG 字段 + */ + public static final String NOTE_TAG = "TAG"; + + /** + * 字段名 + */ + private String field; + + /** + * 字段类型 + */ + private String type; + + /** + * 字段长度 + */ + private Integer length; + + /** + * 注释 + */ + private String note; + + public TDengineTableField(String field, String type) { + this.field = field; + this.type = type; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/annotation/TDengineDS.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/annotation/TDengineDS.java new file mode 100644 index 000000000..e3960d026 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/annotation/TDengineDS.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation; + +import com.baomidou.dynamic.datasource.annotation.DS; + +import java.lang.annotation.*; + +/** + * TDEngine 数据源 + * + * @author 芋道源码 + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@DS("tdengine") +public @interface TDengineDS { +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/package-info.java new file mode 100644 index 000000000..f92428f7b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/package-info.java @@ -0,0 +1,4 @@ +/** + * iot 模块的 tdengine 拓展封装 + */ +package cn.iocoder.yudao.module.iot.framework.tdengine; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java similarity index 84% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java index 1c246e2c7..08375cb09 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/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; import java.util.Map; /** - * IoT 设备数据 Service 接口 + * IoT 设备【属性】数据 Service 接口 * * @author 芋道源码 */ -public interface IotDeviceDataService { +public interface IotDevicePropertyDataService { + + /** + * 定义设备属性数据的结构 + * + * @param productId 产品编号 + */ + void defineDevicePropertyData(Long productId); /** * 保存设备数据 @@ -40,4 +47,5 @@ public interface IotDeviceDataService { * @return 设备属性历史数据 */ PageResult> getHistoryDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java similarity index 60% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index 4cb39c0bc..e0de0ac3d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -1,19 +1,27 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import jakarta.annotation.Resource; @@ -28,11 +36,32 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; -@Slf4j +/** + * IoT 设备【属性】数据 Service 实现类 + * + * @author 芋道源码 + */ @Service -public class IotDeviceDataServiceImpl implements IotDeviceDataService { +@Slf4j +public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataService { + + /** + * 物模型的数据类型,与 TDengine 数据类型的映射关系 + */ + private static final Map TYPE_MAPPING = MapUtil.builder() + .put(IotDataSpecsDataTypeEnum.INT.getDataType(), TDengineTableField.TYPE_INT) + .put(IotDataSpecsDataTypeEnum.FLOAT.getDataType(), TDengineTableField.TYPE_FLOAT) + .put(IotDataSpecsDataTypeEnum.DOUBLE.getDataType(), TDengineTableField.TYPE_DOUBLE) + .put(IotDataSpecsDataTypeEnum.ENUM.getDataType(), TDengineTableField.TYPE_TINYINT) // TODO 芋艿:为什么要映射为 TINYINT 的说明? + .put( IotDataSpecsDataTypeEnum.BOOL.getDataType(), TDengineTableField.TYPE_TINYINT) // TODO 芋艿:为什么要映射为 TINYINT 的说明? + .put(IotDataSpecsDataTypeEnum.TEXT.getDataType(), TDengineTableField.TYPE_NCHAR) + .put(IotDataSpecsDataTypeEnum.DATE.getDataType(), TDengineTableField.TYPE_TIMESTAMP) + .put(IotDataSpecsDataTypeEnum.STRUCT.getDataType(), TDengineTableField.TYPE_NCHAR) // TODO 芋艿:怎么映射!!!! + .put(IotDataSpecsDataTypeEnum.ARRAY.getDataType(), TDengineTableField.TYPE_NCHAR) // TODO 芋艿:怎么映射!!!! + .build(); @Value("${spring.datasource.dynamic.datasource.tdengine.url}") private String url; @@ -43,12 +72,61 @@ public class IotDeviceDataServiceImpl implements IotDeviceDataService { private IotThingModelMessageService thingModelMessageService; @Resource private IotProductThingModelService thingModelService; + @Resource + private IotProductService productService; + @Resource private TdEngineDMLMapper tdEngineDMLMapper; @Resource private DeviceDataRedisDAO deviceDataRedisDAO; + @Resource + private IotDevicePropertyDataMapper devicePropertyDataMapper; + + @Override + public void defineDevicePropertyData(Long productId) { + // 1.1 查询产品和物模型 + IotProductDO product = productService.validateProductExists(productId); + List thingModels = filterList(thingModelService.getProductThingModelListByProductId(productId), + thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); + // 1.2 解析 DB 里的字段 + List oldFields = new ArrayList<>(); + try { + oldFields.addAll(devicePropertyDataMapper.getProductPropertySTableFieldList(product.getProductKey())); + } catch (Exception e) { + if (!e.getMessage().contains("Table does not exist")) { + throw e; + } + } + + // 2.1 情况一:如果是新增的时候,需要创建表 + List newFields = buildTableFieldList(thingModels); + if (CollUtil.isEmpty(oldFields)) { + if (CollUtil.isEmpty(newFields)) { + log.info("[defineDevicePropertyData][productId({}) 没有需要定义的属性]", productId); + return; + } + newFields.add(0, new TDengineTableField(TDengineTableField.FIELD_TS, TDengineTableField.TYPE_TIMESTAMP)); + devicePropertyDataMapper.createProductPropertySTable(product.getProductKey(), newFields); + return; + } + // 2.2 情况二:如果是修改的时候,需要更新表 + devicePropertyDataMapper.alterProductPropertySTable(product.getProductKey(), oldFields, newFields); + } + + private List buildTableFieldList(List thingModels) { + return convertList(thingModels, thingModel -> { + TDengineTableField field = new TDengineTableField( + thingModel.getIdentifier().toLowerCase(), // TODO 芋艿:为什么要转成小写? + TYPE_MAPPING.get(thingModel.getProperty().getDataType())); + if (thingModel.getProperty().getDataType().equals(IotDataSpecsDataTypeEnum.TEXT.getDataType())) { + field.setLength(((ThingModelDateOrTextDataSpecs) thingModel.getProperty().getDataSpecs()).getLength()); + } + return field; + }); + } + @Override public void saveDeviceData(String productKey, String deviceName, String message) { // 1. 根据产品 key 和设备名称,获得设备信息 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index a53aee55d..1d2e8892a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; +import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; @@ -39,6 +40,9 @@ public class IotProductServiceImpl implements IotProductService { @Resource @Lazy // 延迟加载,解决循环依赖 private IotThingModelMessageService thingModelMessageService; + @Resource + @Lazy // 延迟加载,解决循环依赖 + private IotDevicePropertyDataService devicePropertyDataService; @Override public Long createProduct(IotProductSaveReqVO createReqVO) { @@ -119,8 +123,8 @@ public class IotProductServiceImpl implements IotProductService { // 3. 产品是发布状态 if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { // 3.1 创建产品超级表数据模型 - thingModelFunctionService.createSuperTableDataModel(id); - // 3.2 创建物模型日志超级表数据模型 + devicePropertyDataService.defineDevicePropertyData(id); + // 3.2 创建物模型日志超级表数据模型 TODO 待定:message 要不要分; thingModelMessageService.createSuperTable(id); } productMapper.updateById(updateObj); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java deleted file mode 100644 index bb6d8c077..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableService.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - - -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; - -import java.util.List; - -/** - * IoT 超级表服务,负责根据物模型创建和更新超级表,以及创建超级表的子表等操作。 - */ -public interface IotSuperTableService { - - /** - * 创建超级表数据模型 - */ - void createSuperTableDataModel(IotProductDO product, List thingModelList); - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java deleted file mode 100644 index 1727fae62..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotSuperTableServiceImpl.java +++ /dev/null @@ -1,260 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelRespVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * IoT 超级表服务实现类,负责根据物模型创建和更新超级表,以及创建超级表的子表等操作。 - */ -@Service -@Slf4j -public class IotSuperTableServiceImpl implements IotSuperTableService { - - @Resource - private TdEngineDDLMapper tdEngineDDLMapper; - - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") - private String url; - - @Override - public void createSuperTableDataModel(IotProductDO product, List thingModelList) { - ThingModelRespVO thingModel = buildThingModel(product, thingModelList); - - if (thingModel.getModel() == null || CollUtil.isEmpty(thingModel.getModel().getProperties())) { - log.warn("物模型属性列表为空,不创建超级表"); - return; - } - - String superTableName = getSuperTableName(product.getDeviceType(), product.getProductKey()); - String databaseName = getDatabaseName(); - - List> results = tdEngineDDLMapper.showSuperTables(new TdTableDO(databaseName, superTableName)); - int tableExists = results == null || results.isEmpty() ? 0 : results.size(); - if (tableExists > 0) { - updateSuperTable(thingModel, product.getDeviceType()); - } else { - createSuperTable(thingModel, product.getDeviceType()); - } - } - - /** - * 创建超级表 - */ - private void createSuperTable(ThingModelRespVO thingModel, Integer deviceType) { - // 解析物模型,获取字段列表 - List schemaFields = new ArrayList<>(); - schemaFields.add(TdFieldDO.builder() - .fieldName("time") - .dataType("TIMESTAMP") - .build()); - schemaFields.addAll(FieldParser.parse(thingModel)); - - // 设置超级表的标签 - List tagsFields = List.of( - TdFieldDO.builder().fieldName("product_key").dataType("NCHAR").dataLength(64).build(), - TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build(), - TdFieldDO.builder().fieldName("device_name").dataType("NCHAR").dataLength(64).build(), - TdFieldDO.builder().fieldName("device_type").dataType("INT").build() - ); - - // 获取超级表的名称和数据库名称 - String superTableName = getSuperTableName(deviceType, thingModel.getProductKey()); - String databaseName = getDatabaseName(); - - // 创建超级表 - tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); - } - - /** - * 更新超级表 - */ - private void updateSuperTable(ThingModelRespVO thingModel, Integer deviceType) { - String superTableName = getSuperTableName(deviceType, thingModel.getProductKey()); - try { - List oldFields = getTableFields(superTableName); - List newFields = FieldParser.parse(thingModel); - - updateTableFields(superTableName, oldFields, newFields); - } catch (Exception e) { - log.error("更新物模型超级表失败: {}", e.getMessage(), e); - } - } - - /** - * 获取表的字段信息 - */ - private List getTableFields(String tableName) { - List> tableDescription = tdEngineDDLMapper.describeSuperTable(new TdTableDO(getDatabaseName(), tableName)); - if (CollUtil.isEmpty(tableDescription)) { - return Collections.emptyList(); - } - - return tableDescription.stream() - .filter(map -> !"TAG".equals(map.get("note"))) - .filter(map -> !"time".equals(map.get("field"))) - .map(map -> TdFieldDO.builder() - .fieldName((String) map.get("field")) - .dataType((String) map.get("type")) - .dataLength((Integer) map.get("length")) - .build()) - .collect(Collectors.toList()); - } - - /** - * 更新表的字段,包括新增、修改和删除字段 - */ - private void updateTableFields(String tableName, List oldFields, List newFields) { - String databaseName = getDatabaseName(); - - // 获取新增、修改、删除的字段 - List addFields = getAddFields(oldFields, newFields); - List modifyFields = getModifyFields(oldFields, newFields); - List dropFields = getDropFields(oldFields, newFields); - - // 添加新增字段 - if (CollUtil.isNotEmpty(addFields)) { - for (TdFieldDO addField : addFields) { - tdEngineDDLMapper.addColumnForSuperTable(TdTableDO.builder() - .dataBaseName(databaseName) - .superTableName(tableName) - .column(addField) - .build()); - } - } - // 删除旧字段 - if (CollUtil.isNotEmpty(dropFields)) { - for (TdFieldDO dropField : dropFields) { - tdEngineDDLMapper.dropColumnForSuperTable(TdTableDO.builder() - .dataBaseName(databaseName) - .superTableName(tableName) - .column(dropField) - .build()); - } - } - // 修改字段(先删除再添加) - if (CollUtil.isNotEmpty(modifyFields)) { - for (TdFieldDO modifyField : modifyFields) { - tdEngineDDLMapper.dropColumnForSuperTable(TdTableDO.builder() - .dataBaseName(databaseName) - .superTableName(tableName) - .column(modifyField) - .build()); - tdEngineDDLMapper.addColumnForSuperTable(TdTableDO.builder() - .dataBaseName(databaseName) - .superTableName(tableName) - .column(modifyField) - .build()); - } - } - } - - /** - * 获取需要新增的字段 - */ - private List getAddFields(List oldFields, List newFields) { - Set oldFieldNames = oldFields.stream() - .map(TdFieldDO::getFieldName) - .collect(Collectors.toSet()); - return newFields.stream() - .filter(f -> !oldFieldNames.contains(f.getFieldName())) - .collect(Collectors.toList()); - } - - /** - * 获取需要修改的字段 - */ - private List getModifyFields(List oldFields, List newFields) { - Map oldFieldMap = oldFields.stream() - .collect(Collectors.toMap(TdFieldDO::getFieldName, f -> f)); - - return newFields.stream() - .filter(f -> { - TdFieldDO oldField = oldFieldMap.get(f.getFieldName()); - return oldField != null && ( - !oldField.getDataType().equals(f.getDataType()) || - !Objects.equals(oldField.getDataLength(), f.getDataLength()) - ); - }) - .collect(Collectors.toList()); - } - - /** - * 获取需要删除的字段 - */ - private List getDropFields(List oldFields, List newFields) { - Set newFieldNames = newFields.stream() - .map(TdFieldDO::getFieldName) - .collect(Collectors.toSet()); - return oldFields.stream() - .filter(f -> !"time".equals(f.getFieldName())) - .filter(f -> !newFieldNames.contains(f.getFieldName())) - .collect(Collectors.toList()); - } - - /** - * 构建物模型 - */ - private ThingModelRespVO buildThingModel(IotProductDO product, List thingModelList) { - ThingModelRespVO thingModel = new ThingModelRespVO(); - thingModel.setId(product.getId()); - thingModel.setProductKey(product.getProductKey()); - - List properties = thingModelList.stream() - .filter(item -> IotProductThingModelTypeEnum.PROPERTY.equals( - IotProductThingModelTypeEnum.valueOfType(item.getType()))) - .map(this::buildThingModelProperty) - .collect(Collectors.toList()); - - ThingModelRespVO.Model model = new ThingModelRespVO.Model(); - model.setProperties(properties); - thingModel.setModel(model); - - return thingModel; - } - - /** - * 构建物模型属性 - */ - private ThingModelProperty buildThingModelProperty(IotProductThingModelDO thingModel) { - ThingModelProperty property = BeanUtil.copyProperties(thingModel, ThingModelProperty.class); - property.setDataType(thingModel.getProperty().getDataType()); - return property; - } - - /** - * 获取数据库名称 - */ - private String getDatabaseName() { - int index = url.lastIndexOf("/"); - return index != -1 ? url.substring(index + 1) : url; - } - - /** - * 获取超级表名称 - */ - private String getSuperTableName(Integer deviceType, String productKey) { - String prefix = switch (deviceType) { - case 1 -> "gateway_sub_"; - case 2 -> "gateway_"; - default -> "device_"; - }; - return (prefix + productKey).toLowerCase(); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java index 04086d0a7..6df29e101 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java @@ -61,13 +61,6 @@ public interface IotProductThingModelService { */ PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO); - /** - * 创建超级表数据模型 - * - * @param productId 产品编号 - */ - void createSuperTableDataModel(Long productId); - /** * 获得产品物模型列表 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java index ddb800eee..a53fb6947 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java @@ -21,7 +21,6 @@ import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; -import cn.iocoder.yudao.module.iot.service.tdengine.IotSuperTableService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -50,8 +49,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @Resource private IotProductService productService; - @Resource - private IotSuperTableService dbStructureDataService; @Override @Transactional(rollbackFor = Exception.class) @@ -183,18 +180,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ return productThingModelMapper.selectPage(pageReqVO); } - @Override - public void createSuperTableDataModel(Long productId) { - // 1. 查询产品 - IotProductDO product = productService.getProduct(productId); - - // 2. 查询产品的物模型功能列表 - List thingModelList = productThingModelMapper.selectListByProductId(productId); - - // 3. 生成 TDengine 的数据模型 - dbStructureDataService.createSuperTableDataModel(product, thingModelList); - } - @Override public List getProductThingModelListByProductKey(String productKey) { return productThingModelMapper.selectListByProductKey(productKey); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml new file mode 100644 index 000000000..9894e27a0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml @@ -0,0 +1,45 @@ + + + + + + + + CREATE STABLE product_property_${productKey} + + ${field.field} ${field.type} + + (${field.length}) + + + TAGS ( + device_key NCHAR(50) + ) + + + + ALTER STABLE product_property_${productKey} + ADD COLUMN ${field.field} ${field.type} + + (${field.length}) + + + + + ALTER STABLE product_property_${productKey} + MODIFY COLUMN ${field.field} ${field.type} + + (${field.length}) + + + + + ALTER STABLE product_property_${productKey} + DROP COLUMN ${field.field} + + + \ No newline at end of file From 245ab4e62d6b29addc266f6f176f912c262c3e1b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 26 Dec 2024 09:55:19 +0800 Subject: [PATCH 054/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E4=BF=AE=E5=A4=8D=20device=20?= =?UTF-8?q?=E5=BB=BA=E8=A1=A8=E6=97=B6=EF=BC=8Ctdengine=20=E5=88=86?= =?UTF-8?q?=E6=88=90=20length=20=E5=92=8C=20type=20=E7=9A=84=E6=83=85?= =?UTF-8?q?=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tdengine/IotDevicePropertyDataMapper.java | 36 +++++++++++++++---- .../IotDevicePropertyDataServiceImpl.java | 1 + .../service/device/IotDeviceServiceImpl.java | 1 + .../product/IotProductServiceImpl.java | 1 + 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java index 540918928..6053444fe 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; @@ -7,6 +8,7 @@ import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -29,18 +31,38 @@ public interface IotDevicePropertyDataMapper { List addFields = newFields.stream().filter( // 新增的字段 newField -> oldFields.stream().noneMatch(oldField -> oldField.getField().equals(newField.getField()))) .collect(Collectors.toList()); - List modifyFields = newFields.stream().filter( // 更新的字段 - newField -> oldFields.stream().anyMatch(oldField -> oldField.getField().equals(newField.getField()) - && (ObjectUtil.notEqual(oldField.getType(), newField.getType()) - || (newField.getLength() != null && ObjectUtil.notEqual(oldField.getLength(), newField.getLength()))))) - .collect(Collectors.toList()); List dropFields = oldFields.stream().filter( // 删除的字段 oldField -> newFields.stream().noneMatch(n -> n.getField().equals(oldField.getField()))) .collect(Collectors.toList()); + List modifyTypeFields = new ArrayList<>(); // 变更类型的字段 + List modifyLengthFields = new ArrayList<>(); // 变更长度的字段 + newFields.forEach(newField -> { + TDengineTableField oldField = CollUtil.findOne(oldFields, field -> field.getField().equals(newField.getField())); + if (oldField == null) { + return; + } + if (ObjectUtil.notEqual(oldField.getType(), newField.getType())) { + modifyTypeFields.add(newField); + return; + } + if (newField.getLength()!= null) { + if (newField.getLength() > oldField.getLength()) { + modifyLengthFields.add(newField); + } else if (newField.getLength() < oldField.getLength()) { + // 特殊:TDengine 长度修改时,只允许变长,所以此时认为是修改类型 + modifyTypeFields.add(newField); + } + } + }); + + // 执行 addFields.forEach(field -> alterProductPropertySTableAddField(productKey, field)); - // TODO 芋艿:tdengine 只允许 modify 长度;如果 type 变化,只能 drop + add - modifyFields.forEach(field -> alterProductPropertySTableModifyField(productKey, field)); dropFields.forEach(field -> alterProductPropertySTableDropField(productKey, field)); + modifyLengthFields.forEach(field -> alterProductPropertySTableModifyField(productKey, field)); + modifyTypeFields.forEach(field -> { + alterProductPropertySTableDropField(productKey, field); + alterProductPropertySTableAddField(productKey, field); + }); } void alterProductPropertySTableAddField(@Param("productKey") String productKey, diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index e0de0ac3d..5213decf6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -100,6 +100,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe } } + // TODO 芋艿:建表的时候,表名要小写么? // 2.1 情况一:如果是新增的时候,需要创建表 List newFields = buildTableFieldList(thingModels); if (CollUtil.isEmpty(oldFields)) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index a43521ff9..39bac8974 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -60,6 +60,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { throw exception(PRODUCT_NOT_EXISTS); } // 1.2 校验设备标识是否唯一 + // TODO 芋艿:校验时,需要跨租户唯一,避免 TDEngine 无法处理;并且要忽略大小写 if (deviceMapper.selectByDeviceKey(createReqVO.getDeviceKey()) != null) { throw exception(DEVICE_KEY_EXISTS); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 1d2e8892a..6b7a95f62 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -47,6 +47,7 @@ public class IotProductServiceImpl implements IotProductService { @Override public Long createProduct(IotProductSaveReqVO createReqVO) { // 1. 生成 ProductKey + // TODO 芋艿:校验时,需要跨租户唯一,避免 TDEngine 无法处理;并且要忽略大小写 if (productMapper.selectByProductKey(createReqVO.getProductKey()) != null) { throw exception(PRODUCT_KEY_EXISTS); } From 09a26666ec0036c0536ce891de7aef303ea53779 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 26 Dec 2024 12:51:36 +0800 Subject: [PATCH 055/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=91IoT=EF=BC=9A=E8=A7=A3=E5=86=B3=20device=20?= =?UTF-8?q?=E5=BB=BA=E8=A1=A8=E7=9A=84=E6=97=B6=E5=80=99=EF=BC=8Ctdengine?= =?UTF-8?q?=20=E9=BB=98=E8=AE=A4=E5=AD=97=E6=AE=B5=E9=83=BD=E6=98=AF?= =?UTF-8?q?=E5=B0=8F=E5=86=99=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E9=80=9A?= =?UTF-8?q?=E8=BF=87=20=5F=20=E8=A7=A3=E5=86=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/service/device/IotDevicePropertyDataServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index 5213decf6..99c04a843 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -100,7 +100,6 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe } } - // TODO 芋艿:建表的时候,表名要小写么? // 2.1 情况一:如果是新增的时候,需要创建表 List newFields = buildTableFieldList(thingModels); if (CollUtil.isEmpty(oldFields)) { @@ -119,7 +118,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe private List buildTableFieldList(List thingModels) { return convertList(thingModels, thingModel -> { TDengineTableField field = new TDengineTableField( - thingModel.getIdentifier().toLowerCase(), // TODO 芋艿:为什么要转成小写? + StrUtil.toUnderlineCase(thingModel.getIdentifier()), // TDengine 字段默认都是小写 TYPE_MAPPING.get(thingModel.getProperty().getDataType())); if (thingModel.getProperty().getDataType().equals(IotDataSpecsDataTypeEnum.TEXT.getDataType())) { field.setLength(((ThingModelDateOrTextDataSpecs) thingModel.getProperty().getDataSpecs()).getLength()); From 7b64b7fc69ad38c4cd9bd0616e68059d0661579f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 26 Dec 2024 12:57:56 +0800 Subject: [PATCH 056/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E8=B7=A8=E7=A7=9F=E6=88=B7?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=20ProductKey=20=E5=92=8C=20DeviceKey?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=E8=B7=A8=E7=A7=9F=E6=88=B7=E7=9A=84?= =?UTF-8?q?=20Tdengine=20=E8=A1=A8=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/dal/mysql/device/IotDeviceMapper.java | 4 +++- .../dal/mysql/product/IotProductMapper.java | 4 +++- .../service/device/IotDeviceServiceImpl.java | 10 ++++++---- .../service/product/IotProductServiceImpl.java | 18 +++++++++--------- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 893d7eefd..2ed10eee5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/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; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -47,7 +48,8 @@ public interface IotDeviceMapper extends BaseMapperX { } default IotDeviceDO selectByDeviceKey(String deviceKey) { - return selectOne(IotDeviceDO::getDeviceKey, deviceKey); + return selectOne(new LambdaQueryWrapper() + .apply("LOWER(device_key) = {0}", deviceKey.toLowerCase())); } default List selectList(Integer deviceType) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index aef149ae7..0f5625100 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/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; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; /** @@ -23,7 +24,8 @@ public interface IotProductMapper extends BaseMapperX { } default IotProductDO selectByProductKey(String productKey) { - return selectOne(IotProductDO::getProductKey, productKey); + return selectOne(new LambdaQueryWrapper() + .apply("LOWER(product_key) = {0}", productKey.toLowerCase())); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 39bac8974..1896b98b7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/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; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; @@ -60,10 +61,11 @@ public class IotDeviceServiceImpl implements IotDeviceService { throw exception(PRODUCT_NOT_EXISTS); } // 1.2 校验设备标识是否唯一 - // TODO 芋艿:校验时,需要跨租户唯一,避免 TDEngine 无法处理;并且要忽略大小写 - if (deviceMapper.selectByDeviceKey(createReqVO.getDeviceKey()) != null) { - throw exception(DEVICE_KEY_EXISTS); - } + TenantUtils.executeIgnore(() -> { + if (deviceMapper.selectByDeviceKey(createReqVO.getDeviceKey()) != null) { + throw exception(PRODUCT_KEY_EXISTS); + } + }); // 1.3 校验设备名称在同一产品下是否唯一 if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), createReqVO.getDeviceKey()) != null) { throw exception(DEVICE_NAME_EXISTS); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 6b7a95f62..d384e44c0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.service.product; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; @@ -9,7 +10,6 @@ import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; -import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; @@ -34,9 +34,6 @@ public class IotProductServiceImpl implements IotProductService { @Resource private IotProductMapper productMapper; - @Resource - @Lazy // 延迟加载,解决循环依赖 - private IotProductThingModelService thingModelFunctionService; @Resource @Lazy // 延迟加载,解决循环依赖 private IotThingModelMessageService thingModelMessageService; @@ -46,11 +43,14 @@ public class IotProductServiceImpl implements IotProductService { @Override public Long createProduct(IotProductSaveReqVO createReqVO) { - // 1. 生成 ProductKey - // TODO 芋艿:校验时,需要跨租户唯一,避免 TDEngine 无法处理;并且要忽略大小写 - if (productMapper.selectByProductKey(createReqVO.getProductKey()) != null) { - throw exception(PRODUCT_KEY_EXISTS); - } + // 1. 校验 ProductKey + TenantUtils.executeIgnore(() -> { + // 为什么忽略租户?避免多个租户之间,productKey 重复,导致 TDengine 设备属性表重复 + if (productMapper.selectByProductKey(createReqVO.getProductKey()) != null) { + throw exception(PRODUCT_KEY_EXISTS); + } + }); + // 2. 插入 IotProductDO product = BeanUtils.toBean(createReqVO, IotProductDO.class) .setStatus(IotProductStatusEnum.UNPUBLISHED.getStatus()); From fae17e91253fb8e23c6aecf955aa75603f437b15 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Thu, 26 Dec 2024 13:27:02 +0800 Subject: [PATCH 057/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IOT:=20ThingModel=20=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=92=8C=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/yudao-module-iot-biz/pom.xml | 7 ----- .../IotProductThingModelController.http | 2 +- .../thingmodel/model/ThingModelEvent.java | 5 ---- .../model/ThingModelInputOutputParam.java | 5 ---- .../thingmodel/model/ThingModelProperty.java | 5 ---- .../thingmodel/model/ThingModelService.java | 5 ---- .../dataType/ThingModelStructDataSpecs.java | 4 --- .../IotProductThingModelService.java | 7 ----- .../IotProductThingModelServiceImpl.java | 28 ++++++++++--------- 9 files changed, 16 insertions(+), 52 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 19b50ec21..d0ed0bcac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -25,13 +25,6 @@ ${revision} - - cn.iocoder.boot - yudao-module-iot-plugin-api - 0.0.1 - compile - - cn.iocoder.boot yudao-spring-boot-starter-biz-tenant diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http index 7742705ef..7e7aa05d6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http @@ -176,7 +176,7 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} ### 请求 /iot/product-thing-model/get 接口 => 成功 -GET {{baseUrl}}/iot/product-thing-model/get?id=40 +GET {{baseUrl}}/iot/product-thing-model/get?id=67 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index 55a64a268..f49f5f86e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -21,11 +21,6 @@ public class ThingModelEvent { * 事件名称 */ private String name; - /** - * 事件描述 - */ - // TODO @puhui999: 考虑移除 - private String description; /** * 是否是标准品类的必选事件。 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java index d50c6343b..3b7b1414f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java @@ -22,11 +22,6 @@ public class ThingModelInputOutputParam { * 参数名称 */ private String name; - /** - * 参数描述 - */ - // TODO @puhui999: 考虑移除 - private String description; /** * 用于区分输入或输出参数 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index 0865f403c..bb7376fc8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -24,11 +24,6 @@ public class ThingModelProperty { * 属性名称 */ private String name; - /** - * 属性描述 - */ - // TODO @puhui999: 考虑移除 - private String description; /** * 云端可以对该属性进行的操作类型 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index 8100537e1..0bdf498d3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -21,11 +21,6 @@ public class ThingModelService { * 服务名称 */ private String name; - /** - * 服务描述 - */ - // TODO @puhui999: 考虑移除 - private String description; /** * 是否是标准品类的必选服务。 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java index e0f5bb539..5e31d3996 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java @@ -25,10 +25,6 @@ public class ThingModelStructDataSpecs extends ThingModelDataSpecs { * 属性名称 */ private String name; - /** - * 属性描述 - */ - private String description; /** * 云端可以对该属性进行的操作类型 * 关联枚举 {@link IotProductThingModelAccessModeEnum} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java index 2eac5e1ad..6df29e101 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java @@ -23,13 +23,6 @@ public interface IotProductThingModelService { */ Long createProductThingModel(@Valid IotProductThingModelSaveReqVO createReqVO); - /** - * 创建超级表数据模型 - * - * @param productId 产品编号 - */ - void createSuperTableDataModel(Long productId); - /** * 更新产品物模型 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java index 90ea27ca0..3dc5790a5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java @@ -193,17 +193,17 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ // 2.1 生成属性上报事件 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); if (propertyPostEvent != null) { - newThingModelList.add(buildEventThingModelDO(productId, productKey, propertyPostEvent)); + newThingModelList.add(buildEventThingModelDO(productId, productKey, propertyPostEvent, "属性上报事件")); } // 2.2 生成属性设置服务 ThingModelService propertySetService = generatePropertySetService(propertyList); if (propertySetService != null) { - newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertySetService)); + newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertySetService, "属性设置服务")); } // 2.3 生成属性获取服务 ThingModelService propertyGetService = generatePropertyGetService(propertyList); if (propertyGetService != null) { - newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertyGetService)); + newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertyGetService,"属性获取服务")); } // 3.1 获取数据库中的默认的旧事件和服务列表 @@ -246,18 +246,20 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ /** * 构建事件功能对象 */ - private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event) { + private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event, + String description) { return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) - .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(event.getDescription()) + .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(description) .setType(IotProductThingModelTypeEnum.EVENT.getType()).setEvent(event); } /** * 构建服务功能对象 */ - private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service) { + private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service, + String description) { return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) - .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(service.getDescription()) + .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(description) .setType(IotProductThingModelTypeEnum.SERVICE.getType()).setService(service); } @@ -271,8 +273,8 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } // 1.2 生成属性上报事件 - return new ThingModelEvent().setIdentifier("post").setName("属性上报").setDescription("属性上报事件") - .setType(IotProductThingModelServiceEventTypeEnum.INFO.getType()).setMethod("thing.event.property.post") + return new ThingModelEvent().setIdentifier("post").setName("属性上报").setMethod("thing.event.property.post") + .setType(IotProductThingModelServiceEventTypeEnum.INFO.getType()) .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); } @@ -289,8 +291,8 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } // 2. 生成属性设置服务 - return new ThingModelService().setIdentifier("set").setName("属性设置").setDescription("属性设置服务") - .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()).setMethod("thing.service.property.set") + return new ThingModelService().setIdentifier("set").setName("属性设置").setMethod("thing.service.property.set") + .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()) .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) .setOutputParams(Collections.emptyList()); // 属性设置服务一般不需要输出参数 } @@ -305,8 +307,8 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } // 1.2 生成属性获取服务 - return new ThingModelService().setIdentifier("get").setName("属性获取").setDescription("属性获取服务") - .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()).setMethod("thing.service.property.get") + return new ThingModelService().setIdentifier("get").setName("属性获取").setMethod("thing.service.property.get") + .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()) .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); } From b4288bc39397f9de68d3f3ada18bc7fe5435ab5e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 26 Dec 2024 13:56:38 +0800 Subject: [PATCH 058/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9AThingModel=20=E7=BB=B4=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thingmodel/model/ThingModelEvent.java | 7 +- .../thingmodel/model/ThingModelService.java | 7 +- .../IotProductThingModelServiceImpl.java | 73 ++++++++++--------- 3 files changed, 41 insertions(+), 46 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index f49f5f86e..f6b45deb5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -22,16 +22,13 @@ public class ThingModelEvent { */ private String name; /** - * 是否是标准品类的必选事件。 - * - * - true:是 - * - false:否 + * 是否是标准品类的必选事件 */ private Boolean required; /** * 事件类型 * - * 关联枚举 {@link IotProductThingModelServiceEventTypeEnum} + * 枚举 {@link IotProductThingModelServiceEventTypeEnum} */ private String type; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index 0bdf498d3..95a702999 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -22,16 +22,13 @@ public class ThingModelService { */ private String name; /** - * 是否是标准品类的必选服务。 - * - * - true:是 - * - false:否 + * 是否是标准品类的必选服务 */ private Boolean required; /** * 调用类型 * - * 关联枚举 {@link IotProductThingModelServiceCallTypeEnum} + * 枚举 {@link IotProductThingModelServiceCallTypeEnum} */ private String callType; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java index 3dc5790a5..9e20a710b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java @@ -185,43 +185,44 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ */ public void createDefaultEventsAndServices(Long productId, String productKey) { // 1. 获取当前属性列表 - List propertyList = productThingModelMapper + List properties = productThingModelMapper .selectListByProductIdAndType(productId, IotProductThingModelTypeEnum.PROPERTY.getType()); // 2. 生成新的事件和服务列表 - List newThingModelList = new ArrayList<>(); + List newThingModels = new ArrayList<>(); // 2.1 生成属性上报事件 - ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); + ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties); if (propertyPostEvent != null) { - newThingModelList.add(buildEventThingModelDO(productId, productKey, propertyPostEvent, "属性上报事件")); + newThingModels.add(buildEventThingModelDO(productId, productKey, propertyPostEvent, "属性上报事件")); } // 2.2 生成属性设置服务 - ThingModelService propertySetService = generatePropertySetService(propertyList); + ThingModelService propertySetService = generatePropertySetService(properties); if (propertySetService != null) { - newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertySetService, "属性设置服务")); + newThingModels.add(buildServiceThingModelDO(productId, productKey, propertySetService, "属性设置服务")); } // 2.3 生成属性获取服务 - ThingModelService propertyGetService = generatePropertyGetService(propertyList); + ThingModelService propertyGetService = generatePropertyGetService(properties); if (propertyGetService != null) { - newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertyGetService,"属性获取服务")); + newThingModels.add(buildServiceThingModelDO(productId, productKey, propertyGetService,"属性获取服务")); } // 3.1 获取数据库中的默认的旧事件和服务列表 - List oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( + List oldThingModels = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) ); // 3.2 创建默认的事件和服务 - createDefaultEventsAndServices(oldThingModelList, newThingModelList); + createDefaultEventsAndServices(oldThingModels, newThingModels); } /** * 创建默认的事件和服务 */ - private void createDefaultEventsAndServices(List oldThingModelList, List newThingModelList) { - // 1.1 使用 diffList 方法比较新旧列表 - List> diffResult = diffList(oldThingModelList, newThingModelList, + private void createDefaultEventsAndServices(List oldThingModels, + List newThingModels) { + // 使用 diffList 方法比较新旧列表 + List> diffResult = diffList(oldThingModels, newThingModels, (oldVal, newVal) -> { // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 boolean same = Objects.equals(oldVal.getIdentifier(), newVal.getIdentifier()) @@ -231,7 +232,7 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } return same; }); - // 1.2 批量添加、修改、删除 + // 批量添加、修改、删除 if (CollUtil.isNotEmpty(diffResult.get(0))) { productThingModelMapper.insertBatch(diffResult.get(0)); } @@ -246,8 +247,8 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ /** * 构建事件功能对象 */ - private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event, - String description) { + private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, + ThingModelEvent event, String description) { return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(description) .setType(IotProductThingModelTypeEnum.EVENT.getType()).setEvent(event); @@ -256,8 +257,8 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ /** * 构建服务功能对象 */ - private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service, - String description) { + private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, + ThingModelService service, String description) { return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(description) .setType(IotProductThingModelTypeEnum.SERVICE.getType()).setService(service); @@ -266,64 +267,64 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ /** * 生成属性上报事件 */ - private ThingModelEvent generatePropertyPostEvent(List thingModelList) { - // 1.1 没有属性则不生成 - if (CollUtil.isEmpty(thingModelList)) { + private ThingModelEvent generatePropertyPostEvent(List thingModels) { + // 没有属性则不生成 + if (CollUtil.isEmpty(thingModels)) { return null; } - // 1.2 生成属性上报事件 + // 生成属性上报事件 return new ThingModelEvent().setIdentifier("post").setName("属性上报").setMethod("thing.event.property.post") .setType(IotProductThingModelServiceEventTypeEnum.INFO.getType()) - .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); + .setOutputParams(buildInputOutputParam(thingModels, IotProductThingModelParamDirectionEnum.OUTPUT)); } /** * 生成属性设置服务 */ - private ThingModelService generatePropertySetService(List thingModelList) { + private ThingModelService generatePropertySetService(List thingModels) { // 1.1 过滤出所有可写属性 - thingModelList = filterList(thingModelList, thingModel -> + thingModels = filterList(thingModels, thingModel -> IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(thingModel.getProperty().getAccessMode())); // 1.2 没有可写属性则不生成 - if (CollUtil.isEmpty(thingModelList)) { + if (CollUtil.isEmpty(thingModels)) { return null; } // 2. 生成属性设置服务 return new ThingModelService().setIdentifier("set").setName("属性设置").setMethod("thing.service.property.set") .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()) - .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) + .setInputParams(buildInputOutputParam(thingModels, IotProductThingModelParamDirectionEnum.INPUT)) .setOutputParams(Collections.emptyList()); // 属性设置服务一般不需要输出参数 } /** * 生成属性获取服务 */ - private ThingModelService generatePropertyGetService(List thingModelList) { + private ThingModelService generatePropertyGetService(List thingModels) { // 1.1 没有属性则不生成 - if (CollUtil.isEmpty(thingModelList)) { + if (CollUtil.isEmpty(thingModels)) { return null; } // 1.2 生成属性获取服务 return new ThingModelService().setIdentifier("get").setName("属性获取").setMethod("thing.service.property.get") .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()) - .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) - .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); + .setInputParams(buildInputOutputParam(thingModels, IotProductThingModelParamDirectionEnum.INPUT)) + .setOutputParams(buildInputOutputParam(thingModels, IotProductThingModelParamDirectionEnum.OUTPUT)); } /** * 构建输入/输出参数列表 * - * @param thingModelList 属性列表 + * @param thingModels 属性列表 * @return 输入/输出参数列表 */ - private List buildInputOutputParam(List thingModelList, - IotProductThingModelParamDirectionEnum directionEnum) { - return convertList(thingModelList, thingModel -> + private List buildInputOutputParam(List thingModels, + IotProductThingModelParamDirectionEnum direction) { + return convertList(thingModels, thingModel -> BeanUtils.toBean(thingModel.getProperty(), ThingModelInputOutputParam.class).setParaOrder(0) // TODO @puhui999: 先搞个默认值看看怎么个事 - .setDirection(directionEnum.getDirection())); + .setDirection(direction.getDirection())); } } From 8b7f329183e21b365222401c8a2c7d32108f0ee5 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 27 Dec 2024 10:37:16 +0800 Subject: [PATCH 059/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IOT:=20ThingModel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ....java => IotThingModelAccessModeEnum.java} | 2 +- ...a => IotThingModelParamDirectionEnum.java} | 2 +- ... => IotThingModelServiceCallTypeEnum.java} | 2 +- ...=> IotThingModelServiceEventTypeEnum.java} | 2 +- ...peEnum.java => IotThingModelTypeEnum.java} | 8 +- .../IotProductThingModelController.java | 84 ------------ ...ller.http => IotThingModelController.http} | 10 +- .../thingmodel/IotThingModelController.java | 84 ++++++++++++ .../thingmodel/model/ThingModelEvent.java | 6 +- ...tOutputParam.java => ThingModelParam.java} | 8 +- .../thingmodel/model/ThingModelProperty.java | 4 +- .../thingmodel/model/ThingModelService.java | 8 +- .../dataType/ThingModelStructDataSpecs.java | 4 +- ...ReqVO.java => IotThingModelPageReqVO.java} | 6 +- ...elRespVO.java => IotThingModelRespVO.java} | 2 +- ...ReqVO.java => IotThingModelSaveReqVO.java} | 6 +- ...Convert.java => IotThingModelConvert.java} | 30 ++-- .../dataobject/device/IotDeviceDataDO.java | 10 +- ...ThingModelDO.java => IotThingModelDO.java} | 13 +- .../IotProductThingModelMapper.java | 62 --------- .../mysql/thingmodel/IotThingModelMapper.java | 62 +++++++++ .../IotDevicePropertyDataServiceImpl.java | 18 +-- .../IotThingModelMessageServiceImpl.java | 40 +++--- ...Service.java => IotThingModelService.java} | 22 +-- ...mpl.java => IotThingModelServiceImpl.java} | 128 +++++++++--------- 25 files changed, 308 insertions(+), 315 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/{IotProductThingModelAccessModeEnum.java => IotThingModelAccessModeEnum.java} (85%) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/{IotProductThingModelParamDirectionEnum.java => IotThingModelParamDirectionEnum.java} (86%) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/{IotProductThingModelServiceCallTypeEnum.java => IotThingModelServiceCallTypeEnum.java} (85%) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/{IotProductThingModelServiceEventTypeEnum.java => IotThingModelServiceEventTypeEnum.java} (85%) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/{IotProductThingModelTypeEnum.java => IotThingModelTypeEnum.java} (74%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/{IotProductThingModelController.http => IotThingModelController.http} (94%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/{ThingModelInputOutputParam.java => ThingModelParam.java} (80%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/{IotProductThingModelPageReqVO.java => IotThingModelPageReqVO.java} (82%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/{IotProductThingModelRespVO.java => IotThingModelRespVO.java} (98%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/{IotProductThingModelSaveReqVO.java => IotThingModelSaveReqVO.java} (92%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/{IotProductThingModelConvert.java => IotThingModelConvert.java} (58%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/{IotProductThingModelDO.java => IotThingModelDO.java} (75%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotProductThingModelMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/{IotProductThingModelService.java => IotThingModelService.java} (64%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/{IotProductThingModelServiceImpl.java => IotThingModelServiceImpl.java} (65%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java index 7fca10a46..0b18bbbf5 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java @@ -10,7 +10,7 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotProductThingModelAccessModeEnum { +public enum IotThingModelAccessModeEnum { READ_ONLY("r"), READ_WRITE("rw"); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java similarity index 86% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java index e12332b6d..b1ae8a947 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java @@ -10,7 +10,7 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotProductThingModelParamDirectionEnum { +public enum IotThingModelParamDirectionEnum { INPUT("input"), // 输入参数 OUTPUT("output"); // 输出参数 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java index 81ffccc49..66ca6bec5 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java @@ -10,7 +10,7 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotProductThingModelServiceCallTypeEnum { +public enum IotThingModelServiceCallTypeEnum { ASYNC("async"), // 异步调用 SYNC("sync"); // 同步调用 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java index fbf76da77..b87d7eb98 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java @@ -10,7 +10,7 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotProductThingModelServiceEventTypeEnum { +public enum IotThingModelServiceEventTypeEnum { INFO("info"), // 信息 ALERT("alert"), // 告警 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java similarity index 74% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java index 153e93ecc..93fdc0ca4 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java @@ -13,13 +13,13 @@ import java.util.Arrays; */ @AllArgsConstructor @Getter -public enum IotProductThingModelTypeEnum implements IntArrayValuable { +public enum IotThingModelTypeEnum implements IntArrayValuable { PROPERTY(1, "属性"), SERVICE(2, "服务"), EVENT(3, "事件"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductThingModelTypeEnum::getType).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotThingModelTypeEnum::getType).toArray(); /** * 类型 @@ -30,8 +30,8 @@ public enum IotProductThingModelTypeEnum implements IntArrayValuable { */ private final String description; - public static IotProductThingModelTypeEnum valueOfType(Integer type) { - for (IotProductThingModelTypeEnum value : values()) { + public static IotThingModelTypeEnum valueOfType(Integer type) { + for (IotThingModelTypeEnum value : values()) { if (value.getType().equals(type)) { return value; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.java deleted file mode 100644 index 9b94def42..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.java +++ /dev/null @@ -1,84 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; -import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - IoT 产品物模型") -@RestController -@RequestMapping("/iot/product-thing-model") -@Validated -public class IotProductThingModelController { - - @Resource - private IotProductThingModelService thingModelService; - - @PostMapping("/create") - @Operation(summary = "创建产品物模型") - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:create')") - public CommonResult createProductThingModel(@Valid @RequestBody IotProductThingModelSaveReqVO createReqVO) { - return success(thingModelService.createProductThingModel(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新产品物模型") - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:update')") - public CommonResult updateProductThingModel(@Valid @RequestBody IotProductThingModelSaveReqVO updateReqVO) { - thingModelService.updateProductThingModel(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除产品物模型") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:delete')") - public CommonResult deleteProductThingModel(@RequestParam("id") Long id) { - thingModelService.deleteProductThingModel(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得产品物模型") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") - public CommonResult getProductThingModel(@RequestParam("id") Long id) { - IotProductThingModelDO thingModel = thingModelService.getProductThingModel(id); - return success(IotProductThingModelConvert.INSTANCE.convert(thingModel)); - } - - @GetMapping("/list-by-product-id") - @Operation(summary = "获得产品物模型") - @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") - public CommonResult> getProductThingModelListByProductId(@RequestParam("productId") Long productId) { - List list = thingModelService.getProductThingModelListByProductId(productId); - return success(IotProductThingModelConvert.INSTANCE.convertList(list)); - } - - @GetMapping("/page") - @Operation(summary = "获得产品物模型分页") - @PreAuthorize("@ss.hasPermission('iot:product-thing-model:query')") - public CommonResult> getProductThingModelPage(@Valid IotProductThingModelPageReqVO pageReqVO) { - PageResult pageResult = thingModelService.getProductThingModelPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotProductThingModelRespVO.class)); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.http similarity index 94% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.http index 7e7aa05d6..1e1f72103 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.http @@ -25,8 +25,7 @@ Authorization: Bearer {{token}} "defaultValue": "30", "unit": "%", "unitName": "百分比" - }, - "description": "当前温度值" + } } } @@ -46,7 +45,6 @@ Authorization: Bearer {{token}} "property": { "identifier": "switch", "name": "开关", - "description": "温度计开关", "accessMode": "rw", "required": true, "dataType": "bool", @@ -81,7 +79,6 @@ Authorization: Bearer {{token}} "property": { "identifier": "argb", "name": "温度计 argb 颜色", - "description": "温度计 argb 颜色", "accessMode": "rw", "required": true, "dataType": "array", @@ -93,7 +90,6 @@ Authorization: Bearer {{token}} { "identifier": "switch", "name": "开关", - "description": "温度计开关", "accessMode": "rw", "required": true, "dataType": "struct", @@ -126,8 +122,7 @@ Authorization: Bearer {{token}} "defaultValue": "30", "unit": "%", "unitName": "百分比" - }, - "description": "当前温度值" + } } ] } @@ -151,7 +146,6 @@ Authorization: Bearer {{token}} "property": { "identifier": "switch", "name": "开关", - "description": "温度计开关", "accessMode": "r", "required": true, "dataType": "bool", diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java new file mode 100644 index 000000000..4397a742f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.thingmodel.IotThingModelConvert; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 产品物模型") +@RestController +@RequestMapping("/iot/thing-model") +@Validated +public class IotThingModelController { + + @Resource + private IotThingModelService thingModelService; + + @PostMapping("/create") + @Operation(summary = "创建产品物模型") + @PreAuthorize("@ss.hasPermission('iot:thing-model:create')") + public CommonResult createThingModel(@Valid @RequestBody IotThingModelSaveReqVO createReqVO) { + return success(thingModelService.createThingModel(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品物模型") + @PreAuthorize("@ss.hasPermission('iot:thing-model:update')") + public CommonResult updateThingModel(@Valid @RequestBody IotThingModelSaveReqVO updateReqVO) { + thingModelService.updateThingModel(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品物模型") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:thing-model:delete')") + public CommonResult deleteThingModel(@RequestParam("id") Long id) { + thingModelService.deleteThingModel(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品物模型") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") + public CommonResult getThingModel(@RequestParam("id") Long id) { + IotThingModelDO thingModel = thingModelService.getThingModel(id); + return success(IotThingModelConvert.INSTANCE.convert(thingModel)); + } + + @GetMapping("/list-by-product-id") + @Operation(summary = "获得产品物模型") + @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") + public CommonResult> getThingModelListByProductId(@RequestParam("productId") Long productId) { + List list = thingModelService.getThingModelListByProductId(productId); + return success(IotThingModelConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品物模型分页") + @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") + public CommonResult> getThingModelPage(@Valid IotThingModelPageReqVO pageReqVO) { + PageResult pageResult = thingModelService.getProductThingModelPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotThingModelRespVO.class)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index f49f5f86e..286251aae 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceEventTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceEventTypeEnum; import lombok.Data; import java.util.List; @@ -31,7 +31,7 @@ public class ThingModelEvent { /** * 事件类型 * - * 关联枚举 {@link IotProductThingModelServiceEventTypeEnum} + * 关联枚举 {@link IotThingModelServiceEventTypeEnum} */ private String type; /** @@ -39,7 +39,7 @@ public class ThingModelEvent { * * 输出参数定义事件调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 */ - private List outputParams; + private List outputParams; /** * 标识设备需要执行的具体操作 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java similarity index 80% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java index 3b7b1414f..893fc1d15 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java @@ -1,18 +1,18 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelParamDirectionEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelParamDirectionEnum; import lombok.Data; import java.util.List; /** - * IOT 产品物模型中的参数 // TODO @puhui999 考虑要不改成 ThingModelParam ? + * IOT 产品物模型中的参数 * * @author HUIHUI */ @Data -public class ThingModelInputOutputParam { +public class ThingModelParam { /** * 参数标识符 @@ -25,7 +25,7 @@ public class ThingModelInputOutputParam { /** * 用于区分输入或输出参数 * - * 关联枚举 {@link IotProductThingModelParamDirectionEnum} + * 关联枚举 {@link IotThingModelParamDirectionEnum} */ private String direction; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index bb7376fc8..db7333df2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelAccessModeEnum; import lombok.Data; import java.util.List; @@ -27,7 +27,7 @@ public class ThingModelProperty { /** * 云端可以对该属性进行的操作类型 * - * 枚举 {@link IotProductThingModelAccessModeEnum} + * 枚举 {@link IotThingModelAccessModeEnum} */ private String accessMode; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index 0bdf498d3..619b64d05 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceCallTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceCallTypeEnum; import lombok.Data; import java.util.List; @@ -31,7 +31,7 @@ public class ThingModelService { /** * 调用类型 * - * 关联枚举 {@link IotProductThingModelServiceCallTypeEnum} + * 关联枚举 {@link IotThingModelServiceCallTypeEnum} */ private String callType; /** @@ -39,13 +39,13 @@ public class ThingModelService { * * 输入参数定义服务调用时所需提供的信息,用于控制设备行为或执行特定任务 */ - private List inputParams; + private List inputParams; /** * 服务的输出参数 * * 输出参数定义服务调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 */ - private List outputParams; + private List outputParams; /** * 标识设备需要执行的具体操作 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java index 5e31d3996..43addca95 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelAccessModeEnum; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import lombok.EqualsAndHashCode; @@ -27,7 +27,7 @@ public class ThingModelStructDataSpecs extends ThingModelDataSpecs { private String name; /** * 云端可以对该属性进行的操作类型 - * 关联枚举 {@link IotProductThingModelAccessModeEnum} + * 关联枚举 {@link IotThingModelAccessModeEnum} */ private String accessMode; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java index a15ae98a1..314441fb6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -13,7 +13,7 @@ import lombok.ToString; @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class IotProductThingModelPageReqVO extends PageParam { +public class IotThingModelPageReqVO extends PageParam { @Schema(description = "功能标识") private String identifier; @@ -22,7 +22,7 @@ public class IotProductThingModelPageReqVO extends PageParam { private String name; @Schema(description = "功能类型", example = "1") - @InEnum(IotProductThingModelTypeEnum.class) + @InEnum(IotThingModelTypeEnum.class) private Integer type; @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java similarity index 98% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java index 8d9c370d9..88c197bab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java @@ -13,7 +13,7 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - IoT 产品物模型 Response VO") @Data @ExcelIgnoreUnannotated -public class IotProductThingModelRespVO { +public class IotThingModelRespVO { @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") @ExcelProperty("产品ID") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java similarity index 92% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java index 5f2be4847..0eb37231b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotProductThingModelSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -12,7 +12,7 @@ import lombok.Data; @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") @Data -public class IotProductThingModelSaveReqVO { +public class IotThingModelSaveReqVO { @Schema(description = "编号", example = "1") private Long id; @@ -38,7 +38,7 @@ public class IotProductThingModelSaveReqVO { @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "功能类型不能为空") - @InEnum(IotProductThingModelTypeEnum.class) + @InEnum(IotThingModelTypeEnum.class) private Integer type; @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotProductThingModelConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java similarity index 58% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotProductThingModelConvert.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java index cb10c62b5..2e9b5441c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotProductThingModelConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.iot.convert.thingmodel; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Named; @@ -16,44 +16,44 @@ import java.util.List; import java.util.Objects; @Mapper -public interface IotProductThingModelConvert { +public interface IotThingModelConvert { - IotProductThingModelConvert INSTANCE = Mappers.getMapper(IotProductThingModelConvert.class); + IotThingModelConvert INSTANCE = Mappers.getMapper(IotThingModelConvert.class); // 将 SaveReqVO 转换为 DO @Mapping(target = "property", expression = "java(convertToProperty(bean))") @Mapping(target = "event", expression = "java(convertToEvent(bean))") @Mapping(target = "service", expression = "java(convertToService(bean))") - IotProductThingModelDO convert(IotProductThingModelSaveReqVO bean); + IotThingModelDO convert(IotThingModelSaveReqVO bean); // 将 DO 转换为 RespVO @Mapping(target = "property", source = "property") @Mapping(target = "event", source = "event") @Mapping(target = "service", source = "service") - IotProductThingModelRespVO convert(IotProductThingModelDO bean); + IotThingModelRespVO convert(IotThingModelDO bean); // 批量转换 - List convertList(List list); + List convertList(List list); @Named("convertToProperty") - default ThingModelProperty convertToProperty(IotProductThingModelSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + default ThingModelProperty convertToProperty(IotThingModelSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { return bean.getProperty(); } return null; } @Named("convertToEvent") - default ThingModelEvent convertToEvent(IotProductThingModelSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.EVENT.getType())) { + default ThingModelEvent convertToEvent(IotThingModelSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotThingModelTypeEnum.EVENT.getType())) { return bean.getEvent(); } return null; } @Named("convertToService") - default ThingModelService convertToService(IotProductThingModelSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotProductThingModelTypeEnum.SERVICE.getType())) { + default ThingModelService convertToService(IotThingModelSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotThingModelTypeEnum.SERVICE.getType())) { return bean.getService(); } return null; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java index ab1934edb..63b732d20 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -30,7 +30,7 @@ public class IotDeviceDataDO { /** * 物模型编号 *

- * 关联 {@link IotProductThingModelDO#getId()} + * 关联 {@link IotThingModelDO#getId()} */ private Long thingModelId; @@ -51,21 +51,21 @@ public class IotDeviceDataDO { /** * 属性标识符 *

- * 关联 {@link IotProductThingModelDO#getIdentifier()} + * 关联 {@link IotThingModelDO#getIdentifier()} */ private String identifier; /** * 属性名称 *

- * 关联 {@link IotProductThingModelDO#getName()} + * 关联 {@link IotThingModelDO#getName()} */ private String name; /** * 数据类型 *

- * 关联 {@link IotProductThingModelDO#getProperty()#getDataType()} + * 关联 {@link IotThingModelDO#getProperty()#getDataType()} */ private String dataType; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotThingModelDO.java similarity index 75% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotThingModelDO.java index f2edc5db7..e3b4a6d9a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotProductThingModelDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotThingModelDO.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelE import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -16,21 +16,20 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -// TODO @huihui:IotProductThingModelDO => IotThingModelDO /** * IoT 产品物模型功能 DO *

- * 每个 {@link IotProductDO} 和 {@link IotProductThingModelDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 + * 每个 {@link IotProductDO} 和 {@link IotThingModelDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 * * @author 芋道源码 */ -@TableName(value = "iot_product_thing_model", autoResultMap = true) -@KeySequence("iot_product_thing_model_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName(value = "iot_thing_model", autoResultMap = true) +@KeySequence("iot_thing_model_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor @AllArgsConstructor -public class IotProductThingModelDO extends BaseDO { +public class IotThingModelDO extends BaseDO { /** * 物模型功能编号 @@ -67,7 +66,7 @@ public class IotProductThingModelDO extends BaseDO { /** * 功能类型 *

- * 枚举 {@link IotProductThingModelTypeEnum} + * 枚举 {@link IotThingModelTypeEnum} */ private Integer type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotProductThingModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotProductThingModelMapper.java deleted file mode 100644 index 175f66f40..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotProductThingModelMapper.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.thingmodel; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * IoT 产品物模型 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface IotProductThingModelMapper extends BaseMapperX { - - default PageResult selectPage(IotProductThingModelPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(IotProductThingModelDO::getIdentifier, reqVO.getIdentifier()) - .likeIfPresent(IotProductThingModelDO::getName, reqVO.getName()) - .eqIfPresent(IotProductThingModelDO::getType, reqVO.getType()) - .eqIfPresent(IotProductThingModelDO::getProductId, reqVO.getProductId()) - .notIn(IotProductThingModelDO::getIdentifier, "get", "set", "post") - .orderByDesc(IotProductThingModelDO::getId)); - } - - default IotProductThingModelDO selectByProductIdAndIdentifier(Long productId, String identifier) { - return selectOne(IotProductThingModelDO::getProductId, productId, - IotProductThingModelDO::getIdentifier, identifier); - } - - default List selectListByProductId(Long productId) { - return selectList(IotProductThingModelDO::getProductId, productId); - } - - default List selectListByProductIdAndType(Long productId, Integer type) { - return selectList(IotProductThingModelDO::getProductId, productId, - IotProductThingModelDO::getType, type); - } - - default List selectListByProductIdAndIdentifiersAndTypes(Long productId, - List identifiers, - List types) { - return selectList(new LambdaQueryWrapperX() - .eq(IotProductThingModelDO::getProductId, productId) - .in(IotProductThingModelDO::getIdentifier, identifiers) - .in(IotProductThingModelDO::getType, types)); - } - - default IotProductThingModelDO selectByProductIdAndName(Long productId, String name) { - return selectOne(IotProductThingModelDO::getProductId, productId, - IotProductThingModelDO::getName, name); - } - - default List selectListByProductKey(String productKey) { - return selectList(IotProductThingModelDO::getProductKey, productKey); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java new file mode 100644 index 000000000..b52abad8b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.thingmodel; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * IoT 产品物模型 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotThingModelMapper extends BaseMapperX { + + default PageResult selectPage(IotThingModelPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotThingModelDO::getIdentifier, reqVO.getIdentifier()) + .likeIfPresent(IotThingModelDO::getName, reqVO.getName()) + .eqIfPresent(IotThingModelDO::getType, reqVO.getType()) + .eqIfPresent(IotThingModelDO::getProductId, reqVO.getProductId()) + .notIn(IotThingModelDO::getIdentifier, "get", "set", "post") + .orderByDesc(IotThingModelDO::getId)); + } + + default IotThingModelDO selectByProductIdAndIdentifier(Long productId, String identifier) { + return selectOne(IotThingModelDO::getProductId, productId, + IotThingModelDO::getIdentifier, identifier); + } + + default List selectListByProductId(Long productId) { + return selectList(IotThingModelDO::getProductId, productId); + } + + default List selectListByProductIdAndType(Long productId, Integer type) { + return selectList(IotThingModelDO::getProductId, productId, + IotThingModelDO::getType, type); + } + + default List selectListByProductIdAndIdentifiersAndTypes(Long productId, + List identifiers, + List types) { + return selectList(new LambdaQueryWrapperX() + .eq(IotThingModelDO::getProductId, productId) + .in(IotThingModelDO::getIdentifier, identifiers) + .in(IotThingModelDO::getType, types)); + } + + default IotThingModelDO selectByProductIdAndName(Long productId, String name) { + return selectOne(IotThingModelDO::getProductId, productId, + IotThingModelDO::getName, name); + } + + default List selectListByProductKey(String productKey) { + return selectList(IotThingModelDO::getProductKey, productKey); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index 99c04a843..eb7fcd430 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -13,17 +13,17 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; -import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; @@ -71,7 +71,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe @Resource private IotThingModelMessageService thingModelMessageService; @Resource - private IotProductThingModelService thingModelService; + private IotThingModelService thingModelService; @Resource private IotProductService productService; @@ -88,8 +88,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe public void defineDevicePropertyData(Long productId) { // 1.1 查询产品和物模型 IotProductDO product = productService.validateProductExists(productId); - List thingModels = filterList(thingModelService.getProductThingModelListByProductId(productId), - thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); + List thingModels = filterList(thingModelService.getThingModelListByProductId(productId), + thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); // 1.2 解析 DB 里的字段 List oldFields = new ArrayList<>(); try { @@ -115,7 +115,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe devicePropertyDataMapper.alterProductPropertySTable(product.getProductKey(), oldFields, newFields); } - private List buildTableFieldList(List thingModels) { + private List buildTableFieldList(List thingModels) { return convertList(thingModels, thingModel -> { TDengineTableField field = new TDengineTableField( StrUtil.toUnderlineCase(thingModel.getIdentifier()), // TDengine 字段默认都是小写 @@ -153,8 +153,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe // 1. 获取设备信息 IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); // 2. 获取设备属性最新数据 - List thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey()); - thingModelList = filterList(thingModelList, thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType() + List thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey()); + thingModelList = filterList(thingModelList, thingModel -> IotThingModelTypeEnum.PROPERTY.getType() .equals(thingModel.getType())); // 3. 过滤标识符和属性名称 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index ad909c437..d91041995 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -11,16 +11,16 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.thingmodel.IotProductThingModelService; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils; import jakarta.annotation.Resource; @@ -52,7 +52,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ private String url; @Resource - private IotProductThingModelService iotProductThingModelService; + private IotThingModelService iotThingModelService; @Resource private IotDeviceService iotDeviceService; @Resource @@ -83,7 +83,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 Map params = thingModelMessage.dataToMap(); - List thingModelList = getValidThingModelList(thingModelMessage.getProductKey()); + List thingModelList = getValidThingModelList(thingModelMessage.getProductKey()); if (thingModelList.isEmpty()) { return; } @@ -102,9 +102,9 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ .build()); } - private List getValidThingModelList(String productKey) { - return filterList(iotProductThingModelService.getProductThingModelListByProductKey(productKey), - thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); + private List getValidThingModelList(String productKey) { + return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey), + thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); } @Override @@ -134,17 +134,17 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); } - private List getValidFunctionList(String productKey) { - return filterList(iotProductThingModelService.getProductThingModelListByProductKey(productKey), - thingModel -> IotProductThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); + private List getValidFunctionList(String productKey) { + return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey), + thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); } - private List filterAndCollectValidFields(Map params, List thingModelList, IotDeviceDO device, Long time) { + private List filterAndCollectValidFields(Map params, List thingModelList, IotDeviceDO device, Long time) { // 1. 获取属性标识符集合 - Set propertyIdentifiers = convertSet(thingModelList, IotProductThingModelDO::getIdentifier); + Set propertyIdentifiers = convertSet(thingModelList, IotThingModelDO::getIdentifier); // 2. 构建属性标识符和属性的映射 - Map thingModelMap = convertMap(thingModelList, IotProductThingModelDO::getIdentifier); + Map thingModelMap = convertMap(thingModelList, IotThingModelDO::getIdentifier); // 3. 过滤并收集有效的属性字段 List schemaFieldValues = new ArrayList<>(); @@ -164,21 +164,21 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * 缓存设备属性 * * @param device 设备信息 - * @param iotProductThingModelDO 物模型属性 + * @param iotThingModelDO 物模型属性 * @param val 属性值 * @param time 时间 */ - private void setDeviceDataCache(IotDeviceDO device, IotProductThingModelDO iotProductThingModelDO, Object val, Long time) { + private void setDeviceDataCache(IotDeviceDO device, IotThingModelDO iotThingModelDO, Object val, Long time) { IotDeviceDataDO deviceData = IotDeviceDataDO.builder() .productKey(device.getProductKey()) .deviceName(device.getDeviceName()) - .identifier(iotProductThingModelDO.getIdentifier()) + .identifier(iotThingModelDO.getIdentifier()) .value(val != null ? val.toString() : null) .updateTime(DateUtil.toLocalDateTime(new Date(time))) .deviceId(device.getId()) - .thingModelId(iotProductThingModelDO.getId()) - .name(iotProductThingModelDO.getName()) - .dataType(iotProductThingModelDO.getProperty().getDataType()) + .thingModelId(iotThingModelDO.getId()) + .name(iotThingModelDO.getName()) + .dataType(iotThingModelDO.getProperty().getDataType()) .build(); deviceDataRedisDAO.set(deviceData); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java similarity index 64% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java index 6df29e101..f2ec53ecf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.iot.service.thingmodel; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import jakarta.validation.Valid; import java.util.List; @@ -13,7 +13,7 @@ import java.util.List; * * @author 芋道源码 */ -public interface IotProductThingModelService { +public interface IotThingModelService { /** * 创建产品物模型 @@ -21,21 +21,21 @@ public interface IotProductThingModelService { * @param createReqVO 创建信息 * @return 编号 */ - Long createProductThingModel(@Valid IotProductThingModelSaveReqVO createReqVO); + Long createThingModel(@Valid IotThingModelSaveReqVO createReqVO); /** * 更新产品物模型 * * @param updateReqVO 更新信息 */ - void updateProductThingModel(@Valid IotProductThingModelSaveReqVO updateReqVO); + void updateThingModel(@Valid IotThingModelSaveReqVO updateReqVO); /** * 删除产品物模型 * * @param id 编号 */ - void deleteProductThingModel(Long id); + void deleteThingModel(Long id); /** * 获得产品物模型 @@ -43,7 +43,7 @@ public interface IotProductThingModelService { * @param id 编号 * @return 产品物模型 */ - IotProductThingModelDO getProductThingModel(Long id); + IotThingModelDO getThingModel(Long id); /** * 获得产品物模型列表 @@ -51,7 +51,7 @@ public interface IotProductThingModelService { * @param productId 产品编号 * @return 产品物模型列表 */ - List getProductThingModelListByProductId(Long productId); + List getThingModelListByProductId(Long productId); /** * 获得产品物模型分页 @@ -59,7 +59,7 @@ public interface IotProductThingModelService { * @param pageReqVO 分页查询 * @return 产品物模型分页 */ - PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO); + PageResult getProductThingModelPage(IotThingModelPageReqVO pageReqVO); /** * 获得产品物模型列表 @@ -67,6 +67,6 @@ public interface IotProductThingModelService { * @param productKey 产品 Key * @return 产品物模型列表 */ - List getProductThingModelListByProductKey(String productKey); + List getProductThingModelListByProductKey(String productKey); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java similarity index 65% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index 3dc5790a5..4617bd15b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -5,14 +5,14 @@ import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelInputOutputParam; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelParam; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.thingmodel.IotThingModelConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; -import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapper; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; +import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotThingModelMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.*; import cn.iocoder.yudao.module.iot.service.product.IotProductService; @@ -36,17 +36,17 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @Service @Validated @Slf4j -public class IotProductThingModelServiceImpl implements IotProductThingModelService { +public class IotThingModelServiceImpl implements IotThingModelService { @Resource - private IotProductThingModelMapper productThingModelMapper; + private IotThingModelMapper thingModelMapper; @Resource private IotProductService productService; @Override @Transactional(rollbackFor = Exception.class) - public Long createProductThingModel(IotProductThingModelSaveReqVO createReqVO) { + public Long createThingModel(IotThingModelSaveReqVO createReqVO) { // 1. 校验功能标识符在同一产品下是否唯一 validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); @@ -60,11 +60,11 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ validateProductStatus(createReqVO.getProductId()); // 5. 插入数据库 - IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(createReqVO); - productThingModelMapper.insert(thingModel); + IotThingModelDO thingModel = IotThingModelConvert.INSTANCE.convert(createReqVO); + thingModelMapper.insert(thingModel); // 6. 如果创建的是属性,需要更新默认的事件和服务 - if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } // TODO @puhui999: 服务和事件的情况 method 怎么设置?在前端设置还是后端设置? @@ -73,7 +73,7 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @Override @Transactional(rollbackFor = Exception.class) - public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { + public void updateThingModel(IotThingModelSaveReqVO updateReqVO) { // 1. 校验功能是否存在 validateProductThingModelMapperExists(updateReqVO.getId()); @@ -84,20 +84,20 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ validateProductStatus(updateReqVO.getProductId()); // 4. 更新数据库 - IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(updateReqVO); - productThingModelMapper.updateById(thingModel); + IotThingModelDO thingModel = IotThingModelConvert.INSTANCE.convert(updateReqVO); + thingModelMapper.updateById(thingModel); // 5. 如果更新的是属性,需要更新默认的事件和服务 - if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } } @Override @Transactional(rollbackFor = Exception.class) - public void deleteProductThingModel(Long id) { + public void deleteThingModel(Long id) { // 1. 校验功能是否存在 - IotProductThingModelDO thingModel = productThingModelMapper.selectById(id); + IotThingModelDO thingModel = thingModelMapper.selectById(id); if (thingModel == null) { throw exception(THING_MODEL_NOT_EXISTS); } @@ -106,32 +106,32 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ validateProductStatus(thingModel.getProductId()); // 2. 删除功能 - productThingModelMapper.deleteById(id); + thingModelMapper.deleteById(id); // 3. 如果删除的是属性,需要更新默认的事件和服务 - if (Objects.equals(thingModel.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(thingModel.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey()); } } @Override - public IotProductThingModelDO getProductThingModel(Long id) { - return productThingModelMapper.selectById(id); + public IotThingModelDO getThingModel(Long id) { + return thingModelMapper.selectById(id); } @Override - public List getProductThingModelListByProductId(Long productId) { - return productThingModelMapper.selectListByProductId(productId); + public List getThingModelListByProductId(Long productId) { + return thingModelMapper.selectListByProductId(productId); } @Override - public PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) { - return productThingModelMapper.selectPage(pageReqVO); + public PageResult getProductThingModelPage(IotThingModelPageReqVO pageReqVO) { + return thingModelMapper.selectPage(pageReqVO); } @Override - public List getProductThingModelListByProductKey(String productKey) { - return productThingModelMapper.selectListByProductKey(productKey); + public List getProductThingModelListByProductKey(String productKey) { + return thingModelMapper.selectListByProductKey(productKey); } /** @@ -140,13 +140,13 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ * @param id 功能编号 */ private void validateProductThingModelMapperExists(Long id) { - if (productThingModelMapper.selectById(id) == null) { + if (thingModelMapper.selectById(id) == null) { throw exception(THING_MODEL_NOT_EXISTS); } } private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { - IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); + IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) { throw exception(THING_MODEL_IDENTIFIER_EXISTS); } @@ -167,14 +167,14 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } private void validateNameUnique(Long productId, String name) { - IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndName(productId, name); + IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndName(productId, name); if (thingModel != null) { throw exception(THING_MODEL_NAME_EXISTS); } } private void validateIdentifierUnique(Long productId, String identifier) { - IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); + IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (thingModel != null) { throw exception(THING_MODEL_IDENTIFIER_EXISTS); } @@ -185,11 +185,11 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ */ public void createDefaultEventsAndServices(Long productId, String productKey) { // 1. 获取当前属性列表 - List propertyList = productThingModelMapper - .selectListByProductIdAndType(productId, IotProductThingModelTypeEnum.PROPERTY.getType()); + List propertyList = thingModelMapper + .selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType()); // 2. 生成新的事件和服务列表 - List newThingModelList = new ArrayList<>(); + List newThingModelList = new ArrayList<>(); // 2.1 生成属性上报事件 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); if (propertyPostEvent != null) { @@ -207,10 +207,10 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } // 3.1 获取数据库中的默认的旧事件和服务列表 - List oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( + List oldThingModelList = thingModelMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), - Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) + Arrays.asList(IotThingModelTypeEnum.EVENT.getType(), IotThingModelTypeEnum.SERVICE.getType()) ); // 3.2 创建默认的事件和服务 createDefaultEventsAndServices(oldThingModelList, newThingModelList); @@ -219,9 +219,9 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ /** * 创建默认的事件和服务 */ - private void createDefaultEventsAndServices(List oldThingModelList, List newThingModelList) { + private void createDefaultEventsAndServices(List oldThingModelList, List newThingModelList) { // 1.1 使用 diffList 方法比较新旧列表 - List> diffResult = diffList(oldThingModelList, newThingModelList, + List> diffResult = diffList(oldThingModelList, newThingModelList, (oldVal, newVal) -> { // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 boolean same = Objects.equals(oldVal.getIdentifier(), newVal.getIdentifier()) @@ -233,40 +233,40 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ }); // 1.2 批量添加、修改、删除 if (CollUtil.isNotEmpty(diffResult.get(0))) { - productThingModelMapper.insertBatch(diffResult.get(0)); + thingModelMapper.insertBatch(diffResult.get(0)); } if (CollUtil.isNotEmpty(diffResult.get(1))) { - productThingModelMapper.updateBatch(diffResult.get(1)); + thingModelMapper.updateBatch(diffResult.get(1)); } if (CollUtil.isNotEmpty(diffResult.get(2))) { - productThingModelMapper.deleteByIds(convertSet(diffResult.get(2), IotProductThingModelDO::getId)); + thingModelMapper.deleteByIds(convertSet(diffResult.get(2), IotThingModelDO::getId)); } } /** * 构建事件功能对象 */ - private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event, - String description) { - return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) + private IotThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event, + String description) { + return new IotThingModelDO().setProductId(productId).setProductKey(productKey) .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(description) - .setType(IotProductThingModelTypeEnum.EVENT.getType()).setEvent(event); + .setType(IotThingModelTypeEnum.EVENT.getType()).setEvent(event); } /** * 构建服务功能对象 */ - private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service, - String description) { - return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) + private IotThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service, + String description) { + return new IotThingModelDO().setProductId(productId).setProductKey(productKey) .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(description) - .setType(IotProductThingModelTypeEnum.SERVICE.getType()).setService(service); + .setType(IotThingModelTypeEnum.SERVICE.getType()).setService(service); } /** * 生成属性上报事件 */ - private ThingModelEvent generatePropertyPostEvent(List thingModelList) { + private ThingModelEvent generatePropertyPostEvent(List thingModelList) { // 1.1 没有属性则不生成 if (CollUtil.isEmpty(thingModelList)) { return null; @@ -274,17 +274,17 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ // 1.2 生成属性上报事件 return new ThingModelEvent().setIdentifier("post").setName("属性上报").setMethod("thing.event.property.post") - .setType(IotProductThingModelServiceEventTypeEnum.INFO.getType()) - .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); + .setType(IotThingModelServiceEventTypeEnum.INFO.getType()) + .setOutputParams(buildInputOutputParam(thingModelList, IotThingModelParamDirectionEnum.OUTPUT)); } /** * 生成属性设置服务 */ - private ThingModelService generatePropertySetService(List thingModelList) { + private ThingModelService generatePropertySetService(List thingModelList) { // 1.1 过滤出所有可写属性 thingModelList = filterList(thingModelList, thingModel -> - IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(thingModel.getProperty().getAccessMode())); + IotThingModelAccessModeEnum.READ_WRITE.getMode().equals(thingModel.getProperty().getAccessMode())); // 1.2 没有可写属性则不生成 if (CollUtil.isEmpty(thingModelList)) { return null; @@ -292,15 +292,15 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ // 2. 生成属性设置服务 return new ThingModelService().setIdentifier("set").setName("属性设置").setMethod("thing.service.property.set") - .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()) - .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) + .setCallType(IotThingModelServiceCallTypeEnum.ASYNC.getType()) + .setInputParams(buildInputOutputParam(thingModelList, IotThingModelParamDirectionEnum.INPUT)) .setOutputParams(Collections.emptyList()); // 属性设置服务一般不需要输出参数 } /** * 生成属性获取服务 */ - private ThingModelService generatePropertyGetService(List thingModelList) { + private ThingModelService generatePropertyGetService(List thingModelList) { // 1.1 没有属性则不生成 if (CollUtil.isEmpty(thingModelList)) { return null; @@ -308,9 +308,9 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ // 1.2 生成属性获取服务 return new ThingModelService().setIdentifier("get").setName("属性获取").setMethod("thing.service.property.get") - .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()) - .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) - .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); + .setCallType(IotThingModelServiceCallTypeEnum.ASYNC.getType()) + .setInputParams(buildInputOutputParam(thingModelList, IotThingModelParamDirectionEnum.INPUT)) + .setOutputParams(buildInputOutputParam(thingModelList, IotThingModelParamDirectionEnum.OUTPUT)); } /** @@ -319,10 +319,10 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ * @param thingModelList 属性列表 * @return 输入/输出参数列表 */ - private List buildInputOutputParam(List thingModelList, - IotProductThingModelParamDirectionEnum directionEnum) { + private List buildInputOutputParam(List thingModelList, + IotThingModelParamDirectionEnum directionEnum) { return convertList(thingModelList, thingModel -> - BeanUtils.toBean(thingModel.getProperty(), ThingModelInputOutputParam.class).setParaOrder(0) // TODO @puhui999: 先搞个默认值看看怎么个事 + BeanUtils.toBean(thingModel.getProperty(), ThingModelParam.class).setParaOrder(0) // TODO @puhui999: 先搞个默认值看看怎么个事 .setDirection(directionEnum.getDirection())); } From c9904f0994389a6b8c613e51a861745012607019 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 28 Dec 2024 21:06:19 +0800 Subject: [PATCH 060/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9AThingModel=20=E7=BB=B4=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crm/dal/dataobject/receivable/CrmReceivableDO.java | 4 +++- .../admin/thingmodel/model/ThingModelParam.java | 2 +- .../model/dataType/ThingModelStructDataSpecs.java | 8 +++----- .../iot/dal/mysql/thingmodel/IotThingModelMapper.java | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java index 269cac6cc..c24614ad5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java @@ -66,7 +66,9 @@ public class CrmReceivableDO extends BaseDO { */ private LocalDateTime returnTime; /** - * 回款方式,关联枚举{@link CrmReceivableReturnTypeEnum} + * 回款方式 + * + * 枚举 {@link CrmReceivableReturnTypeEnum} */ private Integer returnType; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java index 893fc1d15..9cddf1d29 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java @@ -25,7 +25,7 @@ public class ThingModelParam { /** * 用于区分输入或输出参数 * - * 关联枚举 {@link IotThingModelParamDirectionEnum} + * 枚举 {@link IotThingModelParamDirectionEnum} */ private String direction; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java index 43addca95..8fcaefdc5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java @@ -27,14 +27,12 @@ public class ThingModelStructDataSpecs extends ThingModelDataSpecs { private String name; /** * 云端可以对该属性进行的操作类型 - * 关联枚举 {@link IotThingModelAccessModeEnum} + * + * 枚举 {@link IotThingModelAccessModeEnum} */ private String accessMode; /** - * 是否是标准品类的必选服务。 - * - * - true:是 - * - false:否 + * 是否是标准品类的必选服务 */ private Boolean required; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java index b52abad8b..b68732634 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java @@ -23,6 +23,7 @@ public interface IotThingModelMapper extends BaseMapperX { .likeIfPresent(IotThingModelDO::getName, reqVO.getName()) .eqIfPresent(IotThingModelDO::getType, reqVO.getType()) .eqIfPresent(IotThingModelDO::getProductId, reqVO.getProductId()) + // TODO @芋艿:看看要不要加枚举 .notIn(IotThingModelDO::getIdentifier, "get", "set", "post") .orderByDesc(IotThingModelDO::getId)); } From 0e20ca342f67b547fb181773f7008448fd248019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 29 Dec 2024 22:31:58 +0800 Subject: [PATCH 061/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=8F=92=E4=BB=B6=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/enabled.txt | 1 + ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 9347 -> 8804 bytes .../plugininfo/PluginInfoController.java | 18 +- .../plugininfo/vo/PluginInfoImportReqVO.java | 19 ++ .../framework/plugin/SpringConfiguration.java | 17 -- ...uration.java => UnifiedConfiguration.java} | 29 +-- .../service/plugininfo/PluginInfoService.java | 11 +- .../plugininfo/PluginInfoServiceImpl.java | 197 ++++++++++-------- .../module/iot/plugin/WelcomePlugin.java | 91 ++++++++ .../yudao-module-iot-http-plugin/pom.xml | 2 + 10 files changed, 258 insertions(+), 127 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/{ServiceRegistryConfiguration.java => UnifiedConfiguration.java} (55%) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java diff --git a/plugins/enabled.txt b/plugins/enabled.txt index e69de29bb..b62400a81 100644 --- a/plugins/enabled.txt +++ b/plugins/enabled.txt @@ -0,0 +1 @@ +http-plugin@0.0.1 diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar index 0300a632ae6d0bd042e974113a7193dc0e578232..28b10d529ce689efb557305c356827c90e42e60e 100644 GIT binary patch literal 8804 zcmb_h1ymf_wuRshjRYsSyK90&aCg_n-Q696(+TeG?!kjYAP^upK?1>o6F!+thBuR$ zy!q?@+pDX)SD$@O-BY)!cI_=M1px^U_H8s*q-*^4<@XKT{ilqmvLL;rtQe#G?_scD zP4{8sdDFZ@_kW9kgMnfEXPAtjtfZKzk}`vgm`Yr$4FoZ&s3+N1eG`1?{^(>@}TkX;AA>bTZV-#x3gTuK> z+_6HQSy_SIkmnZ4ezE!`JBH{BYP5hmPS951y=Hx5&m z7RI(R-(M!ambOlC@vl!mi}eb%JA?W$^`AQgaX)n~Cv{mRrlL_kIxx zV1j|M{ksGbPEK|b1~$f4CJqcnRtAoaX?#K~We}nPB&I~Lk#T;h zNstt9#uVYO9NuZ}l7!M9@Rk8#s^zmSxo?xPcEr?Lis*K$u=Y)7DqL)Lbi-Y2JI~~_ zJPtfrH3p3V7gyfyj-OjUFFKChrhnP0zsul8(TDiDBM8j`)g)p}{4!g5@}|TJB>dH` zGq1$qEs-*`p+fVRyQQipn^ZKLqy-tx9^(8SrV6vI;UFE&!H7Q|_ai(H{Wyi1t6Fw7+2UJRyLgF1ScX z`g&D;UE=s6H0{x`C`Q+?JdZ<;k9b@rE8_LFWL@WEgjh53{_%dYRjL!R6y;EDWCTQO zp5PEs(pv%FiMN>bmG7hH5l23EYmcBa=>?%6U>`FU8V#}-Dg?VN$+NwXJc?0{S{4k5 zCJwCa5bHI>0Mz8Yz+lJTirSo-t(8K4In&qJVowjpat-XnlLFG9yeZk~XMuK=erH%? zgWRmpyAlBmNecud!c(Cu#K6}`^GM)xMWq(tI!q)=M>-7xtr46#8=UKAS?N%;=WTdC zIE)FhBH%TDb{mwU5iRSbsktE3VcsO;?|G)6A8<#`$GA%F46=CRIl4=$LJ~~Q)0|s| zW=}fH0&6g)PF_k+wh+tox!S`s+;u;W`kiL`40n-Gz26rSQDp9R+n_NPOf99QxKU(K zf*_Aj^ir>zKdA=!RMiQ;q}qP>Xc3w`Z4NTzr#8vFcu^Vp9W6}JgcGUNT0%C%1V0M2 z(K%@ns;nz|rRkinIw1vDoG=TT1kOv$V}Xm2-I;H!A*fv_UMW2DGnm~@4rw>wHl+d4 zWF;|yoN{642T%188p6##zS!MK7{!`r$`hEE8loo4fk@9g^{dmOXbmN=m14dInx@8E z#A`7~6$2wKT7pljjPhS2Cqx(rDIc!bt*gR!Vqy+An;l@-<9!%fLE5Wf+XcOpbPn;1 z1Wm6nDICs}=k{+d%;SfxA1k7CdS!Wr&*NvYrnR^>YfHp|%b&a!- zErCe;=}7xaNc;QN`!RrWAI|*hhU6r^&*?9 zV`(Y(LI`5zn98J6xb`-6!}W2?BVx`!uH3pQcEN~vp~4hZ$Rv6461XR-fP}KkmuOqm zm@wqhs?l3vOHkIc{0c?zUyEaJ>1AN?zQxWa7RTOQ63sCze%Rbb9t{1j4lOvAZ`0g$dM$l zrq0~r@Fl+CbEeE5H1N#FM^Ik&5nDhfy;6}5@v|b!TnP&#=g#XOv*m^{kQB^rn z8ykfyQ%)-Nfvq?ip|b|O85&jG(U~9<&!t!28t_&h8LOrQs1q^-oOwnocZasmK*jR@Yw%p5x>O3A~q6BYUhT*W&8R`_^UxEaB?d+_cP{0xt z#7GzcpG~`HRiE;YHbrM=r@jjC5-$nM?8=di5DQGCp=$jap1o0?OBouw%;~i@$opng32Hj69~?;oq+}?#0vI;w&%+<56G`m zDXNf?ywV}8I!K5)P}6g_^70PWJX!RF&MQ+@udoq-d+91SBv}HUZyvksrjxVDs=y(&&F4|>cG8BUwE zlkDj{;P=|3ycoLEQame9nit2s!p}W2X`e2*r|q}<>jIPm_F%QsENixm350Ydci=EQ zZ|%#t4jfHXR86k6=aW<(4e5;9J=$BFQ{Oymmdnnj`3Or>%0~`mb*E8h^)#Gg>!i2( z3u1s@<8Ui~41r4XE4@ZW&KSa%CNZ3^*S7Pm$Au3~t|9f1y?LT_7!om7k|0Sl2k`I) z1mzsK0sxxS`ger+b@7QLg^TOx=ryn{FjXkmI}B$u5W{)QJ^eQ}bOp%!8B4;~WqKW1?U%wRi&+T8_%jNQxIjf; z+1EuGqPeuQhL<}pFrye4(&oBrsuJjhf|9ZxKPA~ggT3o^0e6JDxiCHBfS)7R9=IFd zz_L?)mT?k14{-+})7Tab4^E%5EtJShO^il1lrsMzF~L7`>X6lg<$|7RHSzIa=OUX6 zgtHYE62gR0n2Pt2T)>lRd}=vq!sBK@t+QUs z@A+OFw>ZMIjL;qT#0>8SQ`(_AWMo&g0Xp2q^uF~4IelLZZthEJuWd4cH$8i70^Lhr zYd+$t?uGZ*L~I5$G1mx991~HPH|L{GAo56m98eJOTqN zhXMm*|M#p={x^n6#{8WYrYl>@p$lU03nNG^^r>QqCWgwJEWjfaQDG^(?ul0>D+b4V ziqx9mGFY?lNmi1{=a4Z?AD8V4;zprAt${C!0flqExz_cd+3{ek`Q+r?J0h@*bx}lu zF!Qk8ZIQ?Rz-Eebx^dHvX1&H@vjY#8C4(vI5s*@)-8(v1g#~lj>1jxvoHv1|i9uM5 z!J`9{(WxO#F_2CH%m--<=!VO6C2yV6j2P-afrg<9k?*>^niu#|G7%urNNdx&Fv-~S zoU}z51%1__0}gO2nL}Hno>&`482IDu7qx}#LG~CJK<&OqK4D*cGDrZUqNS^J3pQN# zM(E{Ca%$(m4f$qNE=o0|jlr`XYXVm$2_^@^$B&}lyS#u7(4TQ5debgLWemvF>%pTD|IeiXW@U8l=l|_>{lY4i9tz(n{en?1E44nfcddd`% zVC?8wQ(tm%RwTPDlV`!9dGt$qzh*C7$}cJXK{O`u`ePTJ_-Qf$X|>h92zvfG&ru6?vRNf7xL`A3=cyJU<>#BxDmpX-dY91S(o9YpVy(p_qtqfz5apoEe+nBb@3r>)p@19zn@2RMzCcE~~pT&?Ay8?#o_ zKEvQ6H}{q?Jx{^Mg{12WYm02ztQS$FcE%gh2=zi|%1@84RRAVYW{i4+4{>C9t4^jS z8>J{x>Kcm0q(i1>Du%5Q6V_)FWwU30b_m^m(Rs&Pkwm&Yp=PsUx`TR4Fn8r>QnbiB z)wSeXkv}{S5eKnoyCTTD5+qT%_*lIkOqD58ZBA%4?5&YWp3=-0NV%6T$m4m@Z(;_A z_tf3{tFtT;cQ6btZ=nCY;O&vJ^Fc6RV4)~rV66Y!1^@eUSG&~1_=t1Yp$#z%RznEa z4^LKv@SNgEg0?gqa??D8)K7l;G)xV8b|XE5b1GoZZOv*onaT7lD(?yAdzs6()g`CkXQZ2jdNr*zDdq zlIL}{cYagZylA8PgS>e-pj(n2rH-ze9$l$uvF6RngQF)zPyjv_cw$y7BKc62zG`+I zxHPfBYC4;_H`SbOgVi#${f9x_;w@~XIVT4`k)^ArXo2Hu1nLPbky<^PVb=)qQ2;nR zg-9xte>`D`85EXXH-DeydaL!AjZvss*|HloA_!RE$kX+ z*4Hb}w}9zjqerG>LWDyD36Oe;=T;-C^b2Y_VdZYmUvuCrce#Wh4a4C$u;q>$&wY}z z$SoBU*{PvF#%$IQg6jENPp6U#0&EE>Y!!Hv8uWqq>W4Nh32BX?=6oEwr&^{N=D2f@G6290dx3mnVXvdjs1~BA0Q{9w;W|l;OX_uts{!99DkFC?cW!brP|dSMW5g0DGEybxe;N(d>hi|~zP?Idb(&MsAruEN%UPF4eJ8v;*-cjD{V za!F`WR;r>N9|437%9g8pw!$V&W8~o(i~GU2=NYpzEJRr`0~gMU0J~~PfqM~xaU7$3 z9MWr#3UI7zq$zj1(b&Sq91;Nw??|qC(b(Xhp0$PGscc4rKr|YO=EZ&YjwP}Cl zbDo70y@nPy8NmTBBXVfAeGa8sRHF=Y*8)4^{{{0&Eid+2g+3;$aNwe>Rwmi5g8`Bx zVzyIZ6oV711T{@aU@7JVjpkdJKHM7CFWVZ0UTS%IGbe=j1Fpdfa&bs^uE%Gvcpa4M z>|U9I$X_fynl#v7x0tKRlwLeFafknSv`8y*Bi|pJrC0#TPC9akNIpWERtRW8B@QCD z!|~3NZS%HvG9E6TWo?qVGZQ7yfN(L1lWCSH8#ja+am9uoSYDQ!j@_*wup4TcshDH z%qeQl5Mj9rFzI`rO-#HcQG=tjd4tuNa99zwyv|~;=d;YIX#H}{gFb7Io&QmpM{5N( zv-y+U3R_Fzwm$4xLtMBrPQ+=|;9NsPn#s}ZEbbyU`#>$4<`)tUJnwmn(U^BzM3I6_ zOGB1OYgq88h;mP$cj4Laq1XZ&xrGI7oDrl3XUZ23IC}_6@{#Qwu;Jpw;@64Tja*xZ zlXV(!ajjHxsdMn{+fg~s)twTJXQb|VbiWFIf1EE>USYqCT*{6*@rNQfH_85Va#(7~ z1-B8KO(D@KlO7>T$z2@Up&l6&o7ILO-@()_0-7t)a1gTNL^@-A9qvlGZVFg_50nVLZp%kS0Kl^?K34wh68tV znwN=3)e=6Kx3z0~J~!@6*_QWnna%D5`=gGFTF8f+q)@<@|&h#|D6$>MuN z=1URhhvM(=!p}6Y1Jy=O4lAzN z7j2dZ$0&Ilwpb*)@yC)v_@V0Yt_AGlXrJ5Xg1kje?Lkm`gk zgN@2-%?rLPSl73nORw>MIFoEUCI^|>--wK2cu*c$*jfWG=g53e#pALW#J4Bp;(&;~ zXrp2pviKP7Tp@jd@*YEQl)(7}?TU5%1-1_vy_Ha#&F{GwjE%V8B)2T)XVok+Qb=qn z+Uu+)wnorZ*}vDRl*iK6u-h%&cpiZaFE5@NsvuSiB-hP3^9)*?i14Ue#jHb*wLzS) zI^ppMQ-Z+{$Pl4C`qb|p&?$9DTXz?B_6~Rl=dt8xC3@x??$_ZNN!}*us}GQcBERXA zBC2`!cujdn436p$OKzRhwc4JU!~H;kI*sk1}!r^5_jTHBRfT*{FBH0aV|ratPwo`DJ*jt*mU_(*%AWArOObP`wi zz7x-M6h&c^_S4K#ffQOF52cOnkmr4nov^W!bcj@PqWu@gBsX7MA5VT_MW`BMr}Y!@C|Vh}=RJ_p>q5qCoh;&V zxUtM<#`TJlWScxdp*|_O^Ztb-FD$zS zX6K{j6agorz2?2+eR0B|F%=@Z+?qh9UYbxn-3o4vI~gQbks4 zJOvv)747_p6(1j+vuAO$QJ;sWdiTNo-Dg2+RyFp=ecEM|1}-!ST~Uey{lskpBTVRF zO69hc%$&GrLno4RX4}}_E)lv+vd5l)-Lh6%)=KpQPV5=aY(`KO0VLlU!(E&1l+r;B zB{5p&!{Ni0DBfLCxb;%VLg`hRkPk5^&jo+2%JZNKL2`s7pN^c^UYRtbteJ{Q7>pPJ z&&F8{2CuVSy0*acn)WV+hiHR9j3tgd`Y_$=mPZ&f;Q)P|#~maLR+IX%F|>LcGF<>U z627Lu`;#~&+GI<{Vhu!^lbuf?)w@^jU22$5Cc8?$!c^Hqb>@sdVqtUO*fV7G^Q}x3Dy9U3PXXJJ5KD~Bl zqZjDlkWKkZr_keJNuR6TW)YvaE8P1kORT(N`ykyfl_^i9G)_uao4sLDmPBSew@vBx z)~3>0`n~vE3kE(!vnp!JjfXmJrLumEc4*Tm-m~F4(nyw3E-e_&>WUqB{tOi9`F`GK ztC*b@-A!c`p1t!9MZb|Hme)q_+*H0|Icj73>7Sp61~5Krdf#7I!tdYD{~sLO#wks_)B9b3ZNv!A!6=&EEW-ycGB&42XYrQtxMaKTyH;1;2g%hp+kr z_V>=}x8QFh&!6&s`v>eleAZtT{$@~qAKwa-+`F~E*_A&^{(K|)W>`J|gueqG?8|=! zelsv1fL4D7{;)Iu8UD@Ce1O0FJNO^==09ioW^g`anfyhT?{?=uXZmJ%K4e0;*Q@Ru z_oENrr}O*%e9QF5jr2#tzc)aCq|Eb|{&xv~vO^z^_1}wW4;2g%|J5#ktMF%O?XM;N zDqlR5P`al$|Dr1oCBBOp4+VZ+e&0yb_kjv_cPH@pKUVw?3iYGKKZC!Ks0Xm+&)}aa z)jucuMyei?75(>Q|Ak`xsPz4~{gq_>sFmmc=>AOj<1GI^=fCduFDv~{xgMJQz2ILj jx(@}7?oXQkYr%(0u)Gu$^taro_b=#sg;#>$+pqrt43(v- literal 9347 zcmb_h1yo#Fwyoe0q;Qwu?hxGF-8HzoySuxEpuyeU3JVZ4IKd$aZUGYDlSy|oJ?ZJ0 zzy7~#)qAy8oxRV!=heG!zq1vj!6D!PKZbm2vgSX&{C0qSJj;rz2+~Q)i7_br76t>5 zdkj1DpSx{;{2Bil0D$(-VX}g9l47FDD)h2qs&V6ReT=~1u8b%0|P93!ltsecL>XmAOG}VPW%*Dc(oz1f_R{ z;9EuNScbGx?(XiYv})-uWaKz@@%ZvMy?gxS@{*vw#A4^FymNLrKe0P5Ae7-%EVtmD zxtZHtjYg5u`+czhfTQ1^YXbhbSR>m%s_|>U^Pd40c1Cu_CXRm-i2Ub34;N!YyT1v? z`m1moJ7X7XlfOaX{SC^(&iS8^n2CR0D9L|7+FQGrSv(a21|a_Uw?LJJ4HJ2+fa&9G zS^ql%31??}2}4_BYZFI$BWpt^r%DZ2Z?rk=hwgFm`b8O_S`~WSoA4L&VEIB|)WITP zF9M8F2MQeOxFw<3xxb9jCh8G164+F_H@bfyz_1%2@z-i-Y_!z&%3WF#E>N{XI;`A$ z7`H|oHkG{nay(?(^>yuQ*VoPmH@??i4^uvX)Cg}#zJM|f=2z)VELGYGUCufzB%P)_ zIg^~9M3f?&n-iid9J6Ps>9FPZQ^C3gLJY+c+qN!5U-4=&mr@W{irG=;&3hJv8o$ku z8)V^zh}^oxASte%#k27k1%|Wkaw$t=C!~%jy_QlBXj*=rOe%w|n@=Cq;DaiO*eluSiiM7WMKZ*#DGa`S}OHt>~0 z7ZVn{qo|(CAztKvuRQ$M-2$W*M8`q7x}3 zua!WOkDh&t3hUt<B#N>X4_!xHV1uY|iIpvP!PM{yOuWj$2qYU-fn!xdrqK%+54g4M@sF~o|RAlsA?U14iudp2t$ zSniBN6?6nLP8qkst+#&9Q4q+!$+YVUR78VxAfHgGQCvSUTy)Vk@*HIvD~zl+Ie=_; zF{`v))@mkr)y1a{3Y!!h_i7yHIwY9MMhKk|9(8Rf?4L}}Qk|haEm9PGsaCeaSc(%J zPmPWDYyivmdD*V?`&m`z0FJO%sZ|K=yOwK`>zmV|cpTAu*M3I3sq?T>2nI4MLFh0SAd{*kxQE!mQ#9E7yukPxYTkQinoWLtqXFo;c*63W6?Ik>6;u@!wT4Upok}iR zoRBYTJBWqc$yF+h7x7)hcM+iqE{^-_(Vmmb_E)jdMKx)^<>aN6G-Gn!pE`9O(=7Pv zuxi2AE}3Q?w%xe2)tql&4WQYgQTqT#`G}o*eQ@gpgPPUL7ZCQj zDzUP0FX}_h6;AwnB3ki`iq?vzWW(D&>r?Cxdkf&M;Kq1b2pY+hA%x?~-QnZjsZGdWdwPeoQ`WeWmet`jO65uq zUS#TkEGvj{2jmWte7>N9eVTT#;@^lhs5mzm8MPY#8*# zwPU9!49YKMXl(4>hNpZzL)f{pU)$Kdp5F`cV;-+%R>nwXKK@k9m(RxLgbO*e%|@Y2 zD)8MD_R*=YqDBLy)^(7osYVveu$NOuL4w|d{3<6w4%fP3e%L1bDCXS36nI!BsJ*)s z)V|c!Toxx~F)p%ZBI=ULIpnyd`X$$7zMzZ#HvF^<@yr=leLe)yg;-40?>ODq)|_b+ zTbB_H;|Hyj+Frb-yVdgC7SeBpx**o4bJ z#`HnqqaNEt+1{!0aNX(4+k(n|Xj}Udg2g(kZ{?At>4TrtSZqKSp2B>36mjkeYLZmm zAq_aIlCpXt>nl?@+wLBUCesi|kL`&2IUuj2y!o{wR7B_*u9vi-nP zG;HPgr7_(|%ct(!U3Je@!hOcZ6@+Kzq7#m+lM`1;yAPLvQ3FGfnIS*7Hc>Q+VmTQ~ zW%QfOez=qOfHh1?FPpui0NphBm6M(x)vw(hdu0KK-1>{IpdR6u9iB5qWOa_I@GJM% zG;#X6y2RTP<+o2^d+(+0{h&*|r{Ta( z^5P3TeSN+|y>mTRzlVu*bJ*@T{LVeH%8BY5JmLjG?!>yfHHbDG7ExHJ!fvj_+@DF< zeIX$4trskgetvNl*_lp1se;W_M<}lTt^eL93B0+0o|WR@E5pIi3T`c_3dR);fi89# z%r|fXUTziiD|z}8C}rVu&S871d;F8VoNRu&2XYx|8b9E3;izwloiqpU^)+;XSD3UF zYVJp+ft~%4z7=JN!Qft#D!MJ;&&z{Mln0uIfU7OIhs1aXL!sghh(Ioe*~K__mxSbb zRQk_Drs~FqCF&Rb+f8ALc=Rwd8$$GlA&26NXgo>CXo#V=i18;0g0S2QgBettIffH) zNRDNR=lM06oKcgyq2)C(NFcLCmYvhAy`?P++VzhGu%Bx2#IH?r4(bbJcpwyZxOb3OEvXzS;Mqi@nNEoo zEKOdP>0vM3-Ssrow0@;KjuZ$Hf(1U~)7mJ!gV{oE-Vx%SS&3IaB*7(s%*)ob!fP~y z=bU)(6jZW~dP-{PjDs*MP^ksmz-k!vc3gqld}zEyKQn$7v2WL@w9raOa#eKnSm|s0 zs9Whb9aN0zn?gY}%zd_#L$ftFAmfH13kvmhN9*0nOAP6?b)8udi;lp!K#qWo0IvW- zPd!+k=hr+{)rf*SL&iHSXDbF)g=D&PWL$EV~6QMxUi>m(Vg15 z?wB5<@V)K6j6xEf0m?e=^DJd#9m*aNFHb2(Q@+woINj|b+{;0eS8tzb8$Z-%WkJqF zsN_d4pREk&>z$ICUTiV+TVk{f!KfqTwtumszhqx?==K}pzeb4P(!F2n_iYB&1j6PT z)LsLAe}DO@%FVBfS%$#?04^v1fbG9m3j{hMHp@SxT{oPw>P|gKg7(NDd>~DXtz{V#wCEP>yh*B zn$!D?RyW`8-_P)Sh}Ga5m^7NqBtKr^BWr{qgnj$abJ|%DM;=)JtUfixPaG@$w&8_X@;H3}ZQHNRp z;Uh=1X-<@QZ!(oRw!qp^*g>-7In<1Gz z)ei2mTIFWoXAUxka#rq+wtL@kD{%X3{O0!rzML6{r+pVQh+->kCv~7U@{A+24?Rk( zaMxi2TcT?i;5=8OZIEjc`Gms2yL|a&x;)!CB?7Z84b=q%?xGa|zY7I|prNmxhjh`I zFD@x}>8@fFdWlz{9!HjREBZzg*9WR?*mcG_wL&jKUdFdL5B6MnKj}@avO4sc#I$+n zIY$+-=oO9+K0H2QqWO@^N_Y<+N)413w?{M|b+KKGa;y(Xp*135n(3&?aPK&$*3q&f zBI4mlHiaS<$R9X2ur<7qtQC0%CVhdzGlU1X(Ca8se@yBpqWpgMG`U1Pc(1Xy9!MS+ zGD(jD4?{1l5TZcxyz%o#$Nhvm$Uom2?6=wWq%Z&g<>T8p%m4P)_<3XGsC)ULsbl-f z(aY3j0PDc$@)7}g)?kKOQYkfPSx}C7S@DVKFlvVf2P3A##-=$Lvf+)EHkD|U2CB)K zP17X<#6${?MgH@amqy0m50|(l#~F(&!;QN`cJDL3cFgZ}X7|5+!0rTJ$NnxY1SK3| zO5IkZ$z)5@Ig)NkrK?73VNcv9)h99NqFm~iUwtiHgmPKr;c1 z4hJ6sQXtb1?75~J-fa|q`mEcrcJKk8*YbpVra@Z)=}HVBU+>` z6A|Cm(BKmOW^Q1&ta!N$NAfi++Sddh-)t+%`MRvu)k>@EjniSKMs3x^DqG4-6HCeE z-Qse*^l|aBb0eLDtMV$Xlu7L5;a3~wu)2%<%Kog|2XpYNv#UO6E+rKy9hKx8fDh}) zuvXXv9#}y*sw9}6COnZY@U0FxKmL`06TieBL211XS7P z;LlU%Sa%dIu;z6bz*U*yYN(;-;2GpDe6H6UUroTb$#r< zPn5p5&Gogn*}n&sZ@GQMCnRX+x2I#4BX4OJWs54CXVtHyadT8AK~0oDhbHLBYY2N>dJFM$C)21xbpvJEv`w zPI^mWmVC-A%xdV&n?5MhG7HL-Xx2~N(u%;Fgn2$e&p`8{j3!VG+vXZa`1MSJvyocd zqWLB8yka*3cwN}uLnDRUWS_B&(j~Vg*Nm3bZd;x2Qc^sE03wwtu*KgeA0kdoDQT=U zCiXA54&6VoOO(&^oH`RfO(cRK6TxPeEsfAhm2Oo-jkMco9XST5bddVOl(|kuzmI)B z4v(KVj7MRrjl?jbfT6h*Py>N8!@XDHNL!iIp5*XNXq=#OX%8spHp)0D8bnM7QsC6L z8`~09RjJ72oaW3bP&ftioa%9-+>S zbpL61hUZ<7dO8Pv0p`a%oQTh+(S|H3qk*F{qPbzmn_eh-c{D~2a@Ze-kVK>}GI3OO z%q7P;uU`mz=t@f~kBEHKE=|Hz#)MMZt16O1l*#5uO-<@f}d$$XWE9*;#A3XOdI6Z3k^_C~)^{Aur)I)uhW)fUNmJH7>97_}n~G8{r_< zP%d3UH)=)uhEpfsC{vig^?6=b9OD%q@qt|5gle3cV zU*rzgaIvzm=Hg&j`jQnO33__&qgB~ZpgLc6iZ@@&MDzL&g;mRBcN6zqH)4Ijq(X`c z5)`W-@Do8HxVx?l{>X^NF!hz$H%yxKh&)W6jt$379!IRYq!U|$p3$D{yYE>MbBZVf ztsDb#48_1qVt$NPtnwG6@)+q@VzBO^I_}n-)Zv`ZSZ$K2Gvdw>4PHk~$+W7Q7Y&yS z7)Sw|-@^$g&)>*?^{G#3VACsziVOUdQ7de(JR)<*1Pf^eIQP^UnucXL5Dm8RijPA5bkT;S30-aq<{JFAzMXWLY! ztWJnXky2hYoEAvmHXgy~QWj13s|I1gM?fXf2fT_wOkV2njMonhsQH%-a9X}MO)rv@ zk&I^Of{Q`wo_tj#UZUF|PkE4*K452IS95&G^?eY2AA=ZSUm)|&%9jE9mGX{&{B=~4 zg^Yl+^&`WB*09y)6YCps_bb#2w6OOv27XXgsAMX9ky;8je7OPa8?wcF<4{Niuiz|E zJ!&&Ls6cAgf-oivviC5@#ve77+A(=FF^D%esNyVV2r7}qvV7u(cVW6ly{%Y`J_>$7 z13QkuUYaj#Gz+IbOQ}Om9zhpr=LszkuM0hSC1M?VQW?rr(qI{bzTAXFjB$W9Q0t{I zWI#YgDD(;_r!8ve@R7(X$k(`%GjkGZ0d3gRYRt7NakF zxEsWAJ35IwKkBmB$+H}ruW8bht4X|B4fNlRtovNx-T-lUPod0tV_&}Yw=Dt&=&A(E z&y3ho`%4A-AO+wTd*wr^25&qsAzAbsZ~*GMzuv~(|6oT-hn$^%x7^Szz;MX7^mXQ5 znAHP#bZ#gmoF0X=zs($=5$<*Zy<`&K7}OG2zAcSTc8hZ_F**3@JC`j`w$Pck?q1r~ zOv(V|_EW9~bUunL)Oo~BYFd^cd=ZOl*uc@|`|IcTQprR)87B|-q4Fp4%-5y!k80`R z4?X^?$Aa`II{xrjYz$pZo?7a^1{3}oY-CISo7F)7%I;4M{eN|Hc>Xi^A07nVPg8;J z(H@{Pe{9av{nF|GVHE^X?YzEzG(%V(7a;t9WVW}np?9~jo>Lo-U1kS%9V^2KRS|dc z!$gLt2_~?b`$K5H87EfP%D1T^OC+N5YVIZQ94j?PCVGqKXr=!qE#Gd2+$S1Q^lmD( z@yM0obOgtj<-6%F3Fm1+IWdx&iUs+#rh7QKp@0W9^WdJ@M)`5Bn0`oHVvq*4gQPO5 zj)iO43?$vKQv!-ICtY;HTP#dtQBLB-9%dBF*!TKfJrw4F1lFNRYlvYE>KVY>PO zSPq@y3nxVW`XPLfdX+<-onl|M;JjEf@HXceUi+yl#$wHfo+O9DwhV?0oBM7k$(MyQ zU0Gw0M&z%M&Z(X1L@4pSOH3vqee3vaIlP}UeYyP^N-W57y}9P5wY&NJvX2e2zKz#9 zpp)5ELBbhiFceISL08AtHsRSA4qaz1J3lcwLn481QMx`hf!1I~H|r>o-es9BZ0vxH z_uQl;@`E!Mk!(lnrH#(^!M3Bb-Scp~fWtdLnR1Dkk~(En?YA!QtkWdVcTB{I2z6GT z-`8XEX-ps1-1qk6$ehgRFhMG`;uh@jimwo7OB|BcFqJnFq|4Goso_Q(Z}}4qz#J^c zE-AmkAt&$<7I_CEPW2mIBs(O2%#U1ib2@rU_U_I~u9>^#cz0%Rmq4*EhWcjW<=_@9 zZS!Z?cNdYxMV)yrW(Qf{)N1;3bj}FV;prpbOjS`engSA@=L=er>Lzklw96ARW0KBy zRW^~w1D!$l=ej5U^4V~FM(0WiHf1$%X)D>8vMjVMXbn>Dg~ED+;`C=Vvw}jnlB9vQ z4Oxu-X%h{#I^6l6Ve`1)PcWEx251Ml>myDD_&o>ZSQaqH`EbAzL9E?t@}lDV*S;z$ z@nkk%yWEhGjSjx2AC?w&e&Hr>brnFdR4!hX0?Q9VPIFkw?=>Pm zj5%|`2lr$TT6trjeWj-tM71KwWe;9qsH*9GxvpoDkj# z!u1mY1*SUR0_)U7q+SG6XyLT&mv#D2Sun?QF~01AF=kF=QEW&@C;m>`*e@*eP9h9dO z$H4z(il6 uploadJar( - @RequestParam("id") Long id, - @RequestParam("jar") MultipartFile file) throws Exception { - if (file.isEmpty()) { - throw exception(FILE_IS_EMPTY); - } - pluginInfoService.uploadJar(id, file); + @PostMapping("/upload-file") + @Operation(summary = "上传插件文件") + public CommonResult uploadFile(@Valid PluginInfoImportReqVO reqVO) { + pluginInfoService.uploadFile(reqVO.getId(), reqVO.getFile()); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java new file mode 100644 index 000000000..9216d09ec --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +@Schema(description = "管理后台 - IoT 插件上传 Request VO") +@Data +public class PluginInfoImportReqVO { + + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") + private Long id; + + @Schema(description = "插件文件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "插件文件不能为空") + private MultipartFile file; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java deleted file mode 100644 index d87a94f31..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.module.iot.framework.plugin; - -import org.pf4j.spring.SpringPluginManager; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; - -@Configuration -public class SpringConfiguration { - - @Bean - @DependsOn("serviceRegistryInitializedMarker") - public SpringPluginManager pluginManager() { - return new SpringPluginManager(); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java similarity index 55% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index 3450b67fb..66adc3c9f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -1,35 +1,36 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import lombok.extern.slf4j.Slf4j; +import org.pf4j.spring.SpringPluginManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; -import javax.annotation.PostConstruct; import javax.annotation.Resource; @Slf4j @Configuration -public class ServiceRegistryConfiguration { +public class UnifiedConfiguration { + + private static final String SERVICE_REGISTRY_INITIALIZED_MARKER = "serviceRegistryInitializedMarker"; @Resource private DeviceDataApi deviceDataApi; - @PostConstruct - public void init() { - // 将主程序中的 DeviceDataApi 实例注册到 ServiceRegistry + @Bean(SERVICE_REGISTRY_INITIALIZED_MARKER) + public Object serviceRegistryInitializedMarker() { ServiceRegistry.registerService(DeviceDataApi.class, deviceDataApi); log.info("[init][将 DeviceDataApi 实例注册到 ServiceRegistry 中]"); - } - - /** - * 定义一个标记用的 Bean,用于表示 ServiceRegistry 已初始化完成 - */ - @Bean("serviceRegistryInitializedMarker") // TODO @haohao:1)这个名字,可以搞个 public static final 常量;2)是不是 conditionBefore 啥 - public Object serviceRegistryInitializedMarker() { - // 返回任意对象即可,这里返回 null 都可以,但最好返回个实际对象 return new Object(); } + @Bean + @DependsOn(SERVICE_REGISTRY_INITIALIZED_MARKER) + public SpringPluginManager pluginManager() { + log.info("[init][实例化 SpringPluginManager]"); + return new SpringPluginManager(); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java index 867103402..d023791c8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import jakarta.validation.Valid; import org.springframework.web.multipart.MultipartFile; +import java.util.List; + /** * IoT 插件信息 Service 接口 * @@ -58,7 +60,7 @@ public interface PluginInfoService { * @param id 插件id * @param file 文件 */ - void uploadJar(Long id, MultipartFile file); + void uploadFile(Long id, MultipartFile file); /** * 更新插件的状态 @@ -67,4 +69,11 @@ public interface PluginInfoService { * @param status 状态 */ void updatePluginStatus(Long id, Integer status); + + /** + * 获得启用的插件列表 + * + * @return 插件列表-插件id + */ + List getEnabledPlugins(); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java index bd7efa8d0..333d0fa98 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java @@ -1,17 +1,13 @@ package cn.iocoder.yudao.module.iot.service.plugininfo; -import cn.hutool.core.io.IoUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; -import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.pf4j.PluginDescriptor; import org.pf4j.PluginState; @@ -22,11 +18,13 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.web.multipart.MultipartFile; -import java.nio.file.Path; +import java.io.File; +import java.io.IOException; +import java.nio.file.*; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @@ -47,9 +45,6 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Resource private SpringPluginManager pluginManager; - @Resource - private FileApi fileApi; - @Value("${pf4j.pluginsDir}") private String pluginsDir; @@ -95,6 +90,19 @@ public class PluginInfoServiceImpl implements PluginInfoService { // 删除 pluginInfoMapper.deleteById(id); + // 删除插件文件 + Executors.newSingleThreadExecutor().submit(() -> { + try { + TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 + File file = new File(pluginsDir, pluginInfoDO.getFile()); + if (file.exists() && !file.delete()) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFile()); + } + } catch (InterruptedException e) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFile(), e); + } + }); + } private PluginInfoDO validatePluginInfoExists(Long id) { @@ -116,73 +124,100 @@ public class PluginInfoServiceImpl implements PluginInfoService { } @Override - public void uploadJar(Long id, MultipartFile file) { - // 1. 校验存在 + public void uploadFile(Long id, MultipartFile file) { + // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // 2. 判断文件名称与插件 ID 是否匹配 + // 2. 获取插件 ID String pluginId = pluginInfoDo.getPluginId(); - // 3. 停止卸载旧的插件 - // 3.1. 获取插件信息 + // 3. 停止并卸载旧的插件 + stopAndUnloadPlugin(pluginId); + + // 4. 上传新的插件文件 + String pluginIdNew = uploadAndLoadNewPlugin(file); + + // 5. 更新插件启用状态文件 + updatePluginStatusFile(pluginIdNew, false); + + // 6. 更新插件信息 + updatePluginInfo(pluginInfoDo, pluginIdNew, file); + } + + // 停止并卸载旧的插件 + private void stopAndUnloadPlugin(String pluginId) { PluginWrapper plugin = pluginManager.getPlugin(pluginId); if (plugin != null) { - // 3.2. 如果插件状态是启动的,停止插件 if (plugin.getPluginState().equals(PluginState.STARTED)) { - pluginManager.stopPlugin(pluginId); + pluginManager.stopPlugin(pluginId); // 停止插件 } - // 3.3. 卸载插件 - pluginManager.unloadPlugin(pluginId); + pluginManager.unloadPlugin(pluginId); // 卸载插件 } + } - // 4. 上传插件 - String pluginIdNew; + // 上传并加载新的插件文件 + private String uploadAndLoadNewPlugin(MultipartFile file) { + Path pluginsPath = Paths.get(pluginsDir); try { - String path = fileApi.createFile(pluginsDir, IoUtil.readBytes(file.getInputStream())); - Path pluginPath = Path.of(path); - pluginIdNew = pluginManager.loadPlugin(pluginPath); - } catch (Exception e) { - throw exception(PLUGIN_INSTALL_FAILED); - } - - PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginIdNew); - if (pluginWrapper == null) { - throw exception(PLUGIN_INSTALL_FAILED); - } - - // 5. 读取配置文件和脚本 - String configJson = ""; - String script = ""; - try (JarFile jarFile = new JarFile(pluginWrapper.getPluginPath().toFile())) { - // 5.1 获取config文件在jar包中的路径 - String configFile = "classes/config.json"; - JarEntry configEntry = jarFile.getJarEntry(configFile); - - if (configEntry != null) { - // 5.2 读取配置文件 - configJson = IoUtil.readUtf8(jarFile.getInputStream(configEntry)); - log.info("configJson:{}", configJson); + if (!Files.exists(pluginsPath)) { + Files.createDirectories(pluginsPath); // 创建插件目录 } - - // 5.3 读取script.js脚本 - String scriptFile = "classes/script.js"; - JarEntry scriptEntity = jarFile.getJarEntry(scriptFile); - if (scriptEntity != null) { - // 5.4 读取脚本文件 - script = IoUtil.readUtf8(jarFile.getInputStream(scriptEntity)); - log.info("script:{}", script); + String filename = file.getOriginalFilename(); + if (filename != null) { + Path jarPath = pluginsPath.resolve(filename); + Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING); // 保存上传的 JAR 文件 + return pluginManager.loadPlugin(jarPath.toAbsolutePath()); // 加载插件 + } else { + throw exception(PLUGIN_INSTALL_FAILED); } } catch (Exception e) { throw exception(PLUGIN_INSTALL_FAILED); } + } + // 更新插件状态文件 + private void updatePluginStatusFile(String pluginIdNew, boolean isEnabled) { + Path enabledFilePath = Paths.get(pluginsDir, "enabled.txt"); + Path disabledFilePath = Paths.get(pluginsDir, "disabled.txt"); + Path targetFilePath = isEnabled ? enabledFilePath : disabledFilePath; + Path oppositeFilePath = isEnabled ? disabledFilePath : enabledFilePath; + + try { + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginIdNew); + if (pluginWrapper == null) { + throw exception(PLUGIN_INSTALL_FAILED); + } + String pluginInfo = pluginIdNew + "@" + pluginWrapper.getDescriptor().getVersion(); + List targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) + : new ArrayList<>(); + List oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) + : new ArrayList<>(); + + if (!targetLines.contains(pluginInfo)) { + targetLines.add(pluginInfo); + Files.write(targetFilePath, targetLines, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + } + + if (oppositeLines.contains(pluginInfo)) { + oppositeLines.remove(pluginInfo); + Files.write(oppositeFilePath, oppositeLines, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + } + } catch (IOException e) { + throw exception(PLUGIN_INSTALL_FAILED); + } + } + + // 更新插件信息 + private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginIdNew, MultipartFile file) { pluginInfoDo.setPluginId(pluginIdNew); pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); pluginInfoDo.setFile(file.getOriginalFilename()); - pluginInfoDo.setConfigSchema(configJson); - pluginInfoDo.setScript(script); + pluginInfoDo.setScript(""); - PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); + PluginDescriptor pluginDescriptor = pluginManager.getPlugin(pluginIdNew).getDescriptor(); + pluginInfoDo.setConfigSchema(pluginDescriptor.getPluginDescription()); pluginInfoDo.setVersion(pluginDescriptor.getVersion()); pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription()); pluginInfoMapper.updateById(pluginInfoDo); @@ -190,52 +225,50 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Override public void updatePluginStatus(Long id, Integer status) { - // 1. 校验存在 + // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // 插件状态无效 + // 2. 校验插件状态是否有效 if (!IotPluginStatusEnum.contains(status)) { throw exception(PLUGIN_STATUS_INVALID); } + // 3. 获取插件ID和插件实例 String pluginId = pluginInfoDo.getPluginId(); PluginWrapper plugin = pluginManager.getPlugin(pluginId); + + // 4. 根据状态更新插件 if (plugin != null) { - if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) && plugin.getPluginState() != PluginState.STARTED) { - // 启动插件 + // 4.1 如果目标状态是运行且插件未启动,则启动插件 + if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) + && plugin.getPluginState() != PluginState.STARTED) { pluginManager.startPlugin(pluginId); - } else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) && plugin.getPluginState() == PluginState.STARTED) { - // 停止插件 + updatePluginStatusFile(pluginId, true); // 更新插件状态文件为启用 + } + // 4.2 如果目标状态是停止且插件已启动,则停止插件 + else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) + && plugin.getPluginState() == PluginState.STARTED) { pluginManager.stopPlugin(pluginId); + updatePluginStatusFile(pluginId, false); // 更新插件状态文件为禁用 } } else { - // 已经停止,未获取到插件 + // 5. 插件不存在且状态为停止,抛出异常 if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { throw exception(PLUGIN_STATUS_INVALID); } } + + // 6. 更新数据库中的插件状态 pluginInfoDo.setStatus(status); pluginInfoMapper.updateById(pluginInfoDo); } -// @PostConstruct -// public void init() { -// Executors.newSingleThreadScheduledExecutor().schedule(this::startPlugins, 3, TimeUnit.SECONDS); -// } -// -// @SneakyThrows -// private void startPlugins() { -// for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { -// if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { -// continue; -// } -// log.info("start plugin:{}", pluginInfoDO.getPluginId()); -// try { -// pluginManager.startPlugin(pluginInfoDO.getPluginId()); -// } catch (Exception e) { -// log.error("start plugin error", e); -// } -// } -// } + @Override + public List getEnabledPlugins() { + return pluginInfoMapper.selectList().stream() + .filter(pluginInfoDO -> IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) + .map(PluginInfoDO::getPluginId) + .toList(); + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java new file mode 100644 index 000000000..18b9c1417 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.iocoder.yudao.module.iot.api.Greeting; +import org.apache.commons.lang.StringUtils; +import org.pf4j.Extension; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.pf4j.RuntimeMode; +import com.sun.net.httpserver.HttpServer; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; + +/** + * 打招呼 测试用例 + */ +public class WelcomePlugin extends Plugin { + + private HttpServer server; + + public WelcomePlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + System.out.println("WelcomePlugin.start()"); + // for testing the development mode + if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { + System.out.println(StringUtils.upperCase("WelcomePlugin")); + } + startHttpServer(); + } + + @Override + public void stop() { + System.out.println("WelcomePlugin.stop()"); + stopHttpServer(); + } + + private void startHttpServer() { + try { + server = HttpServer.create(new InetSocketAddress(9081), 0); + server.createContext("/", exchange -> { + String response = "Welcome to PF4J HTTP Server"; + exchange.sendResponseHeaders(200, response.getBytes().length); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + }); + server.setExecutor(null); + server.start(); + System.out.println("HTTP server started on port 9081"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void stopHttpServer() { + if (server != null) { + server.stop(0); + System.out.println("HTTP server stopped"); + } + } + + @Extension + public static class WelcomeGreeting implements Greeting { + + @Override + public String getGreeting() { + return "Welcome to PF4J"; + } + + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index 200a451b6..1ecf140a4 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -24,6 +24,7 @@ cn.iocoder.yudao.module.iot.plugin.HttpPlugin 0.0.1 ahh + http-plugin-0.0.1 @@ -104,6 +105,7 @@ ${plugin.class} ${plugin.version} ${plugin.provider} + ${plugin.description} ${plugin.dependencies} From 1a3c6756ab12b9eae2c8e7b71c71ad7c4fc2c2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 29 Dec 2024 22:33:16 +0800 Subject: [PATCH 062/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=20HTTP=20=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E5=88=A0=E9=99=A4=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/plugin/WelcomePlugin.java | 91 ------------------- 1 file changed, 91 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java deleted file mode 100644 index 18b9c1417..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2012-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package cn.iocoder.yudao.module.iot.plugin; - -import cn.iocoder.yudao.module.iot.api.Greeting; -import org.apache.commons.lang.StringUtils; -import org.pf4j.Extension; -import org.pf4j.Plugin; -import org.pf4j.PluginWrapper; -import org.pf4j.RuntimeMode; -import com.sun.net.httpserver.HttpServer; -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; - -/** - * 打招呼 测试用例 - */ -public class WelcomePlugin extends Plugin { - - private HttpServer server; - - public WelcomePlugin(PluginWrapper wrapper) { - super(wrapper); - } - - @Override - public void start() { - System.out.println("WelcomePlugin.start()"); - // for testing the development mode - if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { - System.out.println(StringUtils.upperCase("WelcomePlugin")); - } - startHttpServer(); - } - - @Override - public void stop() { - System.out.println("WelcomePlugin.stop()"); - stopHttpServer(); - } - - private void startHttpServer() { - try { - server = HttpServer.create(new InetSocketAddress(9081), 0); - server.createContext("/", exchange -> { - String response = "Welcome to PF4J HTTP Server"; - exchange.sendResponseHeaders(200, response.getBytes().length); - OutputStream os = exchange.getResponseBody(); - os.write(response.getBytes()); - os.close(); - }); - server.setExecutor(null); - server.start(); - System.out.println("HTTP server started on port 9081"); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void stopHttpServer() { - if (server != null) { - server.stop(0); - System.out.println("HTTP server stopped"); - } - } - - @Extension - public static class WelcomeGreeting implements Greeting { - - @Override - public String getGreeting() { - return "Welcome to PF4J"; - } - - } - -} \ No newline at end of file From 8ca9bebfd1c8cdac3f64842df1d7c640ce68fa1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 30 Dec 2024 09:33:56 +0800 Subject: [PATCH 063/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=9B=B4=E6=96=B0=20HttpPlugin?= =?UTF-8?q?=EF=BC=8C=E9=87=8D=E6=9E=84=E7=BA=BF=E7=A8=8B=E6=B1=A0=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E9=80=BB=E8=BE=91=E4=BB=A5=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E7=BA=BF=E7=A8=8B=E6=B1=A0=E6=B4=BB=E8=B7=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iocoder/yudao/module/iot/plugin/HttpPlugin.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java index 70da0131c..66e0c69a3 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java @@ -19,12 +19,12 @@ public class HttpPlugin extends Plugin { private static final int PORT = 8092; - private final ExecutorService executorService; + private ExecutorService executorService; private DeviceDataApi deviceDataApi; public HttpPlugin(PluginWrapper wrapper) { super(wrapper); - // 创建单线程池 + // 初始化线程池 this.executorService = Executors.newSingleThreadExecutor(); } @@ -32,6 +32,11 @@ public class HttpPlugin extends Plugin { public void start() { log.info("HttpPlugin.start()"); + // 重新初始化线程池,确保它是活跃的 + if (executorService.isShutdown() || executorService.isTerminated()) { + executorService = Executors.newSingleThreadExecutor(); + } + // 从 ServiceRegistry 中获取主程序暴露的 DeviceDataApi 接口实例 deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); if (deviceDataApi == null) { @@ -79,11 +84,11 @@ public class HttpPlugin extends Plugin { future.channel().closeFuture().sync(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - log.error("HTTP 服务启动中断", e); + log.warn("HTTP 服务启动被中断", e); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } -} +} \ No newline at end of file From cbfbc55cd8612296978b56a122972a35e0e4c5da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 30 Dec 2024 12:01:58 +0800 Subject: [PATCH 064/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=B7=BB=E5=8A=A0=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=92=8C=E6=8F=92=E4=BB=B6=E5=AE=9E=E4=BE=8B=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=8C=85=E6=8B=AC=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E7=9A=84=E5=A2=9E=E5=88=A0=E6=94=B9=E6=9F=A5?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=94=AF=E6=8C=81=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=92=8C=E7=8A=B6=E6=80=81=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=EF=BC=8C=E5=90=8C=E6=97=B6=E4=BC=98=E5=8C=96=E4=BA=86=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE=E7=B1=BB=E5=9E=8B=E7=9A=84=E5=A4=84=E7=90=86=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 8804 -> 8881 bytes .../enums/plugin/IotPluginDeployTypeEnum.java | 10 +- .../iot/enums/plugin/IotPluginStatusEnum.java | 10 +- .../iot/enums/plugin/IotPluginTypeEnum.java | 11 +- .../PluginInfoController.java | 13 +- .../PluginInstanceController.java | 64 ++++------ .../vo/PluginInfoImportReqVO.java | 2 +- .../admin/plugin/vo/PluginInfoPageReqVO.java | 17 +++ .../vo/PluginInfoRespVO.java | 4 +- .../vo/PluginInfoSaveReqVO.java | 4 +- .../vo/PluginInstancePageReqVO.java | 2 +- .../vo/PluginInstanceRespVO.java | 2 +- .../vo/PluginInstanceSaveReqVO.java | 2 +- .../admin/plugininfo/PluginController.java | 116 ------------------ .../plugininfo/vo/PluginInfoPageReqVO.java | 59 --------- .../dataobject/plugininfo/PluginInfoDO.java | 16 ++- .../dal/mysql/plugin/PluginInfoMapper.java | 25 ++++ .../PluginInstanceMapper.java | 4 +- .../mysql/plugininfo/PluginInfoMapper.java | 36 ------ .../PluginInfoService.java | 6 +- .../PluginInfoServiceImpl.java | 17 ++- .../PluginInstanceService.java | 6 +- .../PluginInstanceServiceImpl.java | 9 +- .../plugininstance/PluginInstanceMapper.xml | 2 +- 24 files changed, 126 insertions(+), 311 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{plugininfo => plugin}/PluginInfoController.java (86%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{plugininstance => plugin}/PluginInstanceController.java (76%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{plugininfo => plugin}/vo/PluginInfoImportReqVO.java (89%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoPageReqVO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{plugininfo => plugin}/vo/PluginInfoRespVO.java (96%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{plugininfo => plugin}/vo/PluginInfoSaveReqVO.java (94%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{plugininstance => plugin}/vo/PluginInstancePageReqVO.java (94%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{plugininstance => plugin}/vo/PluginInstanceRespVO.java (95%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/{plugininstance => plugin}/vo/PluginInstanceSaveReqVO.java (94%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInfoMapper.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/{plugininstance => plugin}/PluginInstanceMapper.java (89%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininfo/PluginInfoMapper.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{plugininfo => plugin}/PluginInfoService.java (87%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{plugininfo => plugin}/PluginInfoServiceImpl.java (95%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{plugininstance => plugin}/PluginInstanceService.java (82%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/{plugininstance => plugin}/PluginInstanceServiceImpl.java (83%) diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar index 28b10d529ce689efb557305c356827c90e42e60e..25120abe7f4494bd468cca84c8cea531193ff425 100644 GIT binary patch delta 3218 zcmZXWX*d*I`@qMNMhqFs3}%`^BV)-<64^DfFPW6c+DK%VWo%^|W0|s>Fi42-geHO5v_2Y=Q$V6D zZGWIZXZaJ6&NIOoG-X0D7{nyWU(1bL4j$W8dY zY9H5)NuTA(T%YCT%1RADLu(mC^<@9a&;4=I%!A%W->~HFkgdFX7QK^O>(rJ)iwwnQ zcC!_)Q92$q7mQ4JedEyF0~X-x4Pd1+`pUNj=2XFb>}~aUSL)SRmcdf<5ohA-q3UDl z9LBK2h+p1yLDCxhKw&)>i3oQCoWW{6(Ju1vB`52YqMajG0913lov(#idBQ9Rq|E-P z<^6Dp`^ByiuLMK@*wQ1&Xop3z2F>ANZF~DreJlO3JW;(BTpz^*3h?e0G>*^{H)KDTl;xI4zxuAR5l&~B=36n#yN^z4|?w}DVnG8Z4{ zFJ344doM4S2VwdiXp*Y9WbxKAA|H(-drZW2{)U*0_a*gZ^#!~Z*>0cy4O8w&@m!Hm z_Il$ReaLn9_iH)JZ?HQvhZ-XTi|fdCBwXox3Cs&qc;w6`WTWJwvnceG>1|H+ZwQYfQMny^sGPO@|p9@k3 zOB&S=LUvc5HWxH4YPjt+)Vz5q6bbs+u%WiGrT$a#_iise6i_*PM%oEsp_N9syCB1t zWo;1WyS{FowPRx-5Aptid*rg=h!5=p!h2Se2R|9@IXu8x8_>Y0G z3ANr5<%2Q+fq`JZCW+S7yc2{ZMKYov+nqXbO2;ik%n)dtyf3UcW}^@7Po@AT=c%zx$DQ!nuI}wl>mFgr1(ZxEGA{21&r;FBv5X*Tx%iW-UwN4c& z*%s3S)k;3QFJkk4A*56lfvp(DY=@X&u>i(iV4Azn>D?a2CQ92@m@?tuFJPx$3`rMwWW6>T}Lc@H-6pah4X zT6e0#`K-dK*w%e7ysgnO@8Kw|rb!Dm|BN1MGEv>1MvkF;zjp!=23DxP=c~<8r94Br zDP^|r4zF~RR7_m$nhUh`fVq6)VciJh^QQ0AQUc}jw)!95W2X{i&P@$V5seEep?cxM zJ&mG^H}IyuL0q-9O6kU+oW!S8p(X`Llb1vo&TDPqA^o|@a|1PMm_*oN$HEGoJm9!N zwMU|x(|EMG&yEp-zk;$af;896b|9W>_BK+M*)e9~=nk`f(~|hN^_M3yZmH;stiG4! zxuxM`^CtGX&b~gqD*9=Aph?Esm>ANW9k}B17%#S-oHS3*jDFgw67dr{d_Kj{Qr3Kj zLYzwrX!UJ0sh2Z)DK>;+KU3J2c!y$REveOAzT_6Jf45uVhDxG5xTixUW^2gT^(Al1 zala(d&qI5d0BSyOA4YSDUoK3%)RdeyM@ry^4i^Sb-v2q@TWLc4l0gmB4qPrEgzZ0? z!T9GncwPph8fqsb?YyW*m4UIzCFnz`js zc0Ju4>^!&K%n~8i&_{R5-aDDeeqM1I_4JqUo196@;99|0`&bxCu#|~qTk&SS5b)2A z?Y(M$0LZ;&5t=vKQ3h?0J^jO{%*stm5AQkS{|tK9T1v6&lW*(gH6ucjWm@iPtikSG z#lERLz0~w-9SRcHQ&l1rx1a7sa`?c^=GZCIz8fVrn`4g+sX&|2PS?+Dg z%f;Gqg6>Gnnw4g_L!TyHL||3CBt%C6^1^efEq>0m%`}y%m)}O|(GCGzD^oSy>cw6m z%3)F!%twy#n*N}q`sIfSU+kNUAHQSR9A!roH0)i~GVRM}(3{5*aTzqXkvE z&D*gWz^^uHxaBWZJ7E78h&D=eCl+T4`jEw%D@-`365=c9=5n-AA1-Yswc>~L+$P$3 z;BFRjG8@r6{^{EV-v^=0elgX0rW>cSc>)DdeL7zS6HnRJa#4!vJs_T!bOu?8LYst{ zH!Y?U67j>_oKZ;;sLe}QEj$|uK?!u_Y|K3ONuY%r@_fG{@FZq0O?Llr+KaeFw7)WO zZb(KtHoK`5(o!ie%kR8HULVU#T|cfZ>dga!D;cZ0Ys7h4NPyinE)?O%8)C$B!b6=F zM%aBcFs4Rr>VSuB<1jbPQz3y-E*}A0W*^lE0pFF(9+0Shg2a?ryvfOZ$z~1FKnYDy!*Ul#I6-o<@6jqUO&cD(mg}(!be%Ab5J` zP=w7_dx@jk^|S@%&}TDTG^g=U&BN?>mv-@&lW)IQjco1J-am!c|MVO1j|MR870b|A z0Dxq{FU;`LKz>yQU-4f%(%Kqsh#f2V$QRZ|%3MPKWXJv47yu~+sfG9Q_VjZ0_Pyim z1L~|g(SkS$=$ookX)m{-4O}ihjfuHRu2paV~6R|N5IM1|CLa*sI!eUQAun zLj~HidNzM~;JKF&v$x06LoLgasN2M7i;^yQzsI3m%c@17<=gEVz-6O zeX$ccS7fub;UE{71=2&1Y;uN5Q|kB#y9Tq=h2{nG#4ji2oD*MuZ@9 zJ^!D+AW3@&PDa8Bq#*Oo(UrQyza;_ze@eriOMSNwU|w}~87f=$EsWh{UqhD0P8j>Xj}N1=$CQvISy~i^vR0He zrN|741{0B=`A^?}{(H_n&t2a4o^$WH=iaAP|EnGlVM;^G3^*;_&36ic5;R>Wfc>I5 z>0uP8AQU2~&QcgnB}XBSN}0lsRH_v6Qfr>F9ZAi}%yH5{+TvE-DyRW~COQBBjtOE@ z#5A#rp)Ftb7uiVMqY}^p_F^K2+vYdSjTPg!6tHgmumhSyOFXtyJx88Rb+)@ba&r^iyq{i$%Qr~IRh@)5cQ&~aaE z_q=*(B?~QwcssU_TLNAe=A^Hnjdq|<+T?FhO7G1P3G~WxPZao$dy=+J+wbm9N1OwZ z;0q$dLJYQ!F4jkYkq57JZcUezJs&!hT*;|rYo!fxzuX@v6sc&W7y{v;&Yg=Wq)&32 zMn?(1erg6qR}<5i>c_?Z_}olKdbC$iM!Z=Fl%j^&ryEybrmy^Gw&e?1q( znk8Y|ThT18i8Utdw6AK^^LGz6RY*&3^#ToJtXifOUq^}h|KUQo0M|^40KIoGVf&EBm z<{;D?x1jd6ZxP*mcVw2PfMy~1leXHY6r+{}9tS+YPBGhlM(1S#jOa? zL|yLdyy1~`hiH6jm47jT%YFZl{_nMAJiWF^CKRyxZaD)0kdE2^@>b z*=-})#!T83-%{}e#Jioc#W*B=8g^`hHKn}ckzXKjQDwSbG9BIovpdJ1NEdqeexjlB z51-tDCP{>4798UBRV=@HphL{0BltMs zZM7Q5nA@;g9bfs87`os3SzlYfi)pSw_e#s=wumqtSp7V+sB(ZXBHebd74FQ0H5hJ{ z3z~V|sv0%iY9@={N_k<}0~4%sp>-`L2aMXCo40q)Xo@mLNcPac9<;T|4vaaN(a!e3vRJ9&N&2PWDBlh?Df3slC`Rjw>k z*YgFop|400UvR)O#zTt1^B=?x1~_2MmpS*}N`ZS)KNIMDwBL2elCA&gXE|g<&OiIw@#D9(1017wnn(T`+6)|D0TDcN+XHDnwF(nTiJE$Ur9avAQz_Vd zh(|#wTlKPkJ)m0{L$nEgS`jmszpUtjoSFER}RlS$80s{EPXkTa*bb7wF;$Wy`M`(AUQOKn^wR;>$TMice$O zqIlbR0cqh{5A<0DukD*z@X@hFx)e;N3_Jb zlb=7pwpOM_5cQN@mFy5!>@{tQ{w3Rww-v+}prz{?@MadJ1P9TNIHo9L{2fU~8RPk= z(V!I_{kPuzI#R|&KG|3OW^6&9J5$iZWqm@>1O3c$r2tTfWEF_6A8LtvSq3HG^IG`%xLhhxc*R-2??Ad{?h=w-yG?uLJme>wlrg@+RAlk~S;o4X=h0ax~4>j^bh(@7iub@6T$`*(n1FkgT(eeOpu-*@fTR zMh8_g3=XQ@`nC$QZ=ku&cDS76mS6a4L@@|FwHUB0N#zgThe4m~?Q3k@-{chc zI?GSCy05`!#E3;djdcXm9f~6B;S(G`p3bDi>FuD(>DDD9SKpusxk$l_h03X=G#<*S zo=xq(^}F+dk9x^hmeoG)89(_cS$++5s5izHBem@x9O$<{BN5MTSWqo*xHf4~;Kw?^ zF=l`?7vy?+A#E@j5%Y>k%5N6q)cnP59`>UTB|QswtJ)S6&Kj*) zp`1S#_h!jGM9n#)TM%cQkT-~pUrn+=%m~A>bW4MFKS`IGy_+culUXqxpSe3Y^MhC? z14x%*GOQT{lPdJ2wm0z6NzYBUWIK*C_CEL>GsP?>1nBRfGZUWO%$9s&jCKQ?(@7o< znhLjl;90gI7%)k1ow4|$8rh0cQi0keb(?qLNO$F0>St9OC+MHSWYtGf%1s zhMiXnlPd;714mk!lNH$klNzq5Pq*Ey)ub;xLR<=K(_+Uo(r-8$$tR&*zYSflFeAm}{jtXG8k}e0(hBO%E?AND09& zyw?JS>k1)vphaPGM6mJqGE*=9rq=rDR43^A>@mU=NJY&>^RG2y>V#mY+KibO(xPla z2qI6RIYfoRbci~Ic!(~AtipyA+6kLe*dXl6_*a`TAQ4C4Y3F}R6Cq+l2^$j;pwh$; zME)z~%%TF+*Lg4;yrLK*QC5-Dlv9iUTh#wH0PKL{W87)rWlXs+Gi9Y0C%M$TCqtST eK`~BB?*E value.getDeployType().equals(deployType)) + .findFirst() + .orElse(null); } public static boolean isValidDeployType(Integer deployType) { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java index 9aba854b0..aee2fbe0f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java @@ -34,12 +34,10 @@ public enum IotPluginStatusEnum implements IntArrayValuable { } public static IotPluginStatusEnum fromState(Integer state) { - for (IotPluginStatusEnum value : values()) { - if (value.getStatus().equals(state)) { - return value; - } - } - return null; + return Arrays.stream(values()) + .filter(value -> value.getStatus().equals(state)) + .findFirst() + .orElse(null); } @Override diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java index 27368d268..8b9cef2b4 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java @@ -35,14 +35,11 @@ public enum IotPluginTypeEnum implements IntArrayValuable { return ARRAYS; } - // TODO @haohao:可以使用 hutool 简化 public static IotPluginTypeEnum fromType(Integer type) { - for (IotPluginTypeEnum value : values()) { - if (value.getType().equals(type)) { - return value; - } - } - return null; + return Arrays.stream(values()) + .filter(value -> value.getType().equals(type)) + .findFirst() + .orElse(null); } public static boolean isValidType(Integer type) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java similarity index 86% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java index 4bb5b6e78..96eb3dda6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java @@ -1,14 +1,14 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; +package cn.iocoder.yudao.module.iot.controller.admin.plugin; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoImportReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoImportReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; -import cn.iocoder.yudao.module.iot.service.plugininfo.PluginInfoService; +import cn.iocoder.yudao.module.iot.service.plugin.PluginInfoService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -72,6 +72,7 @@ public class PluginInfoController { @PostMapping("/upload-file") @Operation(summary = "上传插件文件") + @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") public CommonResult uploadFile(@Valid PluginInfoImportReqVO reqVO) { pluginInfoService.uploadFile(reqVO.getId(), reqVO.getFile()); return success(true); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/PluginInstanceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInstanceController.java similarity index 76% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/PluginInstanceController.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInstanceController.java index 9382f8c6d..dc6433c7f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/PluginInstanceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInstanceController.java @@ -1,32 +1,31 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininstance; - -import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import org.springframework.validation.annotation.Validated; -import org.springframework.security.access.prepost.PreAuthorize; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Operation; - -import jakarta.validation.*; -import jakarta.servlet.http.*; -import java.util.*; -import java.io.IOException; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +package cn.iocoder.yudao.module.iot.controller.admin.plugin; import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; - -import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.*; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstancePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstanceRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstanceSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; -import cn.iocoder.yudao.module.iot.service.plugininstance.PluginInstanceService; +import cn.iocoder.yudao.module.iot.service.plugin.PluginInstanceService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - IoT 插件实例") @RestController @@ -78,17 +77,4 @@ public class PluginInstanceController { return success(BeanUtils.toBean(pageResult, PluginInstanceRespVO.class)); } - @GetMapping("/export-excel") - @Operation(summary = "导出IoT 插件实例 Excel") - @PreAuthorize("@ss.hasPermission('iot:plugin-instance:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportPluginInstanceExcel(@Valid PluginInstancePageReqVO pageReqVO, - HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = pluginInstanceService.getPluginInstancePage(pageReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "IoT 插件实例.xls", "数据", PluginInstanceRespVO.class, - BeanUtils.toBean(list, PluginInstanceRespVO.class)); - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoImportReqVO.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoImportReqVO.java index 9216d09ec..e71e4c484 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoImportReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoPageReqVO.java new file mode 100644 index 000000000..7d4677dd4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoPageReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 插件信息分页 Request VO") +@Data +public class PluginInfoPageReqVO extends PageParam { + + @Schema(description = "插件名称", example = "http") + private String name; + + @Schema(description = "状态") + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java similarity index 96% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java index 6f081764a..af1ee3e14 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; @@ -34,7 +34,7 @@ public class PluginInfoRespVO { @Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("插件包文件名") - private String file; + private String fileName; @Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("插件版本") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java similarity index 94% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java index 8ce254a3a..b35c45abc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; @@ -23,7 +23,7 @@ public class PluginInfoSaveReqVO { private Integer deployType; @Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED) - private String file; + private String fileName; @Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED) private String version; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInstancePageReqVO.java similarity index 94% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInstancePageReqVO.java index 9fccdc0ae..23f885d5a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInstancePageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo; import lombok.*; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInstanceRespVO.java similarity index 95% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInstanceRespVO.java index 92edca821..e92b49f1e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInstanceRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInstanceSaveReqVO.java similarity index 94% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInstanceSaveReqVO.java index 95db299d1..802a7f01f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInstanceSaveReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java deleted file mode 100644 index 321eef9b6..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java +++ /dev/null @@ -1,116 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; - -import jakarta.annotation.Resource; -import org.pf4j.spring.SpringPluginManager; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import javax.annotation.security.PermitAll; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.List; -import java.util.stream.Collectors; - -/** - * 插件 Controller 测试用例 - */ -@RestController -@RequestMapping("/iot/plugins") -public class PluginController { - - @Resource - private SpringPluginManager springPluginManager; - - @Value("${pf4j.pluginsDir}") - private String pluginsDir; - - /** - * 上传插件 JAR 文件并加载插件 - * - * @param file 上传的 JAR 文件 - * @return 上传结果 - */ - @PermitAll - @PostMapping("/upload") - public ResponseEntity uploadPlugin(@RequestParam("file") MultipartFile file) { - if (file.isEmpty()) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("上传的文件为空"); - } - - // 确保插件目录存在 - Path pluginsPath = Paths.get(pluginsDir); - try { - if (!Files.exists(pluginsPath)) { - Files.createDirectories(pluginsPath); - } - - // 保存上传的 JAR 文件到插件目录 - String filename = file.getOriginalFilename(); - if (filename == null || (!filename.endsWith(".jar") && !filename.endsWith(".zip"))) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("上传的文件不是 JAR 或 ZIP 文件"); - } - - Path jarPath = pluginsPath.resolve(filename); - - Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING); - - // 加载插件 - String pluginId = springPluginManager.loadPlugin(jarPath.toAbsolutePath()); - - // 启动插件 - springPluginManager.startPlugin(pluginId); - - return ResponseEntity.ok("插件上传并加载成功"); - } catch (IOException e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("上传插件时发生错误: " + e.getMessage()); - } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("加载插件时发生错误: " + e.getMessage()); - } - } - - /** - * 卸载指定插件 - * - * @param pluginId 插件 ID - * @return 卸载结果 - */ - @PermitAll - @DeleteMapping("/unload/{pluginId}") - public ResponseEntity unloadPlugin(@PathVariable String pluginId) { - if (springPluginManager.getPlugins().stream().noneMatch(plugin -> plugin.getDescriptor().getPluginId().equals(pluginId))) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("插件未加载: " + pluginId); - } - - springPluginManager.stopPlugin(pluginId); - springPluginManager.unloadPlugin(pluginId); - - // 删除插件 JAR 文件(可选) -// PluginWrapper plugin = pluginManager.getPlugin(pluginId); -// PluginDescriptor descriptor = plugin.getDescriptor(); -// Path jarPath = Paths.get(pluginsDir).resolve(descriptor.getPluginId() + ".jar"); -// Files.deleteIfExists(jarPath); - - return ResponseEntity.ok("插件卸载成功: " + pluginId); - } - - /** - * 列出所有已加载的插件 - * - * @return 插件列表 - */ - @PermitAll - @GetMapping("/list") - public ResponseEntity> listPlugins() { - List plugins = springPluginManager.getPlugins().stream() - .map(plugin -> plugin.getDescriptor().getPluginId()) - .collect(Collectors.toList()); - return ResponseEntity.ok(plugins); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java deleted file mode 100644 index a3b36da9d..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java +++ /dev/null @@ -1,59 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginTypeEnum; -import lombok.*; -import io.swagger.v3.oas.annotations.media.Schema; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import org.springframework.format.annotation.DateTimeFormat; -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -// TODO @haohao:只查询必要字段哈 -@Schema(description = "管理后台 - IoT 插件信息分页 Request VO") -@Data -public class PluginInfoPageReqVO extends PageParam { - - @Schema(description = "插件包 ID ", example = "24627") - private String pluginId; - - @Schema(description = "插件名称", example = "赵六") - private String name; - - @Schema(description = "描述", example = "你猜") - private String description; - - @Schema(description = "部署方式", example = "2") - private Integer deployType; - - @Schema(description = "插件包文件名") - private String file; - - @Schema(description = "插件版本") - private String version; - - @Schema(description = "插件类型", example = "2") - @InEnum(IotPluginTypeEnum.class) - private Integer type; - - @Schema(description = "设备插件协议类型") - private String protocol; - - @Schema(description = "状态") - private Integer status; - - @Schema(description = "插件配置项描述信息") - private String configSchema; - - @Schema(description = "插件配置信息") - private String config; - - @Schema(description = "插件脚本") - private String script; - - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java index 043cdb9c8..c503a830f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java @@ -1,6 +1,9 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -27,6 +30,7 @@ public class PluginInfoDO extends BaseDO { @TableId private Long id; // TODO @haohao:这个是不是改成类似 key 之类的字段哈? + // 回复:默认是 pluginId,可以不用改 /** * 插件包 ID */ @@ -41,22 +45,23 @@ public class PluginInfoDO extends BaseDO { private String description; /** * 部署方式 + *

+ * 枚举 {@link IotPluginDeployTypeEnum} */ - // TODO @haohao:枚举 private Integer deployType; /** * 插件包文件名 */ - // TODO @haohao:是不是叫 fileName 哈?避免后续有别的字段,类似 fileUrl? - private String file; + private String fileName; /** * 插件版本 */ private String version; /** * 插件类型 + *

+ * 枚举 {@link IotPluginTypeEnum} */ - // TODO @haohao:枚举 private Integer type; /** * 设备插件协议类型 @@ -64,8 +69,9 @@ public class PluginInfoDO extends BaseDO { private String protocol; /** * 状态 + *

+ * 枚举 {@link IotPluginStatusEnum} */ - // TODO @haohao:枚举 private Integer status; /** * 插件配置项描述信息 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInfoMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInfoMapper.java new file mode 100644 index 000000000..228519fb6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInfoMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.plugin; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.*; + +/** + * IoT 插件信息 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface PluginInfoMapper extends BaseMapperX { + + default PageResult selectPage(PluginInfoPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(PluginInfoDO::getName, reqVO.getName()) + .eqIfPresent(PluginInfoDO::getStatus, reqVO.getStatus()) + .orderByDesc(PluginInfoDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininstance/PluginInstanceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininstance/PluginInstanceMapper.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java index 6c7f1d231..7eee95509 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininstance/PluginInstanceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.plugininstance; +package cn.iocoder.yudao.module.iot.dal.mysql.plugin; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstancePageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; import org.apache.ibatis.annotations.Mapper; -import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.*; /** * IoT 插件实例 Mapper diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininfo/PluginInfoMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininfo/PluginInfoMapper.java deleted file mode 100644 index 69c0bd392..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininfo/PluginInfoMapper.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.plugininfo; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; -import org.apache.ibatis.annotations.Mapper; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.*; - -/** - * IoT 插件信息 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface PluginInfoMapper extends BaseMapperX { - - default PageResult selectPage(PluginInfoPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(PluginInfoDO::getPluginId, reqVO.getPluginId()) - .likeIfPresent(PluginInfoDO::getName, reqVO.getName()) - .eqIfPresent(PluginInfoDO::getDescription, reqVO.getDescription()) - .eqIfPresent(PluginInfoDO::getDeployType, reqVO.getDeployType()) - .eqIfPresent(PluginInfoDO::getFile, reqVO.getFile()) - .eqIfPresent(PluginInfoDO::getVersion, reqVO.getVersion()) - .eqIfPresent(PluginInfoDO::getType, reqVO.getType()) - .eqIfPresent(PluginInfoDO::getProtocol, reqVO.getProtocol()) - .eqIfPresent(PluginInfoDO::getStatus, reqVO.getStatus()) - .eqIfPresent(PluginInfoDO::getConfigSchema, reqVO.getConfigSchema()) - .eqIfPresent(PluginInfoDO::getConfig, reqVO.getConfig()) - .eqIfPresent(PluginInfoDO::getScript, reqVO.getScript()) - .betweenIfPresent(PluginInfoDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(PluginInfoDO::getId)); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java similarity index 87% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java index d023791c8..40ed4a156 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.service.plugininfo; +package cn.iocoder.yudao.module.iot.service.plugin; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import jakarta.validation.Valid; import org.springframework.web.multipart.MultipartFile; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java similarity index 95% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java index 333d0fa98..d9a9eaaff 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.service.plugininfo; +package cn.iocoder.yudao.module.iot.service.plugin; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; -import cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInfoMapper; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -41,7 +41,6 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Resource private PluginInfoMapper pluginInfoMapper; - @Resource private SpringPluginManager pluginManager; @@ -94,12 +93,12 @@ public class PluginInfoServiceImpl implements PluginInfoService { Executors.newSingleThreadExecutor().submit(() -> { try { TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 - File file = new File(pluginsDir, pluginInfoDO.getFile()); + File file = new File(pluginsDir, pluginInfoDO.getFileName()); if (file.exists() && !file.delete()) { - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFile()); + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName()); } } catch (InterruptedException e) { - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFile(), e); + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), e); } }); @@ -213,7 +212,7 @@ public class PluginInfoServiceImpl implements PluginInfoService { private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginIdNew, MultipartFile file) { pluginInfoDo.setPluginId(pluginIdNew); pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); - pluginInfoDo.setFile(file.getOriginalFilename()); + pluginInfoDo.setFileName(file.getOriginalFilename()); pluginInfoDo.setScript(""); PluginDescriptor pluginDescriptor = pluginManager.getPlugin(pluginIdNew).getDescriptor(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java index 0789c4638..97346f9b7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.service.plugininstance; +package cn.iocoder.yudao.module.iot.service.plugin; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstancePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstanceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstancePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstanceSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; import jakarta.validation.Valid; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java similarity index 83% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java index afb05ef2f..7b26948d0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.service.plugininstance; +package cn.iocoder.yudao.module.iot.service.plugin; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstancePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstanceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstancePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstanceSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; -import cn.iocoder.yudao.module.iot.dal.mysql.plugininstance.PluginInstanceMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInstanceMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -13,7 +13,6 @@ import org.springframework.validation.annotation.Validated; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INSTANCE_NOT_EXISTS; -// TODO @haohao:可以搞个 plugin 包,然后把 plugininfo、plugininstance /** * IoT 插件实例 Service 实现类 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml index 2d297c785..007a417ed 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml @@ -1,6 +1,6 @@ - + - CREATE STABLE ${dataBaseName}.${superTableName}( + CREATE STABLE thing_model_message_${superTableName}( ts TIMESTAMP, - id VARCHAR(255), - sys VARCHAR(2048), - method VARCHAR(255), - params VARCHAR(2048) + id NCHAR(64), + sys NCHAR(2048), + method NCHAR(255), + params NCHAR(2048) )TAGS ( - device_key VARCHAR(255) + device_key NCHAR(50) ) - CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} - USING ${dataBaseName}.${superTableName}( + CREATE STABLE ${tableName} + USING thing_model_message_${superTableName}( ts, id , sys , From eaee4642d628ecfb146ac5a1e1826a3c9cbaad6a Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Tue, 31 Dec 2024 17:00:25 +0800 Subject: [PATCH 067/228] =?UTF-8?q?[=E5=8A=9F=E8=83=BD=E6=B7=BB=E5=8A=A0]?= =?UTF-8?q?=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=97=A5=E5=BF=97=E8=A1=A8?= =?UTF-8?q?=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tdengine/ThingModelMessageDO.java | 24 ++++--- .../tdengine/TdThingModelMessageMapper.java | 6 +- .../IotDevicePropertyDataServiceImpl.java | 7 ++ .../product/IotProductServiceImpl.java | 6 +- .../tdengine/IotThingModelMessageService.java | 7 +- .../IotThingModelMessageServiceImpl.java | 64 +++++++++---------- .../mapper/tdengine/TdEngineDMLMapper.xml | 2 +- .../tdengine/TdThinkModelMessageMapper.xml | 12 ++-- 8 files changed, 62 insertions(+), 66 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java index 7dca6edb0..b647c6873 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java @@ -6,6 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; // TODO @芋艿:纠结下字段 +@Deprecated /** * TD 物模型消息日志的数据库 */ @@ -17,26 +18,17 @@ public class ThingModelMessageDO { - // TODO @haohao:superTableName 和 tableName 是不是合并。因为每个 mapper 操作的时候,有且只会使用到其中一个。 - /** - * 超级表名称 - */ - private String superTableName; - - /** - * 表名称 - */ - private String tableName; - /** * 消息 ID */ private String id; /** - * 扩展功能的参数 + * 系统扩展参数 + * + * 例如:设备状态、系统时间、固件版本等系统级信息 */ - private Object sys; + private Object system; /** * 请求方法 @@ -55,6 +47,12 @@ public class ThingModelMessageDO { */ private Long time; + /** + * 设备信息 + */ + private String productKey; + + /** * 设备 key */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java index fc6611931..798d084ac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java @@ -1,11 +1,13 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessageDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; /** * 处理 TD 中物模型消息日志的操作 @@ -20,13 +22,13 @@ public interface TdThingModelMessageMapper { * */ - void createSuperTable(ThingModelMessageDO superTable); + void createSuperTable(@Param("productKey") String productKey); /** * 创建子表 * */ - void createTableWithTag(ThingModelMessageDO table); + void createTableWithTag(@Param("productKey") String productKey,@Param("deviceKey") String deviceKey); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index eb7fcd430..cb7474774 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; +import cn.iocoder.yudao.module.iot.dal.tdengine.TdThingModelMessageMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; @@ -84,6 +85,9 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe @Resource private IotDevicePropertyDataMapper devicePropertyDataMapper; + @Resource + private TdThingModelMessageMapper tdThingModelMessageMapper; + @Override public void defineDevicePropertyData(Long productId) { // 1.1 查询产品和物模型 @@ -108,7 +112,10 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe return; } newFields.add(0, new TDengineTableField(TDengineTableField.FIELD_TS, TDengineTableField.TYPE_TIMESTAMP)); + // 2.1.1 创建产品超级表 devicePropertyDataMapper.createProductPropertySTable(product.getProductKey(), newFields); + // 2.1.2 创建物模型日志超级表 + tdThingModelMessageMapper.createSuperTable(product.getProductKey()); return; } // 2.2 情况二:如果是修改的时候,需要更新表 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index d384e44c0..41537664b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -34,9 +34,6 @@ public class IotProductServiceImpl implements IotProductService { @Resource private IotProductMapper productMapper; - @Resource - @Lazy // 延迟加载,解决循环依赖 - private IotThingModelMessageService thingModelMessageService; @Resource @Lazy // 延迟加载,解决循环依赖 private IotDevicePropertyDataService devicePropertyDataService; @@ -125,8 +122,7 @@ public class IotProductServiceImpl implements IotProductService { if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { // 3.1 创建产品超级表数据模型 devicePropertyDataService.defineDevicePropertyData(id); - // 3.2 创建物模型日志超级表数据模型 TODO 待定:message 要不要分; - thingModelMessageService.createSuperTable(id); + } productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java index ab77eb91a..7f52411d8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java @@ -16,11 +16,6 @@ public interface IotThingModelMessageService { */ void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); - /** - * 创建物模型消息日志超级表 - * - * @param productId 产品编号 - */ - void createSuperTable(Long productId); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 1654c56f5..395d1e91f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -79,7 +79,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); // 1.2 创建物模型日志设备表 - createThingModelMessageDeviceTable(device.getProductKey(), device.getDeviceKey()); + tdThingModelMessageMapper.createTableWithTag(device.getProductKey(), device.getDeviceKey()); } // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 @@ -108,32 +108,34 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); } - @Override - @TenantIgnore - public void createSuperTable(Long productId) { - // 1. 查询产品 - IotProductDO product = productService.getProduct(productId); - - // 2. 获取超级表的名称和数据库名称 - // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 - String databaseName = IotTdDatabaseUtils.getDatabaseName(url); - String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey()); - - // 解析物模型,获取字段列表 - List schemaFields = List.of( - TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(), - TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(), - TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(), - TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(), - TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build() - ); - // 设置超级表的标签 - List tagsFields = List.of( - TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build() - ); - // 3. 创建超级表 - tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); - } +// @Override +// @TenantIgnore +// public void createSuperTable(Long productId) { +// // 1. 查询产品 +// IotProductDO product = productService.getProduct(productId); +// // 2. 创建日志超级表 +// tdThingModelMessageMapper.createSuperTable(product.getProductKey()); +// +// // 2. 获取超级表的名称和数据库名称 +// // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 +//// String databaseName = IotTdDatabaseUtils.getDatabaseName(url); +//// String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey()); +//// +//// // 解析物模型,获取字段列表 +//// List schemaFields = List.of( +//// TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(), +//// TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(), +//// TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(), +//// TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(), +//// TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build() +//// ); +//// // 设置超级表的标签 +//// List tagsFields = List.of( +//// TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build() +//// ); +//// // 3. 创建超级表 +//// tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); +// } private List getValidFunctionList(String productKey) { return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey), @@ -237,13 +239,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ * */ private void createThingModelMessageDeviceTable(String productKey, String deviceKey){ - - - // 2. 创建物模型日志设备数据表 -// tdThingModelMessageMapper.createTableWithTag(ThingModelMessageDO.builder().build() -// .setSuperTableName(productKey) -// .setTableName(deviceKey) -// .setDeviceKey(deviceKey)); + tdThingModelMessageMapper.createTableWithTag(productKey, deviceKey); } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml index 0443a826b..b4084374c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml @@ -42,7 +42,7 @@ + SELECT ts, id, device_key, product_key, type, subType, content, report_time + FROM device_log_${reqVO.deviceKey} + + + AND type = #{reqVO.type} + + + AND subType = #{reqVO.subType} + + + AND ts BETWEEN #{reqVO.createTime[0]} AND #{reqVO.createTime[1]} + + + ORDER BY ts DESC + LIMIT #{reqVO.pageSize} OFFSET #{reqVO.pageNo} + + + + \ No newline at end of file From 603649d2485ec36f30b77ae2a17957fb4bf28100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 6 Jan 2025 18:59:26 +0800 Subject: [PATCH 074/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=96=B0=E5=A2=9E=20MQTT=20RPC=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=EF=BC=8C=E5=8C=85=E5=90=AB=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E5=92=8C=E5=93=8D=E5=BA=94=E6=A8=A1=E5=9E=8B=E3=80=81=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=E5=B7=A5=E5=85=B7=E3=80=81MQTT=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8F=8A=E5=AE=A2=E6=88=B7=E7=AB=AF/=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=E5=AE=9E=E7=8E=B0=EF=BC=8C=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B=E6=9C=8D=E5=8A=A1=E5=92=8C=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=99=A8=E6=8E=A5=E5=8F=A3=EF=BC=8C=E4=BC=98=E5=8C=96=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E7=BB=93=E6=9E=84=E4=BB=A5=E6=94=AF=E6=8C=81=20HTTP?= =?UTF-8?q?=20=E6=8F=92=E4=BB=B6=E7=9A=84=E9=9B=86=E6=88=90=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/mqttrpc/common/RpcRequest.java | 37 ++++++++ .../iot/mqttrpc/common/RpcResponse.java | 32 +++++++ .../mqttrpc/common/SerializationUtils.java | 18 ++++ .../module/iot/mqttrpc/config/MqttConfig.java | 40 ++++++++ .../module/iot/mqttrpc/server/RpcServer.java | 95 +++++++++++++++++++ .../iot/service/plugin/ExampleService.java | 43 +++++++++ .../service/plugin/PluginInfoServiceImpl.java | 1 - .../yudao-module-iot-http-plugin/pom.xml | 5 + .../iot/HttpPluginSpringbootApplication.java | 11 +++ .../module/iot/controller/RpcController.java | 31 ++++++ .../module/iot/mqttrpc/client/RpcClient.java | 95 +++++++++++++++++++ .../module/iot/mqttrpc/config/MqttConfig.java | 41 ++++++++ .../src/main/resources/application.yml | 15 +++ .../yudao-module-iot-mqtt-plugin/pom.xml | 6 +- .../yudao/module/iot/plugin/MqttPlugin.java | 13 +-- 15 files changed, 471 insertions(+), 12 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java new file mode 100644 index 000000000..14e84175c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.mqttrpc.common; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * MQTT RPC 请求 + * + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RpcRequest { + + /** + * 方法名 + */ + private String method; + + /** + * 参数 + */ + private Object[] params; + + /** + * 关联 ID + */ + private String correlationId; + + /** + * 回复地址 + */ + private String replyTo; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java new file mode 100644 index 000000000..675a6ee71 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.iot.mqttrpc.common; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * MQTT RPC 响应 + * + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RpcResponse { + + /** + * 关联 ID + */ + private String correlationId; + + /** + * 结果 + */ + private Object result; + + /** + * 错误 + */ + private String error; +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java new file mode 100644 index 000000000..1529e2dba --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.iot.mqttrpc.common; + +import cn.hutool.json.JSONUtil; + +/** + * 序列化工具类 + * + */ +public class SerializationUtils { + + public static String serialize(Object obj) { + return JSONUtil.toJsonStr(obj); + } + + public static T deserialize(String json, Class clazz) { + return JSONUtil.toBean(json, clazz); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java new file mode 100644 index 000000000..c7a050003 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.iot.mqttrpc.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Data +@Configuration +@ConfigurationProperties(prefix = "mqtt") +public class MqttConfig { + /** + * MQTT 代理地址 + */ + private String broker; + + /** + * MQTT 用户名 + */ + private String username; + + /** + * MQTT 密码 + */ + private String password; + + /** + * MQTT 客户端 ID + */ + private String clientId; + + /** + * MQTT 请求主题 + */ + private String requestTopic; + + /** + * MQTT 响应主题前缀 + */ + private String responseTopicPrefix; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java new file mode 100644 index 000000000..be6ca6f83 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.iot.mqttrpc.server; + +import cn.hutool.core.lang.UUID; +import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest; +import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse; +import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils; +import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.client.mqttv3.*; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.HashMap; +import java.util.Map; + +@Service +@Slf4j +public class RpcServer { + + private final MqttConfig mqttConfig; + private final MqttClient mqttClient; + private final Map methodRegistry = new HashMap<>(); + + public RpcServer(MqttConfig mqttConfig) throws MqttException { + this.mqttConfig = mqttConfig; + this.mqttClient = new MqttClient(mqttConfig.getBroker(), "rpc-server-" + UUID.randomUUID(), new MemoryPersistence()); + MqttConnectOptions options = new MqttConnectOptions(); + options.setAutomaticReconnect(true); + options.setCleanSession(true); + options.setUserName(mqttConfig.getUsername()); + options.setPassword(mqttConfig.getPassword().toCharArray()); + this.mqttClient.connect(options); + } + + @PostConstruct + public void init() throws MqttException { + mqttClient.subscribe(mqttConfig.getRequestTopic(), this::handleRequest); + log.info("RPC Server subscribed to topic: {}", mqttConfig.getRequestTopic()); + } + + private void handleRequest(String topic, MqttMessage message) { + RpcRequest request = SerializationUtils.deserialize(new String(message.getPayload()), RpcRequest.class); + RpcResponse response = new RpcResponse(); + response.setCorrelationId(request.getCorrelationId()); + + try { + MethodInvoker invoker = methodRegistry.get(request.getMethod()); + if (invoker == null) { + throw new NoSuchMethodException("Unknown method: " + request.getMethod()); + } + Object result = invoker.invoke(request.getParams()); + response.setResult(result); + } catch (Exception e) { + response.setError(e.getMessage()); + log.error("Error processing RPC request: {}", e.getMessage(), e); + } + + String replyPayload = SerializationUtils.serialize(response); + MqttMessage replyMessage = new MqttMessage(replyPayload.getBytes()); + replyMessage.setQos(1); + try { + mqttClient.publish(request.getReplyTo(), replyMessage); + log.info("Published response to {}", request.getReplyTo()); + } catch (MqttException e) { + log.error("Failed to publish response: {}", e.getMessage(), e); + } + } + + /** + * 注册可调用的方法 + * + * @param methodName 方法名称 + * @param invoker 方法调用器 + */ + public void registerMethod(String methodName, MethodInvoker invoker) { + methodRegistry.put(methodName, invoker); + log.info("Registered method: {}", methodName); + } + + @PreDestroy + public void cleanup() throws MqttException { + mqttClient.disconnect(); + log.info("RPC Server disconnected"); + } + + /** + * 方法调用器接口 + */ + @FunctionalInterface + public interface MethodInvoker { + Object invoke(Object[] params) throws Exception; + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java new file mode 100644 index 000000000..22ebe8b4f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.iot.service.plugin; + +import cn.iocoder.yudao.module.iot.mqttrpc.server.RpcServer; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; + +@Service +@RequiredArgsConstructor +public class ExampleService { + + private final RpcServer rpcServer; + + @PostConstruct + public void registerMethods() { + rpcServer.registerMethod("add", params -> { + if (params.length != 2) { + throw new IllegalArgumentException("add方法需要两个参数"); + } + int a = ((Number) params[0]).intValue(); + int b = ((Number) params[1]).intValue(); + return add(a, b); + }); + + rpcServer.registerMethod("concat", params -> { + if (params.length != 2) { + throw new IllegalArgumentException("concat方法需要两个参数"); + } + String str1 = params[0].toString(); + String str2 = params[1].toString(); + return concat(str1, str2); + }); + } + + private int add(int a, int b) { + return a + b; + } + + private String concat(String a, String b) { + return a + b; + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java index 7c856447b..77cf590a0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java @@ -18,7 +18,6 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.web.multipart.MultipartFile; -import javax.annotation.PostConstruct; import java.io.File; import java.io.IOException; import java.nio.file.*; diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index 1ecf140a4..27c1d19a0 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -150,5 +150,10 @@ netty-all 4.1.63.Final + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java new file mode 100644 index 000000000..6b553f92b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java @@ -0,0 +1,11 @@ +package cn.iocoder.yudao.module.iot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HttpPluginSpringbootApplication { + public static void main(String[] args) { + SpringApplication.run(HttpPluginSpringbootApplication.class, args); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java new file mode 100644 index 000000000..a5175a786 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java @@ -0,0 +1,31 @@ + +package cn.iocoder.yudao.module.iot.controller; + +import cn.iocoder.yudao.module.iot.mqttrpc.client.RpcClient; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.concurrent.CompletableFuture; + +@RestController +@RequestMapping("/rpc") +@RequiredArgsConstructor +public class RpcController { + + @Resource + private RpcClient rpcClient; + + @PostMapping("/add") + public CompletableFuture add(@RequestParam int a, @RequestParam int b) throws Exception { + return rpcClient.call("add", new Object[]{a, b}, 10); + } + + @PostMapping("/concat") + public CompletableFuture concat(@RequestParam String str1, @RequestParam String str2) throws Exception { + return rpcClient.call("concat", new Object[]{str1, str2}, 10); + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java new file mode 100644 index 000000000..73c1d936c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.iot.mqttrpc.client; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest; +import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse; +import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils; +import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.client.mqttv3.*; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.UUID; +import java.util.concurrent.*; + +@Service +@Slf4j +public class RpcClient { + + private final MqttConfig mqttConfig; + private final MqttClient mqttClient; + private final ConcurrentMap> pendingRequests = new ConcurrentHashMap<>(); + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + public RpcClient(MqttConfig mqttConfig) throws MqttException { + this.mqttConfig = mqttConfig; + this.mqttClient = new MqttClient(mqttConfig.getBroker(), mqttConfig.getClientId(), new MemoryPersistence()); + MqttConnectOptions options = new MqttConnectOptions(); + options.setAutomaticReconnect(true); + options.setCleanSession(true); + options.setUserName(mqttConfig.getUsername()); + options.setPassword(mqttConfig.getPassword().toCharArray()); + this.mqttClient.connect(options); + } + + @PostConstruct + public void init() throws MqttException { + mqttClient.subscribe(mqttConfig.getResponseTopicPrefix() + "#", this::handleResponse); + log.info("RPC Client subscribed to topics: {}", mqttConfig.getResponseTopicPrefix() + "#"); + } + + private void handleResponse(String topic, MqttMessage message) { + String correlationId = topic.substring(mqttConfig.getResponseTopicPrefix().length()); + RpcResponse response = SerializationUtils.deserialize(new String(message.getPayload()), RpcResponse.class); + CompletableFuture future = pendingRequests.remove(correlationId); + if (future != null) { + if (response.getError() != null) { + future.completeExceptionally(new RuntimeException(response.getError())); + } else { + future.complete(response); + } + } else { + log.warn("Received response for unknown correlationId: {}", correlationId); + } + } + + public CompletableFuture call(String method, Object[] params, int timeoutSeconds) throws MqttException { + String correlationId = UUID.randomUUID().toString(); + String replyTo = mqttConfig.getResponseTopicPrefix() + correlationId; + + RpcRequest request = new RpcRequest(method, params, correlationId, replyTo); + String payload = SerializationUtils.serialize(request); + MqttMessage message = new MqttMessage(payload.getBytes()); + message.setQos(1); + mqttClient.publish(mqttConfig.getRequestTopic(), message); + + CompletableFuture futureResponse = new CompletableFuture<>(); + pendingRequests.put(correlationId, futureResponse); + + // 设置超时 + scheduler.schedule(() -> { + CompletableFuture removed = pendingRequests.remove(correlationId); + if (removed != null) { + removed.completeExceptionally(new TimeoutException("RPC call timed out")); + } + }, timeoutSeconds, TimeUnit.SECONDS); + + // 返回最终的结果 + return futureResponse.thenApply(RpcResponse::getResult); + } + + @PreDestroy + public void cleanup() throws MqttException { + mqttClient.disconnect(); + scheduler.shutdown(); + log.info("RPC Client disconnected"); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java new file mode 100644 index 000000000..89569b0c3 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.iot.mqttrpc.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Data +@Configuration +@ConfigurationProperties(prefix = "mqtt") +public class MqttConfig { + + /** + * MQTT 代理地址 + */ + private String broker; + + /** + * MQTT 用户名 + */ + private String username; + + /** + * MQTT 密码 + */ + private String password; + + /** + * MQTT 客户端 ID + */ + private String clientId; + + /** + * MQTT 请求主题 + */ + private String requestTopic; + + /** + * MQTT 响应主题前缀 + */ + private String responseTopicPrefix; +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml new file mode 100644 index 000000000..ea2234f83 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml @@ -0,0 +1,15 @@ +server: + port: 8092 + +spring: + application: + name: yudao-module-iot-http-plugin + +# MQTT-RPC 配置 +mqtt: + broker: tcp://chaojiniu.top:1883 + username: haohao + password: ahh@123456 + clientId: mqtt-rpc-client-${random.int} + requestTopic: rpc/request + responseTopicPrefix: rpc/response/ diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml index d5d48d09a..9607e0f93 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml @@ -145,10 +145,10 @@ ${lombok.version} provided + - io.netty - netty-all - 4.1.63.Final + org.eclipse.paho + org.eclipse.paho.client.mqttv3 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java index 5b50c7124..b3749e402 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java @@ -1,11 +1,12 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginWrapper; import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import javax.annotation.Resource; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -13,11 +14,11 @@ import java.util.concurrent.Executors; public class MqttPlugin extends Plugin { private ExecutorService executorService; + @Resource private DeviceDataApi deviceDataApi; public MqttPlugin(PluginWrapper wrapper) { super(wrapper); - // 初始化线程池 this.executorService = Executors.newSingleThreadExecutor(); } @@ -25,24 +26,20 @@ public class MqttPlugin extends Plugin { public void start() { log.info("MqttPlugin.start()"); - // 重新初始化线程池,确保它是活跃的 if (executorService.isShutdown() || executorService.isTerminated()) { executorService = Executors.newSingleThreadExecutor(); } - // 从 ServiceRegistry 中获取主程序暴露的 DeviceDataApi 接口实例 deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); if (deviceDataApi == null) { log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); return; } + } @Override public void stop() { log.info("MqttPlugin.stop()"); - // 停止线程池 - executorService.shutdownNow(); } - } \ No newline at end of file From b5856c4cfc3a55e89928cb313670210af64a5f7c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 6 Jan 2025 20:24:47 +0800 Subject: [PATCH 075/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=8F=92=E4=BB=B6=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/api/ServiceRegistry.java | 1 + .../module/iot/api/device/DeviceDataApi.java | 3 + .../module/iot/mqttrpc/common/RpcRequest.java | 4 +- .../iot/mqttrpc/common/RpcResponse.java | 3 +- .../mqttrpc/common/SerializationUtils.java | 1 + .../plugin/vo/PluginInfoImportReqVO.java | 2 +- .../admin/plugin/vo/PluginInfoRespVO.java | 17 ----- .../admin/plugin/vo/PluginInfoSaveReqVO.java | 4 + .../mysql/plugin/PluginInstanceMapper.java | 1 + .../iot/job/plugin/PluginInstancesJob.java | 2 +- .../module/iot/mqttrpc/server/RpcServer.java | 5 ++ .../service/plugin/PluginInfoServiceImpl.java | 76 ++++++++++--------- .../plugin/PluginInstanceServiceImpl.java | 29 +++---- .../module/iot/controller/RpcController.java | 1 + .../module/iot/mqttrpc/client/RpcClient.java | 12 ++- 15 files changed, 86 insertions(+), 75 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java index 5603ad8d7..a914e8029 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.api; import java.util.HashMap; import java.util.Map; +// TODO 芋艿:纠结下 /** * 服务注册表 - 插架模块使用,无法使用 Spring 注入 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java index cb747f505..076064db8 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java @@ -2,9 +2,12 @@ package cn.iocoder.yudao.module.iot.api.device; /** * 设备数据 API + * + * @author haohao */ public interface DeviceDataApi { + // TODO @haohao:最好搞成 dto 哈! /** * 保存设备数据 * diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java index 14e84175c..b2a9f0360 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java @@ -5,9 +5,9 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +// TODO @芋艿:要不要加个 mqtt 值了的前缀 /** * MQTT RPC 请求 - * */ @Data @Builder @@ -23,6 +23,7 @@ public class RpcRequest { /** * 参数 */ + // TODO @haohao:object 对象会不会不好序列化? private Object[] params; /** @@ -34,4 +35,5 @@ public class RpcRequest { * 回复地址 */ private String replyTo; + } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java index 675a6ee71..f3225d08e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java @@ -7,7 +7,6 @@ import lombok.NoArgsConstructor; /** * MQTT RPC 响应 - * */ @Data @Builder @@ -23,10 +22,12 @@ public class RpcResponse { /** * 结果 */ + // TODO @haohao:object 对象会不会不好反序列化? private Object result; /** * 错误 */ private String error; + } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java index 1529e2dba..620b00763 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java @@ -15,4 +15,5 @@ public class SerializationUtils { public static T deserialize(String json, Class clazz) { return JSONUtil.toBean(json, clazz); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoImportReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoImportReqVO.java index e71e4c484..bc8d6c8fa 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoImportReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoImportReqVO.java @@ -9,7 +9,7 @@ import org.springframework.web.multipart.MultipartFile; @Data public class PluginInfoImportReqVO { - @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") + @Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") private Long id; @Schema(description = "插件文件", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java index 514ba4f1f..429102469 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java @@ -1,7 +1,5 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -9,63 +7,48 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - IoT 插件信息 Response VO") @Data -@ExcelIgnoreUnannotated public class PluginInfoRespVO { @Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") - @ExcelProperty("主键 ID") private Long id; @Schema(description = "插件包标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") - @ExcelProperty("插件包标识符") private String pluginKey; @Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") - @ExcelProperty("插件名称") private String name; @Schema(description = "描述", example = "你猜") - @ExcelProperty("描述") private String description; @Schema(description = "部署方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @ExcelProperty("部署方式") private Integer deployType; @Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("插件包文件名") private String fileName; @Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("插件版本") private String version; @Schema(description = "插件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @ExcelProperty("插件类型") private Integer type; @Schema(description = "设备插件协议类型") - @ExcelProperty("设备插件协议类型") private String protocol; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("状态") private Integer status; @Schema(description = "插件配置项描述信息") - @ExcelProperty("插件配置项描述信息") private String configSchema; @Schema(description = "插件配置信息") - @ExcelProperty("插件配置信息") private String config; @Schema(description = "插件脚本") - @ExcelProperty("插件脚本") private String script; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") private LocalDateTime createTime; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java index 9a9848130..ad3b31fc1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java @@ -7,6 +7,10 @@ import lombok.*; @Data public class PluginInfoSaveReqVO { + // TODO @haohao:新增的字段有点多,每个都需要哇? + + // TODO @haohao:一些枚举字段,需要加枚举校验。例如说,deployType、status、type 等 + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") private Long id; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java index 249082032..4f773aa06 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java @@ -21,6 +21,7 @@ public interface PluginInstanceMapper extends BaseMapperX { .eq(PluginInstanceDO::getPluginId, pluginId)); } + // TODO @haohao:这个还需要么?相关不用的 VO 可以删除 default PageResult selectPage(PluginInstancePageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(PluginInstanceDO::getMainId, reqVO.getMainId()) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java index ca8398e51..47e7bf560 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.job.plugin; - import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.service.plugin.PluginInstanceService; import org.springframework.scheduling.annotation.Scheduled; @@ -26,4 +25,5 @@ public class PluginInstancesJob { pluginInstanceService.updatePluginInstances(); }); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java index be6ca6f83..90ce2a387 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java @@ -15,6 +15,8 @@ import javax.annotation.PreDestroy; import java.util.HashMap; import java.util.Map; +// TODO @芋艿:server 逻辑,再瞅瞅; +// TODO @haohao:如果只写在 iot biz 里,那么后续 server => client 貌似不方便?微信再讨论下~; @Service @Slf4j public class RpcServer { @@ -90,6 +92,9 @@ public class RpcServer { */ @FunctionalInterface public interface MethodInvoker { + Object invoke(Object[] params) throws Exception; + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java index 77cf590a0..c9030b924 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java @@ -41,18 +41,18 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Resource private PluginInfoMapper pluginInfoMapper; + @Resource private SpringPluginManager pluginManager; + // TODO @芋艿:要不要换位置 @Value("${pf4j.pluginsDir}") private String pluginsDir; @Override public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) { - // 插入 PluginInfoDO pluginInfo = BeanUtils.toBean(createReqVO, PluginInfoDO.class); pluginInfoMapper.insert(pluginInfo); - // 返回 return pluginInfo.getId(); } @@ -67,29 +67,29 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Override public void deletePluginInfo(Long id) { - // 校验存在 + // 1.1 校验存在 PluginInfoDO pluginInfoDO = validatePluginInfoExists(id); - - // 停止插件 + // 1.2 停止插件 if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { throw exception(PLUGIN_INFO_DELETE_FAILED_RUNNING); } - // 卸载插件 + // 2. 卸载插件 + // TODO @haohao:可以复用 stopAndUnloadPlugin PluginWrapper plugin = pluginManager.getPlugin(pluginInfoDO.getPluginKey()); if (plugin != null) { - // 查询插件是否是启动状态 + // 停止插件 if (plugin.getPluginState().equals(PluginState.STARTED)) { - // 停止插件 pluginManager.stopPlugin(plugin.getPluginId()); } // 卸载插件 pluginManager.unloadPlugin(plugin.getPluginId()); } - // 删除 + // 3.1 删除 pluginInfoMapper.deleteById(id); - // 删除插件文件 + // 3.2 删除插件文件 + // TODO @haohao:这个直接主线程 sleep 就好了,不用单独开线程池哈。原因是,低频操作;另外,只有存在的时候,才 sleep + 删除; Executors.newSingleThreadExecutor().submit(() -> { try { TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 @@ -101,7 +101,6 @@ public class PluginInfoServiceImpl implements PluginInfoService { log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), e); } }); - } private PluginInfoDO validatePluginInfoExists(Long id) { @@ -127,22 +126,19 @@ public class PluginInfoServiceImpl implements PluginInfoService { // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // 2. 获取插件标识 - String pluginKey = pluginInfoDo.getPluginKey(); + // 2. 停止并卸载旧的插件 + stopAndUnloadPlugin(pluginInfoDo.getPluginKey()); - // 3. 停止并卸载旧的插件 - stopAndUnloadPlugin(pluginKey); - - // 4. 上传新的插件文件 + // 3.1 上传新的插件文件 String pluginKeyNew = uploadAndLoadNewPlugin(file); - - // 5. 更新插件启用状态文件 + // 3.2 更新插件启用状态文件 updatePluginStatusFile(pluginKeyNew, false); - // 6. 更新插件信息 + // 4. 更新插件信息 updatePluginInfo(pluginInfoDo, pluginKeyNew, file); } + // TODO @haohao:注释的格式 // 停止并卸载旧的插件 private void stopAndUnloadPlugin(String pluginKey) { PluginWrapper plugin = pluginManager.getPlugin(pluginKey); @@ -154,10 +150,13 @@ public class PluginInfoServiceImpl implements PluginInfoService { } } + // TODO @haohao:注释的格式 // 上传并加载新的插件文件 private String uploadAndLoadNewPlugin(MultipartFile file) { + // TODO @haohao:多节点,是不是要上传 s3 之类的存储器;然后定时去加载 Path pluginsPath = Paths.get(pluginsDir); try { + // TODO @haohao:可以使用 FileUtil 简化? if (!Files.exists(pluginsPath)) { Files.createDirectories(pluginsPath); // 创建插件目录 } @@ -166,16 +165,18 @@ public class PluginInfoServiceImpl implements PluginInfoService { Path jarPath = pluginsPath.resolve(filename); Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING); // 保存上传的 JAR 文件 return pluginManager.loadPlugin(jarPath.toAbsolutePath()); // 加载插件 - } else { - throw exception(PLUGIN_INSTALL_FAILED); } + throw exception(PLUGIN_INSTALL_FAILED); // TODO @haohao:这么抛的话,貌似会被 catch (Exception e) { } catch (Exception e) { + // TODO @haohao:打个 error log,方便排查 throw exception(PLUGIN_INSTALL_FAILED); } } + // TODO @haohao:注释的格式 // 更新插件状态文件 private void updatePluginStatusFile(String pluginKeyNew, boolean isEnabled) { + // TODO @haohao:疑问,这里写 enabled.txt 和 disabled.txt 的目的是啥哈? Path enabledFilePath = Paths.get(pluginsDir, "enabled.txt"); Path disabledFilePath = Paths.get(pluginsDir, "disabled.txt"); Path targetFilePath = isEnabled ? enabledFilePath : disabledFilePath; @@ -186,10 +187,8 @@ public class PluginInfoServiceImpl implements PluginInfoService { if (pluginWrapper == null) { throw exception(PLUGIN_INSTALL_FAILED); } - List targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) - : new ArrayList<>(); - List oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) - : new ArrayList<>(); + List targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) : new ArrayList<>(); + List oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) : new ArrayList<>(); if (!targetLines.contains(pluginKeyNew)) { targetLines.add(pluginKeyNew); @@ -207,26 +206,33 @@ public class PluginInfoServiceImpl implements PluginInfoService { } } + // TODO @haohao:注释的格式 // 更新插件信息 private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginKeyNew, MultipartFile file) { + // TODO @haohao:更新实体的时候,最好 new 一个新的! + // TODO @haohao:可以链式调用,简化下代码; pluginInfoDo.setPluginKey(pluginKeyNew); pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); pluginInfoDo.setFileName(file.getOriginalFilename()); pluginInfoDo.setScript(""); - + // 解析 pf4j 插件 PluginDescriptor pluginDescriptor = pluginManager.getPlugin(pluginKeyNew).getDescriptor(); pluginInfoDo.setConfigSchema(pluginDescriptor.getPluginDescription()); pluginInfoDo.setVersion(pluginDescriptor.getVersion()); pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription()); + + // 执行更新 pluginInfoMapper.updateById(pluginInfoDo); } + // TODO @haohao:status、state 字段命名,要统一下~ @Override public void updatePluginStatus(Long id, Integer status) { // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); // 2. 校验插件状态是否有效 + // TODO @haohao:直接参数校验掉。通过 @InEnum if (!IotPluginStatusEnum.contains(status)) { throw exception(PLUGIN_STATUS_INVALID); } @@ -237,17 +243,16 @@ public class PluginInfoServiceImpl implements PluginInfoService { // 4. 根据状态更新插件 if (plugin != null) { - // 4.1 如果目标状态是运行且插件未启动,则启动插件 + // 4.1 启动:如果目标状态是运行且插件未启动,则启动插件 if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) && plugin.getPluginState() != PluginState.STARTED) { pluginManager.startPlugin(pluginKey); - updatePluginStatusFile(pluginKey, true); // 更新插件状态文件为启用 - } - // 4.2 如果目标状态是停止且插件已启动,则停止插件 - else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) + updatePluginStatusFile(pluginKey, true); + // 4.2 停止:如果目标状态是停止且插件已启动,则停止插件 + } else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) && plugin.getPluginState() == PluginState.STARTED) { pluginManager.stopPlugin(pluginKey); - updatePluginStatusFile(pluginKey, false); // 更新插件状态文件为禁用 + updatePluginStatusFile(pluginKey, false); } } else { // 5. 插件不存在且状态为停止,抛出异常 @@ -257,17 +262,20 @@ public class PluginInfoServiceImpl implements PluginInfoService { } // 6. 更新数据库中的插件状态 + // TODO @haohao:新建新建 pluginInfoDo 哈! pluginInfoDo.setStatus(status); pluginInfoMapper.updateById(pluginInfoDo); } @Override public List getPluginInfoList() { - return pluginInfoMapper.selectList(null); + return pluginInfoMapper.selectList(); } + // TODO @haohao:可以改成 getPluginInfoListByStatus 更通用哈。 @Override public List getRunningPluginInfoList() { return pluginInfoMapper.selectListByStatus(IotPluginStatusEnum.RUNNING.getStatus()); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java index 52d79207b..6a65fc026 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java @@ -26,8 +26,9 @@ import java.util.List; public class PluginInstanceServiceImpl implements PluginInstanceService { /** - * 主程序id + * 主程序 ID */ + // TODO @haohao:这个可以后续确认下,有没更合适的标识。例如说 mac 地址之类的 public static final String MAIN_ID = IdUtil.fastSimpleUUID(); @Resource @@ -40,36 +41,37 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { @Value("${server.port:48080}") private int port; + // TODO @haohao:建议把 PluginInfoServiceImpl 里面,和 instance 相关的逻辑拿过来,可能会更好。info 处理信息,instance 处理实例 + // TODO @haohao:这个改成 reportPluginInstance 会不会更合适哈。 @Override public void updatePluginInstances() { - // 1. 查询 pf4j 插件列表 + // 1.1 查询 pf4j 插件列表 List plugins = pluginManager.getPlugins(); - - // 2. 查询插件信息列表 + // 1.2 查询插件信息列表 List pluginInfos = pluginInfoService.getPluginInfoList(); - - // 动态获取主程序的 IP 和端口 + // 1.3 动态获取主程序的 IP 和端口 String mainIp = getLocalIpAddress(); - // 3. 遍历插件列表,并保存为插件实例 + // 2. 遍历插件列表,并保存为插件实例 for (PluginWrapper plugin : plugins) { + // 2.1 查找插件信息 String pluginKey = plugin.getPluginId(); + // TODO @haohao:CollUtil.findOne() 简化 PluginInfoDO pluginInfo = pluginInfos.stream() .filter(pluginInfoDO -> pluginInfoDO.getPluginKey().equals(pluginKey)) .findFirst() .orElse(null); - - // 4. 如果插件信息不存在,则跳过 if (pluginInfo == null) { + // TODO @haohao:建议打个 error log continue; } - // 5. 查询插件实例 + // 2.2 查询插件实例 PluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(MAIN_ID, pluginInfo.getId()); - - // 6. 如果插件实例不存在,则创建 + // 2.3.1 如果插件实例不存在,则创建 if (pluginInstance == null) { + // TODO @haohao:可以链式调用;建议新建一个! pluginInstance = new PluginInstanceDO(); pluginInstance.setPluginId(pluginInfo.getId()); pluginInstance.setMainId(MAIN_ID); @@ -78,13 +80,14 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { pluginInstance.setHeartbeatAt(System.currentTimeMillis()); pluginInstanceMapper.insert(pluginInstance); } else { - // 7. 如果插件实例存在,则更新 + // 2.3.2 如果插件实例存在,则更新 pluginInstance.setHeartbeatAt(System.currentTimeMillis()); pluginInstanceMapper.updateById(pluginInstance); } } } + // TODO @haohao:这个目的是,获取到第一个有效 ip 是哇? private String getLocalIpAddress() { try { List ipList = NetUtil.localIpv4s().stream() diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java index a5175a786..0a9ba9ee4 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java @@ -28,4 +28,5 @@ public class RpcController { public CompletableFuture concat(@RequestParam String str1, @RequestParam String str2) throws Exception { return rpcClient.call("concat", new Object[]{str1, str2}, 10); } + } diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java index 73c1d936c..b73f88c53 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java @@ -1,17 +1,14 @@ package cn.iocoder.yudao.module.iot.mqttrpc.client; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest; import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse; import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils; import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig; import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.client.mqttv3.*; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.springframework.stereotype.Service; @@ -20,6 +17,7 @@ import javax.annotation.PreDestroy; import java.util.UUID; import java.util.concurrent.*; +// TODO @芋艿:需要考虑,怎么公用! @Service @Slf4j public class RpcClient { From cde6ebf92189969ace8739724bc6b9ea925d9e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Tue, 7 Jan 2025 17:44:55 +0800 Subject: [PATCH 076/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=9B=B4=E6=96=B0=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=20API=EF=BC=8C=E9=87=8D=E6=9E=84=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E8=AE=BE=E5=A4=87=E6=95=B0=E6=8D=AE=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E4=BB=A5=E4=BD=BF=E7=94=A8=20DTO=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=A0=A1=E9=AA=8C=E4=BE=9D=E8=B5=96=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8F=92=E4=BB=B6=E7=AE=A1=E7=90=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=8F=92=E4=BB=B6=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E4=B8=8A=E6=8A=A5=E5=92=8C=E7=8A=B6=E6=80=81=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=90=8C=E6=97=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=8F=92=E4=BB=B6=E4=BF=A1=E6=81=AF=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E5=88=A0=E9=99=A4=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=E6=96=87=E4=BB=B6=E5=92=8C=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .vscode/settings.json | 5 + plugins/disabled.txt | 0 plugins/enabled.txt | 1 - ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 8881 -> 16779 bytes yudao-module-iot/yudao-module-iot-api/pom.xml | 7 + .../module/iot/api/device/DeviceDataApi.java | 10 +- .../device/dto/DeviceDataCreateReqDTO.java | 31 +++ .../enums/plugin/IotPluginDeployTypeEnum.java | 4 +- .../iot/api/device/DeviceDataApiImpl.java | 5 +- .../admin/plugin/vo/PluginInfoSaveReqVO.java | 5 +- .../iot/emq/service/EmqxServiceImpl.java | 11 +- .../iot/job/plugin/PluginInstancesJob.java | 2 +- .../device/IotDevicePropertyDataService.java | 8 +- .../IotDevicePropertyDataServiceImpl.java | 17 +- .../iot/service/plugin/PluginInfoService.java | 7 +- .../service/plugin/PluginInfoServiceImpl.java | 204 ++++------------ .../service/plugin/PluginInstanceService.java | 45 +++- .../plugin/PluginInstanceServiceImpl.java | 227 ++++++++++++++---- .../module/iot/controller/RpcController.java | 7 +- .../yudao/module/iot/plugin/HttpHandler.java | 10 +- 21 files changed, 362 insertions(+), 245 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 plugins/disabled.txt delete mode 100644 plugins/enabled.txt create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/DeviceDataCreateReqDTO.java diff --git a/.gitignore b/.gitignore index 09ec36308..49330ee16 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,4 @@ rebel.xml application-my.yaml /yudao-ui-app/unpackage/ +**/.DS_Store diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..b7a0b8667 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "java.compile.nullAnalysis.mode": "automatic", + "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable", + "java.configuration.updateBuildConfiguration": "interactive" +} \ No newline at end of file diff --git a/plugins/disabled.txt b/plugins/disabled.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/plugins/enabled.txt b/plugins/enabled.txt deleted file mode 100644 index 8cf9b4c87..000000000 --- a/plugins/enabled.txt +++ /dev/null @@ -1 +0,0 @@ -http-plugin diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar index 25120abe7f4494bd468cca84c8cea531193ff425..7193d630d82b0166448c05c7550933db82624dac 100644 GIT binary patch delta 11746 zcma)CbyQqS(#PH1-QC^Yo!|rs?oP15-3NDf2p%91+})kP1SeR6B@p;R*z9|6cmMeA zIWt|;r|Q>zt8Uk=sj3F)m=JIjHAP4$1hD68(34g_3561B;CbY}{XGKNz=>Z7b#Uqz z!Uvr3g{TDQfO?hzegfxtA@CstF<)?g1ODra7U+mdN@MQi=Y0_&!NuL()!F=Se9z1LosaREkKqsBFK9~}tN%Z{y^V#V`@h-Ye&4vSzO0t(FFlOm zf`M`ULT3P;k|G0Ibm9H57V)3DCuy2ik;s`Mn6QwevtpPcD5whdse+UtMri`gKELry zMp~Vyag(9|Y1^HOOEX8ewrZ`?&|I8Ma=cvZ zsZ=P*h?TG^T!mv>UvtOSAg^vAmYS+Rnp_29=udX0LC`QnZig#eoApk8J2LzR9Gaqx ztVd12uh?Z8HQa7TGA5Gz_#gqiOO&V3Q z8BPDytd@QU4}GJyo?j-a6((hM`h|antbv8tEE6eU%KTywS-1{wsQ^_PX{*gqznxCJ zGLQrPo4QKcXbFZ6v8Ca%Qt4zeQ}&w?2gfM)rT5Le%N$H_`6N6>PT=JQ24UA5UJtv} zF;YxJ&~GlQkry>IE|7jo?*JcIkKW3&R?c!OuG(wo)uGui&Gr&oL`BBbr-&!=o5t1f zWZR1Zlsd=H&S=&aL(()Hyma=9AW|XHVsyb>e{8emI8?@$gjedGHq(YQ%N`3xT`;9L z$rLo+i$Lof4VPA6s4*A8l&o+L?I_^1T%|ar;>M}6#!dfFPe_Fzkm54KZYT&mZecb` z2;<4@z|mh^n)?!c65~d&Ym8Lr?ntN-lIbo305=VdM!kaTY57mO*0dt@E8Te%PnJuh1KuywPnC=N51y;S_Og`wSSlJ3~c7NIra-m+OL~ zfD${B5uNBnZ>$4tokh>qrCNt~b}`OIV;cz&B5Fi$7wANf&}R`9toTcGDW>YVlvy$p z5q=&@Dv5Q&Aqz+@LSecs%*j$8WR)nqtBPw@8}L}QWg7eT(NIfhR!LN(_w7+awGoYb zP_+pho3w5{zQ8AofZd5*b9IB(SBxP@Hvn()>$*?hZPBy8hy7$}u&jK&GrSzR(w7hx zz`J#~`U-t{$7jqi-W2b63%*H>`y)Cpymx+N_GLgg;+BfM)d+7XxW#U4;m1Sb#M-w0 z2-HLjC4)41RG~HzI*_DLn-Fug{~cU^W|DDfy#enJ>T0!f7A~y$c)hSHy$ZZ=#|gk5 z9Vxa8p={>X3Q?ttc)NLW}28OKWTM4`)GaQV#uosg0O~Z}H-VuG*3s*s(f=Xb~vAxH-U_NJ1`Ou!pGI| zZh8f}oPfPhCyB1UVkiwKSN}UQ3!8R%KOe<*HAOtALDPMU(p!iYowA`U3{=iPhre21 z7Qa@1v9ez^mZI&^Rse|GVWL-Y;NgZY;TtYzLj+vr>?A6z}9TzSGH=i zo#=PF`xr_USF9_ z|LkK27iH?IyO?76p<9uiVk6aB!@;%j2f=7TU=xu}zSLW(GrMFEN@Sp@24%jb7&U52 z?PLlzl8y{G0H5=&!%@lu(62NV!$?z?1|HXSh(-g_<4O?9a0K8ksXdqvzNG5u4 zjZRz5Q+P`4>sTJ7)oT7#GMdI&4=22Zowbi?U;6yfI2d%jLAyOWYTGj){1@f)wy zN9foHh|B*D?+CYI-iBsvDDj-foF=3o*0@;l&W3NY{>N!K7mPpuwS$K zjF*ct`wm0@yDwlA98jM;CrkFlt>AUp)Ay00C(a#dwDycJ9X_5?T>Va=J0py|I5f5> zXBHO0PQkkzx)lLw76e&y?$GBJiQLK)o< zOQD`I+7XRZ?#+P$iIWEfnbds?U<ven#oA73{F0()2WM&yX!%J>!hRi4!FRibKgTN&Xb5JpI-?qqyezp=KGsLHt;fo|?3uW~M zUZ0l#^0r=0DaKm#fxIXyg~XD>aJBBVt21?Wv`Dgy87E+N5XS`5K%6K*6+@c5GYA>N z67H_Q^oxg*>97mR)6x;dcbLq8 zvf=)2DJuV4Xje(nT4MRVS8(Fw_5L^F8%aG=9?efut3b3d&;EQUITG0eTHbslAK(X7 z=%!y^Zh-M`o5m4@ygjQZ>2`E5ttJ9>()g{(RqrSlja6+sgS0%0i_th%Tu7YV+4r|h zuTr;NrsFBC3=?Y>R;#DFLipQq)9w$|4_76oS$xjCs0@^7ysqn0=`80vZrDgx>PhpN zvsD|M(OwG#`U@eT?wFDgC%}-XZby0acXtnZO#|4dE*xadRcjdcXg__M`9MnAhe%RG zC=cBf2|WUo`dVTWFS{kb+#Mry;3zvMuNNQos4y)pCeF-1^NG$EiGOX}^=o8zN%I$% zUD}Im^hW;XV7SLkdHPtc3=S{w%nyO2kNxdm?C#2&9uc3)7G(>b3J;Xym7^vlLwra} zHw>}&O^v^{Mwr7ut_eIhFv^AB=R&+f(15K-vbBuzEg`nfcBCU}E+A_mg#0FmLcoyihWGF)DEN zL$dle@U{R&MVxlUPxsO^HhMVz5yhJ7iU@lO!@VtjgZl5L;RXzI1bJ|y#RP8OAUM%0^rlBM z&0!lpScipz(Oj)GoR3!`N}h4*nS?^>*%o!}QlJF{MGg{0^r##YNs70((plWNrCV4% z!d<4GLP0nCEh9tJjk^x+L}#LWx=1~DW$Hl-iZ?;*w>Nhd1gB(+uG2PHu|3p+2kbB&>lVR=S=*MeXdsS5 z#sq(({TStsaKtl?!5D8o;~D=pQ&{Gd&WnHvXnUwvYZbNS1jC%C#EZ*whrw`zpNMEK z@MCvke>o=eYNqL7-hEYOkW;GJ>Dt*pag$4C83CX6B4SlqAkA^!Vp$ho^atJ!;4 z**I!CyV^KfnK?PRi#t2p+nAfW+c-JC9FZ{fag}v3Ea84i8k!VY`Y>ojDjf2dDcB4O zajF3d=!JrM6K+o!uL@zzI4gyFy&5s5AK-pip!g7}M2elkuFt;H{I}Ov4|k+JUiO0- zz4oE)IQz3Ey6xxy02FKJ)OS4}O3vY#6&?L{$ne#hEwVlc$z+>4CCl)+uYdqLB-Y6p z+~nZ+d_GEh89qx;@XpJp``)pVQ z(k9xBg~01K^PcCmqmJZN4DDHwS4P{^zFjtBnX@X79-VeqfR?c?Y#VY~1^3~jP}4fa zd3L7Tl(h1XN~K+Jx(X>0>X?M5Hr%kyJ*0C#Ir`nuZ3S!?i{P?>G5163N+i`}P4~T7 zAE8~sYx9i-wa0?0w5+x5J|7Dm5i8}^Z{=RZPjQl{e{}qM=pO_n7ltm*xWEpFZ%XbX3J#XfQAW6fiKs-xmFkWPtLo9KtV`_bV^(V#^ktO*c$!EK%Og zH@rt>@XX9cjISY*o9Sc7D(JNfzpBeCmO^7`tx&x`oqNOkWs9uyyA_|vcPdu@8T>(f z5+eT~{QRG8VnSA;$?i?23;0%RzUSZXes&x@oaL1O9I6FjL_vl~B z_Uzi+KE(3*mWQTNUAAm*x4AKsK4W+hKceUHh53vPuh#u(yUJO~&OH8cAQFKeq_f82 z#Z){x+O8M|P@i7qFuY}4uLQciNBErAw8Yj_|4$X$$kjZ&}~&c>J4VLX>Rv24*}8;Vyd<3el#!r_W}f`9&(r?WR@xD z>n|)=_l!j(r0P4$W-2a49`LW#3gzxh2VNr{Q$58Z07_@NF;WyB%^4000pt~F4^EZN z!4LdbuTSYS%$%y7qs=glnacK|I*a>0T#zhv+O%aO(v_B9f#|jp__3#YghGUs&0~r^ zxg|H)plS5#*qC-W?mA{(pFJH!9Wg_W0`?6Do9|pd=Wq!Emtr$M9raPV1w_RtfB0y|SJAkQ zBGOyGzPR~bqQ#$a0ng6Oiy_9Rqrrz`qz<9DwdGB7Fb!L__#95QRuYAMHwsLq_J`Aj zJ7}P*>n5$R3^nIW@RCu2&Bjsmsr{j2Oyp7}0l*K$T%~sbE5R#J*)hH1DTHX?EP|uk z(%?qkvA4o}1_%5gILk;Z`n5z~ycUC-$iNqc-f#zxxqH}=1)7)Rg5Hm&U%8|AJs#1S zf{p&I`nH(*lg4W{+dfYcj=M6QZ)CHyU2k-+VZ2av?0u^@eXbog!3}*^KR}1W&|DZ+K}Ar3z1QyCp*K<#VqH{uj-ykBE5w zDuq8q^nGW|+GxuG;5U>ccz)Zn$(rG)A>ROctii<{zn-EIQ7MylxEegfaT(JOl=T`+ zOr&8p=ouu4gfV?L(k8TKrkLt0g>YZAn3Q7r5YSinbpy#!TS<4QN`!>Jak8ivAd#Ze zs&J0T@=Xo9y@7Sx{lUjF;I<3v7JK7j7<+(6IKjR(>_VSsZpJqJhIH6WD1s-$yea_z z+5P&C$bQqe5G-$634khZ{3n$)ENqPMV zdPP&^|izU=rYMlC(FJbz_5+Yh)#eGSEHD&_P&jM``#&14L!(X2Tjmw`&U^`y0p z!Wfji4f8zEy;I1rNP97yULHC5VgU$nZ_Hty6)3Wxx1o|7v!ygmZa$5R+ZytZwSykA z*yE2KDd-G@$H%xUuE%9NBAtIa##3I%*UkC2X9xKi`inS>#!MZdvS9F?CZJ{@v=w~~CaKg?%Q#F{A~D@tq)uxu>5`9$XhzmuMLKF`{+20V1~6HJLh> zifXn*GaX5egKV@996ls5*qMmc3$mtdUHJTr+;q4hb-+fY28-4+$N1Epmso--ejaPs z)91X4x14u)%J+j8Y%t{1k7QIwFDp;WEnmQs?|DA&{h_86DMY;{*L_liA2c)rf;yF2 zfD+-7g!&{N9Pt-Hn*Mk(^HcqZT0ySmo%%*~oG&$BE3~SSl5Qj)wHo&6BJMb*J>PwV6snVSMKdC=qO- zJSPer4fR_c1q(g#Ict+p-ciTZUlkL44`AvSK)JYvn6AuX5l~c}x=>19RPzU9S)-_DProcPRf{Hx73{EC39z@+4%ksSI|0D-Z*PhpNX6p;yfqP#3yYVnH)l~>&_fZ zcVM-Mq#|gAx-!H}wVeBhjrgbv-q>%xO2xc50MDFzsE?+s`3^DHsk!FjLy4N{ zBD`Tb8t_vJ`qC;Py7&-V7jHhCN;6@fXf{{er;&KlBugKNoN;7?T`-~ra6!&vR3o5d zwT4WNU5=n$#jPG=o-ePb8O`j!dez#s30&HTX=o;RUN{<6%e(ZYw0r@jlXf?$Fb#vg|W^+?dYkRicc%BQei7rq&m#FQq8MB3E|z) z4JMbu9?-&Lqt7a2g> zTA4xrz{)e?8@vP5GGm+g;5X-DF=Z5&jNs_D{>ikYic0Cu3n$A}UiOI1FED{<6=;Y5`>8Bi19cFGxR%5U7-d?t3Kzej16B3CZn5+&z>8-0Tg`#VZ0S> zh)yMN@V+ssvGYah0JBzUU`ttWzt9wjuqxr}E^oCr;+8_=Jh1%2er>E+q%-#z!OVL! z6untP1?49D6`Ls%{=N$(9?$4l#Yyv$oPfhtCCDg;6MC3Ch6{jt_R2XS`WECbC5cJq z;r0HkFr%4^(rl>lZzgPysbhA(P9IdurG&qYJFZHsNm#W#4NI8hpJJhq=yNI=F zT}odWw`Uay@E+m*hV_-7omBIZPefJ-PnA#8ke~Q{=C^kc-|vE>SwV`;DXDBwb?rTy z4mTr(&0HH=3`05>+R(2xFFpJuO>CAHM5XXIlp~1x>g=4xdm(*0pwg_~&Cg3l)qV_f zV!VrwJ_q?ioaCu%tE#Ay!b8>7jg{S{x{c(Y2!UMi0N}=fq!rJZ-1~5x1kMvCQP#Kj zm@*kQnyr0uC^7WtUY3W)BjBtlxW%5)M79^v$IJ zwIJS&(wQwM!<%6h66y=H>` zj#^9-<#1C07TR?~Na;!4e15Es;Bl(BiDLReqaT5V?6weId(OKKIZ<8vR|@9w!=sg@ zQvEDHFe|3n2-*vK#>J8D^ZDQM@SwSt)E|AzY3O%p76RXWR)NW zBt11O3>~@g!=`)JtWEm3zj(y_*ou(<0jjg&Nd^i+Z3e zBsFG!RFJLs$^(3VED`<=-WS!w2vh}6i0m*0B52dqRP6ITz#?c%;x1>H({hABL zp(yte2&`UmL zxoFL2tf?>L%2*R+S2nbC)saOx_*K3uW)}pu<(&H_w^2mhWWl0WDT1o*<>JwpJTbL8 zSc(y>;E%lNam@IQLRN-8y{pGy)|IyKq!y?r=+X^gTS92<4BS76kr)!20YDkoMS@)@ z9g#`inL>^ie*#f;OoLX%CiM)Fsa#HfMrt9c1aO9%f6q{>UI;5nGpUk$qhxJYsG)3t}iAJ{@&pT^QU;W6F^?;)KNl51tH=U&~ zd|w>Y5{-RXH}OjFcmww4O1z!As>iG1i}?!IUC}T{=zHuOE$6XwFH@!|OzJmX#}aI+ zDMdZpC+r;2w3|LK=PIC|b;tHb1=~y_Pz%7u+v|lTXatC`V()^FbO1GXm{A`KB1&O! z>ZqpTJL@jiZOT2;EaxFwh>uhv!tt6|?D@5BvV@L9h4ew3 ztglmM751(^L}od9MgkCg{9R}gJvBdG^kXauN98v;n%|{@3GTc%zw_TJ$=Kl_J}l%C zP{6y@urD zt;nx@Tk5Y24dbsYoU*i*IJ3Np46EDkWE=BK!-j|J?_3+RgN3{48&h{v0E?}glVev( zg94;DTKK)tpsR-?Y0oRd7%VdZd6zR~kZogA=BB13T!r)uh|B~55jrZ446l}AXn1t* zih08j4O%>gav4cbv`O?E`-Hn<>|5kMIYOtn)3(?KN1WWcU>v?hyO!GPvDa0nhf3Jd zidc9Mmnv8=BL;Xf%Fac5fEdyeXxxh9#$HAiqv^a)JTR0PYLgaeZ?6q&nC*p?D}ri5 z0lIfAJK!@;B|o>>wkO57?^>xV1KbIN(WzQeD{#V6Yi&~}%e;;X@(o3)d1|iMbHTo5-KG zWSvi#)xIQ?DdwoBy5tr&B00z#waDp2Nf#TH&iRP_ks=9vEHsDe=wi!3jw4dX=fh1& z|DLD|+RtoxMA_p2i5@)rZ{mvf^YZFve z5N{|$>C&N>efoDNV<&bPKdgLi4y1D$+^rucmydwjI;P+Oyve8T%jgr?aBd4Z09c?9 zTqFKb$V+1qFcX*lrCDhRm;Z%;#CwJQtgCJf_(mcqFtD&+ijoAP;fVq(@t6Q6f}5N* z`}MLaaLsdhe9j@b+ri$1D|_q}1M>Fe^O=?zIUrZoz zA;&b6*gtl{bw3_UU%A|I@kcAt*V$Bs5DrdhcN9UtrPnATEKXh8;~#=vRg0ICHz9;? zA4q@Q*=J=PZYf?{IHcvMWf=-kFOD=Jh6#+UhTI631^0`);om-HZe3?y%j4;wZCYi2 z++Q4LB^*Kjtbmy}#|A#%hK4`+ZekHQWF9N5SF42~->#BX3@XLa{{A+tgoqtnya;15 zY=-@eCzc>7i&?Hp+}XfFN@}}h%w`}oeymfUgT!2R7_Wt2PGtr@OF9|=)Tp&xCWJ+5 zwWdL>glsq{37Og{DHsJVJIp0rJL7(~eD`XsLV=pm4uy*JVvu$OAX9gY8PAB|cpL zO#Gy-+-W|%1!*%mpF_6?DEkO6$YBawC{qiv+PoaL=9k~<6K>{zq+QAJGF{MT?mx`efKu-R_fPC4!^G4nZsYstSxGFho%v$k)a$=~z z_`F|(WvY&Lx(=HH(&Sc1O`Bed(uOi+aHWPc(6VFZyi!7=QQh4L5TDt&r=`lrH%(`0B3SeC@XL)LU&1(C z4!9K+N7L-BndYk305OZOx|P&mB9i@R!0_01)`&^3D}i|$vilgex)@$^-6+P*u$~g!hO~w_HjVkI9RTqBZh|(F{?3cMeVC1gy|bk`qBB4hnS($4b*4 zUb*OMC32rm2e@OP*Pf7b2qwzI4tqtr{!F3TO)T@I1)uB98Rt7Y+j=6yb2{CoDnWHl z_?D4!9rIQG1k$xN@Pl}d=k8RO%)1M);~qk1I=iVM-6qi#sWQe^e40+O9Oi;Kkua-w z`JOrcoKezX;DD-TLaM@Iz3(J3R+AG;gxslir+KSUj>}h7P9=}JR+I0-Z*PbVJ^PK$ z3kh#)Vic{wh`wEJ;J@+ZopQGm7AB4FG@r^L+4FAFSl)ELYi7zGd8M2#9!#2$8pwrv zD`a(_S-w=GR8TDe&)xlmZ1SFClKA~*SLW(TUJ}tyL^XncwMV`bl4f~F)dPOH(WqY^ zh2JhBjsgXMJg$fk!iEMmQ4N;tF+cOpF2j%p7Ibm5SlHQaY zbspSlBTAd|RWL5c3ZvoLM>}8Nkb5gAE2Hu>DsGXVY)$YSG39S)l8V?;F9zFl+_e&l z0H6~Y0l8T_diCL2mY_uydf1&_e5;zNSoU{TPmpS;ir^4fkbm`X0!xWGUph25h(%rq z5)$SYLY0L3g@_~(d?AKOBwpMgGO5f9p+l-j@jtpaf8FxSg$8yit^@&eLM7q-TZvii zZ@c)fw$4AIV9&Bizh$}pWc&Uu_+NdV{}7!2EhzX$@Fj}))yMhI+yA%7FXB1)c)6Yz zCW3t4^k4FS`au84zu5R6ouGfje~l$U7SHnZzZygFUlfHvMgT#N@@tM2Sc?P)G$KQK znRoa#Pk{bwo*Vd)41wZ*)aU;JtAYQ#E$qMP@~?6|@RAgp>{%=SC}I9XJecTNT>bx5 z(fmtSFPr*D8SNjab|lZJivOW&<^QOv{U_c(a=QP(6Q+8`1NC9;Q27T~`ne+fzv805kc-&=D@yt!{mk@i3*gi*12=F0kI9H%430=n0I|gZ zM8_is%8?`ew$~rP=TYe2KhVIQo(MUAF^U1RND;{XE9&?+n z+)#Sf`j%(2hH~3>vdYJG!!*{%6@9E_9Iz7zHXN`fJvj^Z_uOsUo%0<1o%M6I@hTfa zY>sugA&V=7)2v{9KQm8b?4ryGij==}Ll>5Ld}h?ewbW@D^>@?{6jp}|t2(f7Z4u6H zQRoS}S`P4V?F@&~LNFznJ?;zXM(CmQBO7BX&Z8@03QzGGVklDV$Bz2*^>gyiGBv;t zyPT917<9WlI;_=11S2gpndtF2i%+tMF3)Pu%RFC4XJ8&ElD{9)7Wc@9zEpmd113B_ zS8YI##VNIbwhy*bozlHP>g74~C%s$LzGIoXS9 zb>}4zI=4sDs@roBe<<64_6gzoYD`Zyuwv;5)P}yM6=eT#6MvTy-Z5&jo+5NOjBT zn1@}lO7btUdLtb^1deQS>oG^NinkP0khnjX62i9_HDE30W%-&271*r}2#odJe#JR$ z)G-NpE7utElUWf2>2Qr06{0YHI{#_}gha@S%faV+{6ZfXvX0jrN~u2E?i_hbqRpKT z!v3ROwJ=FhlXt_ILJ@JOzEsa3Y>5bABN>^|VCKj@<9#}jfB8JB_)HYmsrA&T4hx7a7m_PCMF8nlfX6#N+|UB@e`cfw3f2UlpmRxie};PZLFWiAr|gj-Bbve-sR z%F`q(Pg7472`n}+ZF(*H0FAnV(SsIZTv7Olf~2vgUbt+Oqug%~i|S%x72CWi?s448$aH8!jqV0L2?QQ36mpRp0M9x@vn;R-5 zP@x^~mk>FuY(fK4keJ42p&e)BLEF1Im%mzj!pc$B0{O=M{bhS%NkGPdhUQs4J2;re z&TUzCTtH5xbzfjZV6i8GHZf@s&$`|$zPUD$n|%u!MW3i8P@$0~w)Mj_)|{p?F5%bO z;%~nv@9`9Z?&7_z(o6}Ip!ZMKL(1h<&U3du6Cl^hs3mK|FC$*g4JlEe>r$p(HOr=y z_)ML5Uzxh6hVto(N@d6BCm~9mZ1V8-vT}=LnOl?ZGb*+}>O;%y zPK}7Odv!4S{pRR$q83D0wdMpP*VQJ<}bm z{pCz{THIn;g=SuK&G!rlLl#B8y`~1goO5w>|9Br4ec`KC#?9qt}qCtx@d++QP#2Q^s7RTbx8EIbbyw8l@;a_o9 zSlV0ir1~hOqc^}IfFua);N!X%<%EC2-TiYy92tUs3M*k}t@enijgS)zHwxUWKE1+! zk*ave6O^NGR)Qj>IrY^VRIN!Ghf*=op-Q1LX#au21%EdSX^-`t-}3J=$MJ~x80J9n zu*tgu;m66TS$%|2Qy#k&Vyn6>K~;yRJKZn#_>NjkQrvk0fLrbAL42JVX@S*;Epwwm zvA+UxxF3D>&)Dt=H6_&z+rl@=aI9Okrk68S-5?+j{Ow*Lw&Q7|r*Cs^0-a6K!yJ4* z;)c2Pea7I&af?=79@iQ^SGgoBj?oIlF%*_>mWfr7>1&-s$c7gMkwBLjKkZ1K7*E8+n zYGtZWO6HpopR(jHi(S_2@dUfi$FP?QF(^r87w?N9-(HF=EAqj`Omc@7&?giyKE8~Z z&bk@|uUte*F4ZIE4HEpTP9F?UoQo6N;o_FFO{G-rGd93XVUE3lMIHGrNI_F)UDAPoxpl@M97wv+9EA; z^A3|)%LHx&%rjP*6iN?+*ii?vSc^HPy^`Wowe{FuJ8lV{?YZaoiXkIAdc!|CJGjY~ zd$0in@+Il#p+RN!E`QZBhZ;g4r<_6SEYcskw}hoT=P&EO@%Qd)Ob?tBNC$@APiThE zfS(ry{m{S-4%`qn9hI4W0pn*PF(DyIG=Ip@{p5+|1OHF@tu`TUns(M-C|hMd!ew4c z_5SAPf@?$mlG=-r9qc@4VLb$j3U zL<;W0{2NOO+LHsZLjJ~qc0XD?XZ*W&yzTkwMM2w`e>Q^k93(>cxVIf80xiUO+a3NP z1i1yAV13X{lgW|v{sMpv0GxpkaIgz>z^B#DU?g-o`!0Sg8J^1?rpc#wBbQRRDPpnP zUg8rlwvuL(M>*xvY1}UZp00F8sr6!`@e{{*2syMA`%Vs+FD~1t#@3c5Ryg>Inu|+8 zF60u=HsUB(id14qN*tY*9`WZjknMoPOt?8%MjjgdPXDy5tQr4nL z6g;+We4@(oL)>1jSDmx$V2ei;Vu_igz>2(+XEoFfhs||W}x;LG(dvziegZzN1qi&QDL)9CZb(SJPj9ntPdqQiH3iDL#8$Lv)FPSg=p^UG^h349R; z3N+?InzWbIR?F7Gwz6-Tx!!#(T3iycI-{S+j!$>H)omn`B22v;u|Zi&#Y}o?%?Eb~ zCg*`I49ksL;#PMj14!n$N=so)UeaAol7zvGsUGe=Quo^QV+cd${c_8m3@DA;a>Umf zJ_3v!DWcaXlak>1TMie{mBvC^{i|>O)4Q^q;AbLKy(Sgx7Cu~v_pm4ZefQh@hXu%D zo>scD3yRW^3?8b^*sW6s`^1?FJU$2{-K=Qi23H&Gh*D1~3v9V;Sb;xMEg9(tx%&Qc z!~BpH(e-;%0MTN9kyZj|%j z45siq77@_lmp!>UW%KJ{dyHdNW5YVgr#lmQSyLFm5k=&Q%{mePX?=0bj=gR?0WlCa zjFES5E)t``b^hFeHfSQa6o}Q1MVNR$e*fDh^Fm03JfJRp4HaFxj-4e9 ziU-ye2mhhWPBPXC&7P~n%J6b~S;8@$$R-D}ckm@;q9;s)E${sCn>Z|E{4uxO8Q_;# zqN<^9GQSa{c0JA;BGRS@zM~=m5qR2o0q^rFAhcE^m%5}GRWr5*dtq)(A(_Xl4IM9g z+>S?1$S|;*i{_7TKgOi&*7{8ms&(jidRESZC6u<2ra!CGppVoI56hQYg7MPk6($4M zZF#o7k7u;@1xflA_kV+fpBQO6W~-B@b{WONPS1-o_2{v)VwT|% z^Aj(_uWwYh4N$|vV#}~e+Q>RyyDKbhbqq{Ga;*RQVZ^!^_)kNOV1!8Do?aFZ-dm6a z5xE6J5Q$p=6qmaN+Tu#L04c7{{J)ME01&>h+kZu2s0Jn?6zd_+&D^(B-wJXMO((N4 z0f0&z06^q#_Vrj8YDsu4;6#{_;3D=V$(e3^x_|{xWDO4h*dqo2!2cpYCH{*{h%k}@ zn%y4C|Azs%R{Rxr0asV?Q~-dcqOL5j>SHB-XA2)27ykbi_W#98c6<=+>m}!Azp)}5il7-rhi`o0D$~I#G7SmQC|}k5x=jAH%t7V?eY(`Ftmp5 enkaX@cYu`I>NwZ;4&b_)y8ztlAD2RZll=$Xda`c- diff --git a/yudao-module-iot/yudao-module-iot-api/pom.xml b/yudao-module-iot/yudao-module-iot-api/pom.xml index d2f83b785..cade52eea 100644 --- a/yudao-module-iot/yudao-module-iot-api/pom.xml +++ b/yudao-module-iot/yudao-module-iot-api/pom.xml @@ -33,6 +33,13 @@ + + + + org.springframework.boot + spring-boot-starter-validation + true + diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java index 076064db8..6eed3592b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.iot.api.device; +import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import jakarta.validation.Valid; + /** * 设备数据 API * @@ -7,14 +10,11 @@ package cn.iocoder.yudao.module.iot.api.device; */ public interface DeviceDataApi { - // TODO @haohao:最好搞成 dto 哈! /** * 保存设备数据 * - * @param productKey 产品 key - * @param deviceName 设备名称 - * @param message 消息 + * @param createDTO 设备数据 */ - void saveDeviceData(String productKey, String deviceName, String message); + void saveDeviceData(@Valid DeviceDataCreateReqDTO createDTO); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/DeviceDataCreateReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/DeviceDataCreateReqDTO.java new file mode 100644 index 000000000..94bc84b80 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/DeviceDataCreateReqDTO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.iot.api.device.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DeviceDataCreateReqDTO { + + /** + * 产品标识 + */ + @NotNull(message = "产品标识不能为空") + private String productKey; + /** + * 设备名称 + */ + @NotNull(message = "设备名称不能为空") + private String deviceName; + /** + * 消息 + */ + @NotNull(message = "消息不能为空") + private String message; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java index 9261e4ae1..263873be7 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java @@ -13,8 +13,8 @@ import java.util.Arrays; @Getter public enum IotPluginDeployTypeEnum implements IntArrayValuable { - UPLOAD(0, "上传 jar"), // TODO @haohao:UPLOAD 和 ALONE 感觉有点冲突,前者是部署方式,后者是运行方式。这个后续再讨论下哈 - ALONE(1, "独立运行"); + DEPLOY_VIA_JAR(0, "通过 jar 部署"), // TODO @haohao:UPLOAD 和 ALONE 感觉有点冲突,前者是部署方式,后者是运行方式。这个后续再讨论下哈 + DEPLOY_STANDALONE(1, "独立部署"); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginDeployTypeEnum::getDeployType).toArray(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java index b4a2a62db..eea7b2a96 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.api.device; +import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -17,8 +18,8 @@ public class DeviceDataApiImpl implements DeviceDataApi { private IotDevicePropertyDataService deviceDataService; @Override - public void saveDeviceData(String productKey, String deviceName, String message) { - deviceDataService.saveDeviceData(productKey, deviceName, message); + public void saveDeviceData(DeviceDataCreateReqDTO createDTO) { + deviceDataService.saveDeviceData(createDTO); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java index ad3b31fc1..25c0f6bcb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; +import lombok.Data; @Schema(description = "管理后台 - IoT 插件信息新增/修改 Request VO") @Data @@ -39,6 +41,7 @@ public class PluginInfoSaveReqVO { private String protocol; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED) + @InEnum(IotPluginStatusEnum.class) private Integer status; @Schema(description = "插件配置项描述信息") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index 2c1553a72..3c21a55ca 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -1,12 +1,12 @@ package cn.iocoder.yudao.module.iot.emq.service; +import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; // TODO @芋艿:在瞅瞅 @@ -16,7 +16,7 @@ import org.springframework.stereotype.Service; * @author ahh */ @Slf4j -//@Service +// @Service public class EmqxServiceImpl implements EmqxService { @Resource @@ -34,7 +34,12 @@ public class EmqxServiceImpl implements EmqxService { String productKey = topic.split("/")[2]; String deviceName = topic.split("/")[3]; String message = new String(mqttMessage.getPayload()); - iotDeviceDataService.saveDeviceData(productKey, deviceName, message); + DeviceDataCreateReqDTO createDTO = DeviceDataCreateReqDTO.builder() + .productKey(productKey) + .deviceName(deviceName) + .message(message) + .build(); + iotDeviceDataService.saveDeviceData(createDTO); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java index 47e7bf560..d32148b47 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java @@ -22,7 +22,7 @@ public class PluginInstancesJob { @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) public void updatePluginInstances() { TenantUtils.executeIgnore(() -> { - pluginInstanceService.updatePluginInstances(); + pluginInstanceService.reportPluginInstances(); }); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java index 08375cb09..a882b5d6c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import jakarta.validation.Valid; @@ -25,12 +26,9 @@ public interface IotDevicePropertyDataService { /** * 保存设备数据 * - * @param productKey 产品 key - * @param deviceName 设备名称 - * @param message 消息 - *

参见 JSON 格式 + * @param createDTO 设备数据 */ - void saveDeviceData(String productKey, String deviceName, String message); + void saveDeviceData(DeviceDataCreateReqDTO createDTO); /** * 获得设备属性最新数据 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index eb7fcd430..b39df3590 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -6,6 +6,7 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -14,8 +15,8 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; -import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; @@ -56,7 +57,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe .put(IotDataSpecsDataTypeEnum.FLOAT.getDataType(), TDengineTableField.TYPE_FLOAT) .put(IotDataSpecsDataTypeEnum.DOUBLE.getDataType(), TDengineTableField.TYPE_DOUBLE) .put(IotDataSpecsDataTypeEnum.ENUM.getDataType(), TDengineTableField.TYPE_TINYINT) // TODO 芋艿:为什么要映射为 TINYINT 的说明? - .put( IotDataSpecsDataTypeEnum.BOOL.getDataType(), TDengineTableField.TYPE_TINYINT) // TODO 芋艿:为什么要映射为 TINYINT 的说明? + .put(IotDataSpecsDataTypeEnum.BOOL.getDataType(), TDengineTableField.TYPE_TINYINT) // TODO 芋艿:为什么要映射为 TINYINT 的说明? .put(IotDataSpecsDataTypeEnum.TEXT.getDataType(), TDengineTableField.TYPE_NCHAR) .put(IotDataSpecsDataTypeEnum.DATE.getDataType(), TDengineTableField.TYPE_TIMESTAMP) .put(IotDataSpecsDataTypeEnum.STRUCT.getDataType(), TDengineTableField.TYPE_NCHAR) // TODO 芋艿:怎么映射!!!! @@ -128,20 +129,20 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe } @Override - public void saveDeviceData(String productKey, String deviceName, String message) { + public void saveDeviceData(DeviceDataCreateReqDTO createDTO) { // 1. 根据产品 key 和设备名称,获得设备信息 - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(productKey, deviceName); + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName()); // 2. 解析消息,保存数据 - JSONObject jsonObject = new JSONObject(message); - log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", productKey, deviceName, jsonObject); + JSONObject jsonObject = new JSONObject(createDTO.getMessage()); + log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject); ThingModelMessage thingModelMessage = ThingModelMessage.builder() .id(jsonObject.getStr("id")) .sys(jsonObject.get("sys")) .method(jsonObject.getStr("method")) .params(jsonObject.get("params")) .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time")) - .productKey(productKey) - .deviceName(deviceName) + .productKey(createDTO.getProductKey()) + .deviceName(createDTO.getDeviceName()) .deviceKey(device.getDeviceKey()) .build(); thingModelMessageService.saveThingModelMessage(device, thingModelMessage); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java index 6a44747a6..2e920e32c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java @@ -78,9 +78,10 @@ public interface PluginInfoService { List getPluginInfoList(); /** - * 获得运行状态的插件信息列表 + * 根据状态获得插件信息列表 * - * @return 运行状态的插件信息列表 + * @param status 状态 + * @return 插件信息列表 */ - List getRunningPluginInfoList(); + List getPluginInfoListByStatus(Integer status); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java index c9030b924..8e1fae88a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java @@ -9,25 +9,16 @@ import cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInfoMapper; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginDescriptor; -import org.pf4j.PluginState; -import org.pf4j.PluginWrapper; import org.pf4j.spring.SpringPluginManager; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.web.multipart.MultipartFile; -import java.io.File; -import java.io.IOException; -import java.nio.file.*; -import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INFO_DELETE_FAILED_RUNNING; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INFO_NOT_EXISTS; /** * IoT 插件信息 Service 实现类 @@ -43,11 +34,10 @@ public class PluginInfoServiceImpl implements PluginInfoService { private PluginInfoMapper pluginInfoMapper; @Resource - private SpringPluginManager pluginManager; + private PluginInstanceService pluginInstanceService; - // TODO @芋艿:要不要换位置 - @Value("${pf4j.pluginsDir}") - private String pluginsDir; + @Resource + private SpringPluginManager pluginManager; @Override public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) { @@ -75,32 +65,13 @@ public class PluginInfoServiceImpl implements PluginInfoService { } // 2. 卸载插件 - // TODO @haohao:可以复用 stopAndUnloadPlugin - PluginWrapper plugin = pluginManager.getPlugin(pluginInfoDO.getPluginKey()); - if (plugin != null) { - // 停止插件 - if (plugin.getPluginState().equals(PluginState.STARTED)) { - pluginManager.stopPlugin(plugin.getPluginId()); - } - // 卸载插件 - pluginManager.unloadPlugin(plugin.getPluginId()); - } + pluginInstanceService.stopAndUnloadPlugin(pluginInfoDO.getPluginKey()); - // 3.1 删除 + // 3. 删除插件文件 + pluginInstanceService.deletePluginFile(pluginInfoDO); + + // 4. 删除插件信息 pluginInfoMapper.deleteById(id); - // 3.2 删除插件文件 - // TODO @haohao:这个直接主线程 sleep 就好了,不用单独开线程池哈。原因是,低频操作;另外,只有存在的时候,才 sleep + 删除; - Executors.newSingleThreadExecutor().submit(() -> { - try { - TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 - File file = new File(pluginsDir, pluginInfoDO.getFileName()); - if (file.exists() && !file.delete()) { - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName()); - } - } catch (InterruptedException e) { - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), e); - } - }); } private PluginInfoDO validatePluginInfoExists(Long id) { @@ -127,144 +98,52 @@ public class PluginInfoServiceImpl implements PluginInfoService { PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); // 2. 停止并卸载旧的插件 - stopAndUnloadPlugin(pluginInfoDo.getPluginKey()); + pluginInstanceService.stopAndUnloadPlugin(pluginInfoDo.getPluginKey()); - // 3.1 上传新的插件文件 - String pluginKeyNew = uploadAndLoadNewPlugin(file); - // 3.2 更新插件启用状态文件 - updatePluginStatusFile(pluginKeyNew, false); + // 3 上传新的插件文件,更新插件启用状态文件 + String pluginKeyNew = pluginInstanceService.uploadAndLoadNewPlugin(file); + pluginInstanceService.updatePluginStatusFile(pluginKeyNew, false); // 4. 更新插件信息 updatePluginInfo(pluginInfoDo, pluginKeyNew, file); } - // TODO @haohao:注释的格式 - // 停止并卸载旧的插件 - private void stopAndUnloadPlugin(String pluginKey) { - PluginWrapper plugin = pluginManager.getPlugin(pluginKey); - if (plugin != null) { - if (plugin.getPluginState().equals(PluginState.STARTED)) { - pluginManager.stopPlugin(pluginKey); // 停止插件 - } - pluginManager.unloadPlugin(pluginKey); // 卸载插件 - } - } - - // TODO @haohao:注释的格式 - // 上传并加载新的插件文件 - private String uploadAndLoadNewPlugin(MultipartFile file) { - // TODO @haohao:多节点,是不是要上传 s3 之类的存储器;然后定时去加载 - Path pluginsPath = Paths.get(pluginsDir); - try { - // TODO @haohao:可以使用 FileUtil 简化? - if (!Files.exists(pluginsPath)) { - Files.createDirectories(pluginsPath); // 创建插件目录 - } - String filename = file.getOriginalFilename(); - if (filename != null) { - Path jarPath = pluginsPath.resolve(filename); - Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING); // 保存上传的 JAR 文件 - return pluginManager.loadPlugin(jarPath.toAbsolutePath()); // 加载插件 - } - throw exception(PLUGIN_INSTALL_FAILED); // TODO @haohao:这么抛的话,貌似会被 catch (Exception e) { - } catch (Exception e) { - // TODO @haohao:打个 error log,方便排查 - throw exception(PLUGIN_INSTALL_FAILED); - } - } - - // TODO @haohao:注释的格式 - // 更新插件状态文件 - private void updatePluginStatusFile(String pluginKeyNew, boolean isEnabled) { - // TODO @haohao:疑问,这里写 enabled.txt 和 disabled.txt 的目的是啥哈? - Path enabledFilePath = Paths.get(pluginsDir, "enabled.txt"); - Path disabledFilePath = Paths.get(pluginsDir, "disabled.txt"); - Path targetFilePath = isEnabled ? enabledFilePath : disabledFilePath; - Path oppositeFilePath = isEnabled ? disabledFilePath : enabledFilePath; - - try { - PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginKeyNew); - if (pluginWrapper == null) { - throw exception(PLUGIN_INSTALL_FAILED); - } - List targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) : new ArrayList<>(); - List oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) : new ArrayList<>(); - - if (!targetLines.contains(pluginKeyNew)) { - targetLines.add(pluginKeyNew); - Files.write(targetFilePath, targetLines, StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING); - } - - if (oppositeLines.contains(pluginKeyNew)) { - oppositeLines.remove(pluginKeyNew); - Files.write(oppositeFilePath, oppositeLines, StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING); - } - } catch (IOException e) { - throw exception(PLUGIN_INSTALL_FAILED); - } - } - - // TODO @haohao:注释的格式 - // 更新插件信息 + /** + * 更新插件信息 + * + * @param pluginInfoDo 插件信息 + * @param pluginKeyNew 插件标识符 + * @param file 文件 + */ private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginKeyNew, MultipartFile file) { - // TODO @haohao:更新实体的时候,最好 new 一个新的! - // TODO @haohao:可以链式调用,简化下代码; - pluginInfoDo.setPluginKey(pluginKeyNew); - pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); - pluginInfoDo.setFileName(file.getOriginalFilename()); - pluginInfoDo.setScript(""); - // 解析 pf4j 插件 - PluginDescriptor pluginDescriptor = pluginManager.getPlugin(pluginKeyNew).getDescriptor(); - pluginInfoDo.setConfigSchema(pluginDescriptor.getPluginDescription()); - pluginInfoDo.setVersion(pluginDescriptor.getVersion()); - pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription()); + // 创建新的插件信息对象并链式设置属性 + PluginInfoDO updatedPluginInfo = new PluginInfoDO() + .setId(pluginInfoDo.getId()) + .setPluginKey(pluginKeyNew) + .setStatus(IotPluginStatusEnum.STOPPED.getStatus()) + .setFileName(file.getOriginalFilename()) + .setScript("") + .setConfigSchema(pluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()) + .setVersion(pluginManager.getPlugin(pluginKeyNew).getDescriptor().getVersion()) + .setDescription(pluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()); // 执行更新 - pluginInfoMapper.updateById(pluginInfoDo); + pluginInfoMapper.updateById(updatedPluginInfo); } - // TODO @haohao:status、state 字段命名,要统一下~ @Override public void updatePluginStatus(Long id, Integer status) { // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // 2. 校验插件状态是否有效 - // TODO @haohao:直接参数校验掉。通过 @InEnum - if (!IotPluginStatusEnum.contains(status)) { - throw exception(PLUGIN_STATUS_INVALID); - } + // 2. 更新插件状态 + pluginInstanceService.updatePluginStatus(pluginInfoDo, status); - // 3. 获取插件标识和插件实例 - String pluginKey = pluginInfoDo.getPluginKey(); - PluginWrapper plugin = pluginManager.getPlugin(pluginKey); - - // 4. 根据状态更新插件 - if (plugin != null) { - // 4.1 启动:如果目标状态是运行且插件未启动,则启动插件 - if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) - && plugin.getPluginState() != PluginState.STARTED) { - pluginManager.startPlugin(pluginKey); - updatePluginStatusFile(pluginKey, true); - // 4.2 停止:如果目标状态是停止且插件已启动,则停止插件 - } else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) - && plugin.getPluginState() == PluginState.STARTED) { - pluginManager.stopPlugin(pluginKey); - updatePluginStatusFile(pluginKey, false); - } - } else { - // 5. 插件不存在且状态为停止,抛出异常 - if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { - throw exception(PLUGIN_STATUS_INVALID); - } - } - - // 6. 更新数据库中的插件状态 - // TODO @haohao:新建新建 pluginInfoDo 哈! - pluginInfoDo.setStatus(status); - pluginInfoMapper.updateById(pluginInfoDo); + // 3. 更新数据库中的插件状态 + PluginInfoDO updatedPluginInfo = new PluginInfoDO(); + updatedPluginInfo.setId(id); + updatedPluginInfo.setStatus(status); + pluginInfoMapper.updateById(updatedPluginInfo); } @Override @@ -272,10 +151,9 @@ public class PluginInfoServiceImpl implements PluginInfoService { return pluginInfoMapper.selectList(); } - // TODO @haohao:可以改成 getPluginInfoListByStatus 更通用哈。 @Override - public List getRunningPluginInfoList() { - return pluginInfoMapper.selectListByStatus(IotPluginStatusEnum.RUNNING.getStatus()); + public List getPluginInfoListByStatus(Integer status) { + return pluginInfoMapper.selectListByStatus(status); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java index 5655f1d3a..cd1d5a654 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.iot.service.plugin; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import org.springframework.web.multipart.MultipartFile; + /** * IoT 插件实例 Service 接口 * @@ -8,8 +11,46 @@ package cn.iocoder.yudao.module.iot.service.plugin; public interface PluginInstanceService { /** - * 更新IoT 插件实例 + * 上报插件实例 */ - void updatePluginInstances(); + void reportPluginInstances(); + + /** + * 停止并卸载插件 + * + * @param pluginKey 插件标识符 + */ + void stopAndUnloadPlugin(String pluginKey); + + /** + * 删除插件文件 + * + * @param pluginInfoDo 插件信息 + */ + void deletePluginFile(PluginInfoDO pluginInfoDo); + + /** + * 上传并加载新的插件文件 + * + * @param file 插件文件 + * @return 插件标识符 + */ + String uploadAndLoadNewPlugin(MultipartFile file); + + /** + * 更新插件状态文件 + * + * @param pluginKeyNew 插件标识符 + * @param isEnabled 是否启用 + */ + void updatePluginStatusFile(String pluginKeyNew, boolean isEnabled); + + /** + * 更新插件状态 + * + * @param pluginInfoDo 插件信息 + * @param status 新状态 + */ + void updatePluginStatus(PluginInfoDO pluginInfoDo, Integer status); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java index 6a65fc026..618d09c73 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java @@ -1,19 +1,38 @@ package cn.iocoder.yudao.module.iot.service.plugin; +import cn.hutool.core.io.FileUtil; import cn.hutool.core.net.NetUtil; import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; +import cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInfoMapper; import cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInstanceMapper; +import cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.pf4j.PluginState; import org.pf4j.PluginWrapper; import org.pf4j.spring.SpringPluginManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import org.springframework.web.multipart.MultipartFile; +import java.io.File; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.nio.file.*; +import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; /** * IoT 插件实例 Service 实现类 @@ -25,79 +44,195 @@ import java.util.List; @Slf4j public class PluginInstanceServiceImpl implements PluginInstanceService { - /** - * 主程序 ID - */ // TODO @haohao:这个可以后续确认下,有没更合适的标识。例如说 mac 地址之类的 + // 简化的UUID + mac 地址 会不会好一些,一台机子有可能会部署多个插件 public static final String MAIN_ID = IdUtil.fastSimpleUUID(); @Resource - private PluginInfoService pluginInfoService; + private PluginInfoMapper pluginInfoMapper; @Resource private PluginInstanceMapper pluginInstanceMapper; @Resource private SpringPluginManager pluginManager; + @Value("${pf4j.pluginsDir}") + private String pluginsDir; + @Value("${server.port:48080}") private int port; - // TODO @haohao:建议把 PluginInfoServiceImpl 里面,和 instance 相关的逻辑拿过来,可能会更好。info 处理信息,instance 处理实例 - - // TODO @haohao:这个改成 reportPluginInstance 会不会更合适哈。 @Override - public void updatePluginInstances() { - // 1.1 查询 pf4j 插件列表 - List plugins = pluginManager.getPlugins(); - // 1.2 查询插件信息列表 - List pluginInfos = pluginInfoService.getPluginInfoList(); - // 1.3 动态获取主程序的 IP 和端口 - String mainIp = getLocalIpAddress(); + public void stopAndUnloadPlugin(String pluginKey) { + PluginWrapper plugin = pluginManager.getPlugin(pluginKey); + if (plugin != null) { + if (plugin.getPluginState().equals(PluginState.STARTED)) { + pluginManager.stopPlugin(pluginKey); // 停止插件 + log.info("已停止插件: {}", pluginKey); + } + pluginManager.unloadPlugin(pluginKey); // 卸载插件 + log.info("已卸载插件: {}", pluginKey); + } else { + log.warn("插件不存在或已卸载: {}", pluginKey); + } + } - // 2. 遍历插件列表,并保存为插件实例 + @Override + public void deletePluginFile(PluginInfoDO pluginInfoDO) { + File file = new File(pluginsDir, pluginInfoDO.getFileName()); + if (file.exists()) { + try { + TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 + if (!file.delete()) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName()); + } + } catch (InterruptedException e) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), + e); + Thread.currentThread().interrupt(); // 恢复中断状态 + } + } + } + + @Override + public String uploadAndLoadNewPlugin(MultipartFile file) { + String pluginKeyNew; + // TODO @haohao:多节点,是不是要上传 s3 之类的存储器;然后定时去加载 + Path pluginsPath = Paths.get(pluginsDir); + try { + FileUtil.mkdir(pluginsPath.toFile()); // 创建插件目录 + String filename = file.getOriginalFilename(); + if (filename != null) { + Path jarPath = pluginsPath.resolve(filename); + Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING); // 保存上传的 JAR 文件 + pluginKeyNew = pluginManager.loadPlugin(jarPath.toAbsolutePath()); // 加载插件 + log.info("已加载插件: {}", pluginKeyNew); + } else { + throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED); + } + } catch (IOException e) { + log.error("[uploadAndLoadNewPlugin][上传插件文件失败]", e); + throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED, e); + } catch (Exception e) { + log.error("[uploadAndLoadNewPlugin][加载插件失败]", e); + throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED, e); + } + return pluginKeyNew; + } + + @Override + public void updatePluginStatusFile(String pluginKeyNew, boolean isEnabled) { + // TODO @haohao:疑问,这里写 enabled.txt 和 disabled.txt 的目的是啥哈? + // pf4j 的插件状态文件,需要 2 个文件,一个 enabled.txt 一个 disabled.txt + Path enabledFilePath = Paths.get(pluginsDir, "enabled.txt"); + Path disabledFilePath = Paths.get(pluginsDir, "disabled.txt"); + Path targetFilePath = isEnabled ? enabledFilePath : disabledFilePath; + Path oppositeFilePath = isEnabled ? disabledFilePath : enabledFilePath; + + try { + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginKeyNew); + if (pluginWrapper == null) { + throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED); + } + List targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) + : new ArrayList<>(); + List oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) + : new ArrayList<>(); + + if (!targetLines.contains(pluginKeyNew)) { + targetLines.add(pluginKeyNew); + Files.write(targetFilePath, targetLines, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + log.info("已添加插件 {} 到 {}", pluginKeyNew, targetFilePath.getFileName()); + } + + if (oppositeLines.contains(pluginKeyNew)) { + oppositeLines.remove(pluginKeyNew); + Files.write(oppositeFilePath, oppositeLines, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + log.info("已从 {} 移除插件 {}", oppositeFilePath.getFileName(), pluginKeyNew); + } + } catch (IOException e) { + log.error("[updatePluginStatusFile][更新插件状态文件失败]", e); + throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED, e); + } + } + + @Override + public void updatePluginStatus(PluginInfoDO pluginInfoDo, Integer status) { + String pluginKey = pluginInfoDo.getPluginKey(); + PluginWrapper plugin = pluginManager.getPlugin(pluginKey); + + if (plugin != null) { + // 启动插件 + if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) + && plugin.getPluginState() != PluginState.STARTED) { + pluginManager.startPlugin(pluginKey); + updatePluginStatusFile(pluginKey, true); + log.info("已启动插件: {}", pluginKey); + } + // 停止插件 + else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) + && plugin.getPluginState() == PluginState.STARTED) { + pluginManager.stopPlugin(pluginKey); + updatePluginStatusFile(pluginKey, false); + log.info("已停止插件: {}", pluginKey); + } + } else { + // 插件不存在且状态为停止,抛出异常 + if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { + throw exception(ErrorCodeConstants.PLUGIN_STATUS_INVALID); + } + } + } + + @Override + public void reportPluginInstances() { + // 1. 获取 pf4j 插件列表 + List plugins = pluginManager.getPlugins(); + + // 2. 获取插件信息列表并转换为 Map 以便快速查找 + List pluginInfos = pluginInfoMapper.selectList(); + Map pluginInfoMap = pluginInfos.stream() + .collect(Collectors.toMap(PluginInfoDO::getPluginKey, Function.identity())); + + // 3. 获取本机 IP 和 MAC 地址 + LinkedHashSet localAddressList = NetUtil.localAddressList(t -> t instanceof Inet4Address); + LinkedHashSet ipList = NetUtil.toIpList(localAddressList); + String ip = ipList.stream().findFirst().orElse("127.0.0.1"); + String mac = NetUtil.getMacAddress(localAddressList.stream().findFirst().orElse(null)); + String mainId = MAIN_ID + "-" + mac; + + // 4. 遍历插件列表,并保存为插件实例 for (PluginWrapper plugin : plugins) { - // 2.1 查找插件信息 String pluginKey = plugin.getPluginId(); - // TODO @haohao:CollUtil.findOne() 简化 - PluginInfoDO pluginInfo = pluginInfos.stream() - .filter(pluginInfoDO -> pluginInfoDO.getPluginKey().equals(pluginKey)) - .findFirst() - .orElse(null); + + // 4.1 查找插件信息 + PluginInfoDO pluginInfo = pluginInfoMap.get(pluginKey); if (pluginInfo == null) { - // TODO @haohao:建议打个 error log + // 4.2 插件信息不存在,记录错误并跳过 + log.error("插件信息不存在,插件包标识符 = {}", pluginKey); continue; } - // 2.2 查询插件实例 - PluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(MAIN_ID, pluginInfo.getId()); - // 2.3.1 如果插件实例不存在,则创建 + // 4.3 查询插件实例 + PluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(mainId, + pluginInfo.getId()); if (pluginInstance == null) { - // TODO @haohao:可以链式调用;建议新建一个! - pluginInstance = new PluginInstanceDO(); - pluginInstance.setPluginId(pluginInfo.getId()); - pluginInstance.setMainId(MAIN_ID); - pluginInstance.setIp(mainIp); - pluginInstance.setPort(port); - pluginInstance.setHeartbeatAt(System.currentTimeMillis()); + // 4.4 如果插件实例不存在,则创建 + pluginInstance = PluginInstanceDO.builder() + .pluginId(pluginInfo.getId()) + .mainId(MAIN_ID + "-" + mac) + .ip(ip) + .port(port) + .heartbeatAt(System.currentTimeMillis()) + .build(); pluginInstanceMapper.insert(pluginInstance); } else { - // 2.3.2 如果插件实例存在,则更新 + // 4.5 如果插件实例存在,则更新心跳时间 pluginInstance.setHeartbeatAt(System.currentTimeMillis()); pluginInstanceMapper.updateById(pluginInstance); } } } - // TODO @haohao:这个目的是,获取到第一个有效 ip 是哇? - private String getLocalIpAddress() { - try { - List ipList = NetUtil.localIpv4s().stream() - .filter(ip -> !ip.startsWith("0.0") && !ip.startsWith("127.") && !ip.startsWith("169.254") && !ip.startsWith("255.255.255.255")) - .toList(); - return ipList.isEmpty() ? "127.0.0.1" : ipList.get(0); - } catch (Exception e) { - log.error("获取本地IP地址失败", e); - return "127.0.0.1"; // 默认值 - } - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java index 0a9ba9ee4..8682a549c 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java @@ -11,6 +11,11 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.concurrent.CompletableFuture; +/** + * 插件实例 RPC 接口 + * + * @author 芋道源码 + */ @RestController @RequestMapping("/rpc") @RequiredArgsConstructor @@ -29,4 +34,4 @@ public class RpcController { return rpcClient.call("concat", new Object[]{str1, str2}, 10); } -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java index 6d0908683..b91146712 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; @@ -12,7 +13,7 @@ import io.netty.util.CharsetUtil; /** * 基于 Netty 的 HTTP 处理器,用于接收设备上报的数据并调用主程序的 DeviceDataApi 接口进行处理。 - * + *

* 1. 请求格式:JSON 格式,地址为 POST /sys/{productKey}/{deviceName}/thing/event/property/post * 2. 返回结果:JSON 格式,包含统一的 code、data、id、message、method、version 字段 */ @@ -76,7 +77,12 @@ public class HttpHandler extends SimpleChannelInboundHandler { try { // 调用主程序的接口保存数据 - deviceDataApi.saveDeviceData(productKey, deviceName, jsonData.toString()); + DeviceDataCreateReqDTO createDTO = DeviceDataCreateReqDTO.builder() + .productKey(productKey) + .deviceName(deviceName) + .message(jsonData.toString()) + .build(); + deviceDataApi.saveDeviceData(createDTO); // 构造成功响应内容 JSONObject successRes = createResponseJson( From 77b89aad773e021b2a7f9d0c85bdbbec468af000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Tue, 7 Jan 2025 23:13:57 +0800 Subject: [PATCH 077/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E9=9B=86=E6=88=90=20Vert.x=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=EF=BC=8C=E9=87=8D=E6=9E=84=20HTTP=20?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E4=B8=BA=20Vert.x=20=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 14 ++ yudao-module-iot/yudao-module-iot-biz/pom.xml | 10 ++ .../plugin/PluginInstanceServiceImpl.java | 6 +- .../dependency-reduced-pom.xml | 81 ++++++++++ .../plugin.properties | 2 +- .../yudao-module-iot-http-plugin/pom.xml | 57 ++++--- .../yudao/module/iot/plugin/HttpHandler.java | 153 ------------------ .../yudao/module/iot/plugin/HttpPlugin.java | 94 ----------- .../module/iot/plugin/HttpVertxHandler.java | 105 ++++++++++++ .../module/iot/plugin/HttpVertxPlugin.java | 70 ++++++++ .../src/main/resources/application-dev.yaml | 7 +- .../src/main/resources/application-local.yaml | 44 +++-- 12 files changed, 355 insertions(+), 288 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/dependency-reduced-pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 6eaa89dfe..fb3cf8562 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -67,6 +67,7 @@ 3.0.6 1.2.5 0.9.0 + 4.4.0 3.5.0 4.11.0 @@ -613,6 +614,19 @@ ${pf4j-spring.version} + + + io.vertx + vertx-core + ${vertx.version} + + + + io.vertx + vertx-web + ${vertx.version} + + diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index d0ed0bcac..66710ae91 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -64,6 +64,16 @@ yudao-spring-boot-starter-excel + + + io.vertx + vertx-core + + + + io.vertx + vertx-web + org.eclipse.paho diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java index 618d09c73..a4bae8964 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java @@ -196,10 +196,8 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { .collect(Collectors.toMap(PluginInfoDO::getPluginKey, Function.identity())); // 3. 获取本机 IP 和 MAC 地址 - LinkedHashSet localAddressList = NetUtil.localAddressList(t -> t instanceof Inet4Address); - LinkedHashSet ipList = NetUtil.toIpList(localAddressList); - String ip = ipList.stream().findFirst().orElse("127.0.0.1"); - String mac = NetUtil.getMacAddress(localAddressList.stream().findFirst().orElse(null)); + String ip = NetUtil.getLocalhostStr(); + String mac = NetUtil.getLocalMacAddress(); String mainId = MAIN_ID + "-" + mac; // 4. 遍历插件列表,并保存为插件实例 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/dependency-reduced-pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/dependency-reduced-pom.xml new file mode 100644 index 000000000..f4ec60d96 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/dependency-reduced-pom.xml @@ -0,0 +1,81 @@ + + + + yudao-module-iot-plugin + cn.iocoder.boot + 2.2.0-snapshot + + 4.0.0 + yudao-module-iot-http-plugin + ${project.artifactId} + 2.2.0-snapshot + 物联网 插件模块 - http 插件 + + + + maven-jar-plugin + 2.4 + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.description} + ${plugin.dependencies} + + + + + + maven-deploy-plugin + + true + + + + maven-shade-plugin + 3.4.1 + + + package + + shade + + + true + shaded + + + cn.iocoder.yudao.module.iot.HttpPluginSpringbootApplication + + + + + + + + + + + org.pf4j + pf4j-spring + 0.9.0 + provided + + + org.projectlombok + lombok + 1.18.34 + provided + + + + cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin + 0.0.1 + http-plugin + http-plugin-0.0.1 + ahh + + diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties index 4e1199acf..44f221cb1 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties @@ -1,5 +1,5 @@ plugin.id=http-plugin -plugin.class=cn.iocoder.yudao.module.iot.plugin.HttpPlugin +plugin.class=cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin plugin.version=0.0.1 plugin.provider=ahh plugin.dependencies= diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index 27c1d19a0..29c0200f1 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -21,7 +21,7 @@ http-plugin - cn.iocoder.yudao.module.iot.plugin.HttpPlugin + cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin 0.0.1 ahh http-plugin-0.0.1 @@ -30,27 +30,6 @@ - - org.apache.maven.plugins maven-antrun-plugin @@ -118,6 +97,29 @@ true + + + + + + + + + + + + + + + + + + + + + + + @@ -145,10 +147,15 @@ ${lombok.version} provided + - io.netty - netty-all - 4.1.63.Final + io.vertx + vertx-core + + + + io.vertx + vertx-web diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java deleted file mode 100644 index b91146712..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java +++ /dev/null @@ -1,153 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.handler.codec.http.*; -import io.netty.util.CharsetUtil; - -/** - * 基于 Netty 的 HTTP 处理器,用于接收设备上报的数据并调用主程序的 DeviceDataApi 接口进行处理。 - *

- * 1. 请求格式:JSON 格式,地址为 POST /sys/{productKey}/{deviceName}/thing/event/property/post - * 2. 返回结果:JSON 格式,包含统一的 code、data、id、message、method、version 字段 - */ -public class HttpHandler extends SimpleChannelInboundHandler { - - private final DeviceDataApi deviceDataApi; - - public HttpHandler(DeviceDataApi deviceDataApi) { - this.deviceDataApi = deviceDataApi; - } - - @Override - protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { - // 期望的路径格式: /sys/{productKey}/{deviceName}/thing/event/property/post - // 使用 "/" 拆分路径 - String uri = request.uri(); - String[] parts = uri.split("/"); - - /* - 拆分结果示例: - parts[0] = "" - parts[1] = "sys" - parts[2] = productKey - parts[3] = deviceName - parts[4] = "thing" - parts[5] = "event" - parts[6] = "property" - parts[7] = "post" - */ - boolean isCorrectPath = parts.length == 8 - && "sys".equals(parts[1]) - && "thing".equals(parts[4]) - && "event".equals(parts[5]) - && "property".equals(parts[6]) - && "post".equals(parts[7]); - if (!isCorrectPath) { - writeResponse(ctx, HttpResponseStatus.NOT_FOUND, "Not Found"); - return; - } - String productKey = parts[2]; - String deviceName = parts[3]; - - // 从请求中获取原始数据,尝试解析请求数据为 JSON 对象 - String requestBody = request.content().toString(CharsetUtil.UTF_8); - JSONObject jsonData; - try { - jsonData = JSONUtil.parseObj(requestBody); - } catch (Exception e) { - JSONObject res = createResponseJson( - 400, - new JSONObject(), - null, - "请求数据不是合法的 JSON 格式: " + e.getMessage(), - "thing.event.property.post", - "1.0" - ); - writeResponse(ctx, HttpResponseStatus.BAD_REQUEST, res.toString()); - return; - } - String id = jsonData.getStr("id", null); - - try { - // 调用主程序的接口保存数据 - DeviceDataCreateReqDTO createDTO = DeviceDataCreateReqDTO.builder() - .productKey(productKey) - .deviceName(deviceName) - .message(jsonData.toString()) - .build(); - deviceDataApi.saveDeviceData(createDTO); - - // 构造成功响应内容 - JSONObject successRes = createResponseJson( - 200, - new JSONObject(), - id, - "success", - "thing.event.property.post", - "1.0" - ); - writeResponse(ctx, HttpResponseStatus.OK, successRes.toString()); - } catch (Exception e) { - JSONObject errorRes = createResponseJson( - 500, - new JSONObject(), - id, - "The format of result is error!", - "thing.event.property.post", - "1.0" - ); - writeResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, errorRes.toString()); - } - } - - /** - * 创建标准化的响应 JSON 对象 - * - * @param code 响应状态码(业务层面的) - * @param data 返回的数据对象(JSON) - * @param id 请求的 id(可选) - * @param message 返回的提示信息 - * @param method 返回的 method 标识 - * @param version 返回的版本号 - * @return 构造好的 JSON 对象 - */ - private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, String version) { - JSONObject res = new JSONObject(); - res.set("code", code); - res.set("data", data != null ? data : new JSONObject()); - res.set("id", id); - res.set("message", message); - res.set("method", method); - res.set("version", version); - return res; - } - - /** - * 向客户端返回 HTTP 响应的辅助方法 - * - * @param ctx 通道上下文 - * @param status HTTP 响应状态码(网络层面的) - * @param content 响应内容(JSON 字符串或其他文本) - */ - private void writeResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String content) { - // 设置响应头为 JSON 类型和正确的编码 - FullHttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, - status, - Unpooled.copiedBuffer(content, CharsetUtil.UTF_8) - ); - response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8"); - response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); - - // 发送响应并在发送完成后关闭连接 - ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java deleted file mode 100644 index 66e0c69a3..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java +++ /dev/null @@ -1,94 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.api.ServiceRegistry; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.*; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.codec.http.*; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginWrapper; -import org.pf4j.Plugin; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -@Slf4j -public class HttpPlugin extends Plugin { - - private static final int PORT = 8092; - - private ExecutorService executorService; - private DeviceDataApi deviceDataApi; - - public HttpPlugin(PluginWrapper wrapper) { - super(wrapper); - // 初始化线程池 - this.executorService = Executors.newSingleThreadExecutor(); - } - - @Override - public void start() { - log.info("HttpPlugin.start()"); - - // 重新初始化线程池,确保它是活跃的 - if (executorService.isShutdown() || executorService.isTerminated()) { - executorService = Executors.newSingleThreadExecutor(); - } - - // 从 ServiceRegistry 中获取主程序暴露的 DeviceDataApi 接口实例 - deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); - if (deviceDataApi == null) { - log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); - return; - } - - // 异步启动 Netty 服务器 - executorService.submit(this::startHttpServer); - } - - @Override - public void stop() { - log.info("HttpPlugin.stop()"); - // 停止线程池 - executorService.shutdownNow(); - } - - /** - * 启动 HTTP 服务 - */ - private void startHttpServer() { - EventLoopGroup bossGroup = new NioEventLoopGroup(1); - EventLoopGroup workerGroup = new NioEventLoopGroup(); - - try { - ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer<>() { - - @Override - protected void initChannel(Channel channel) { - channel.pipeline().addLast(new HttpServerCodec()); - channel.pipeline().addLast(new HttpObjectAggregator(65536)); - // 将从 ServiceRegistry 获取的 deviceDataApi 传入处理器 - channel.pipeline().addLast(new HttpHandler(deviceDataApi)); - } - - }); - - // 绑定端口并启动服务器 - ChannelFuture future = bootstrap.bind(PORT).sync(); - log.info("HTTP 服务器启动成功,端口为: {}", PORT); - future.channel().closeFuture().sync(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - log.warn("HTTP 服务启动被中断", e); - } finally { - bossGroup.shutdownGracefully(); - workerGroup.shutdownGracefully(); - } - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxHandler.java new file mode 100644 index 000000000..335d6c95d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxHandler.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import io.vertx.core.Handler; +import io.vertx.ext.web.RequestBody; +import io.vertx.ext.web.RoutingContext; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HttpVertxHandler implements Handler { + + private final DeviceDataApi deviceDataApi; + + public HttpVertxHandler(DeviceDataApi deviceDataApi) { + this.deviceDataApi = deviceDataApi; + } + + @Override + public void handle(RoutingContext ctx) { + String productKey = ctx.pathParam("productKey"); + String deviceName = ctx.pathParam("deviceName"); + RequestBody requestBody = ctx.body(); + + JSONObject jsonData; + try { + jsonData = JSONUtil.parseObj(requestBody.asJsonObject()); + } catch (Exception e) { + JSONObject res = createResponseJson( + 400, + new JSONObject(), + null, + "请求数据不是合法的 JSON 格式: " + e.getMessage(), + "thing.event.property.post", + "1.0"); + ctx.response() + .setStatusCode(400) + .putHeader("Content-Type", "application/json; charset=UTF-8") + .end(res.toString()); + return; + } + + String id = jsonData.getStr("id", null); + + try { + // 调用主程序的接口保存数据 + DeviceDataCreateReqDTO createDTO = DeviceDataCreateReqDTO.builder() + .productKey(productKey) + .deviceName(deviceName) + .message(jsonData.toString()) + .build(); + deviceDataApi.saveDeviceData(createDTO); + + // 构造成功响应内容 + JSONObject successRes = createResponseJson( + 200, + new JSONObject(), + id, + "success", + "thing.event.property.post", + "1.0"); + ctx.response() + .setStatusCode(200) + .putHeader("Content-Type", "application/json; charset=UTF-8") + .end(successRes.toString()); + } catch (Exception e) { + JSONObject errorRes = createResponseJson( + 500, + new JSONObject(), + id, + "The format of result is error!", + "thing.event.property.post", + "1.0"); + ctx.response() + .setStatusCode(500) + .putHeader("Content-Type", "application/json; charset=UTF-8") + .end(errorRes.toString()); + } + } + + /** + * 创建标准化的响应 JSON 对象 + * + * @param code 响应状态码(业务层面的) + * @param data 返回的数据对象(JSON) + * @param id 请求的 id(可选) + * @param message 返回的提示信息 + * @param method 返回的 method 标识 + * @param version 返回的版本号 + * @return 构造好的 JSON 对象 + */ + private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, + String version) { + JSONObject res = new JSONObject(); + res.set("code", code); + res.set("data", data != null ? data : new JSONObject()); + res.set("id", id); + res.set("message", message); + res.set("method", method); + res.set("version", version); + return res; + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java new file mode 100644 index 000000000..c1d587489 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import io.vertx.core.Vertx; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.handler.BodyHandler; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HttpVertxPlugin extends Plugin { + + private static final int PORT = 8092; + private Vertx vertx; + private DeviceDataApi deviceDataApi; + + public HttpVertxPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + log.info("HttpVertxPlugin.start()"); + + // 获取 DeviceDataApi 实例 + deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); + if (deviceDataApi == null) { + log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); + return; + } + + // 初始化 Vert.x + vertx = Vertx.vertx(); + Router router = Router.router(vertx); + + // 处理 Body + router.route().handler(BodyHandler.create()); + + // 设置路由 + router.post("/sys/:productKey/:deviceName/thing/event/property/post") + .handler(new HttpVertxHandler(deviceDataApi)); + + // 启动 HTTP 服务器 + vertx.createHttpServer() + .requestHandler(router) + .listen(PORT, http -> { + if (http.succeeded()) { + log.info("HTTP 服务器启动成功,端口为: {}", PORT); + } else { + log.error("HTTP 服务器启动失败", http.cause()); + } + }); + } + + @Override + public void stop() { + log.info("HttpVertxPlugin.stop()"); + if (vertx != null) { + vertx.close(ar -> { + if (ar.succeeded()) { + log.info("Vert.x 关闭成功"); + } else { + log.error("Vert.x 关闭失败", ar.cause()); + } + }); + } + } +} \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 5457247e6..c0bd5f64d 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -212,4 +212,9 @@ iot: # 保持连接 keepalive: 60 # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) - clearSession: true \ No newline at end of file + clearSession: true + + +# 插件配置 +pf4j: + pluginsDir: ${user.home}/plugins # 插件目录 \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index e5ae6d195..b6492a1f4 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -45,7 +45,7 @@ spring: primary: master datasource: master: - url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 @@ -53,8 +53,8 @@ spring: # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 - username: root - password: ahh@123456 + username: ruoyi-vue-pro + password: ruoyi-@h2ju02hebp # username: sa # SQL Server 连接的示例 # password: Yudao@2024 # SQL Server 连接的示例 # username: SYSDBA # DM 连接的示例 @@ -63,17 +63,25 @@ spring: # password: Yudao@2024 # OpenGauss 连接的示例 slave: # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: ruoyi-vue-pro + password: ruoyi-@h2ju02hebp + tdengine: # IOT 数据库 +# lazy: true # 开启懒加载,保证启动速度 + url: jdbc:TAOS-RS://chaojiniu.top:6041/ruoyi_vue_pro + driver-class-name: com.taosdata.jdbc.rs.RestfulDriver username: root - password: ahh@123456 + password: taosdata + druid: + validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: redis: - host: 127.0.0.1 # 地址 + host: chaojiniu.top # 地址 port: 6379 # 端口 - database: 0 # 数据库索引 -# password: dev # 密码,建议生产环境开启 + database: 15 # 数据库索引 + password: fsknKD7UvQYZsyf2hXXn # 密码,建议生产环境开启 --- #################### 定时任务相关配置 #################### @@ -175,8 +183,10 @@ logging: cn.iocoder.yudao.module.crm.dal.mysql: debug cn.iocoder.yudao.module.erp.dal.mysql: debug cn.iocoder.yudao.module.iot.dal.mysql: debug + cn.iocoder.yudao.module.iot.dal.tdengine: DEBUG cn.iocoder.yudao.module.ai.dal.mysql: debug org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 + com.taosdata: DEBUG # TDengine 的日志级别 debug: false @@ -259,7 +269,7 @@ justauth: iot: emq: # 账号 - username: anhaohao + username: haohao # 密码 password: ahh@123456 # 主机地址 @@ -271,4 +281,18 @@ iot: # 保持连接 keepalive: 60 # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) - clearSession: true \ No newline at end of file + clearSession: true + +# MQTT-RPC 配置 +mqtt: + broker: tcp://chaojiniu.top:1883 + username: haohao + password: ahh@123456 + clientId: mqtt-rpc-server-${random.int} + requestTopic: rpc/request + responseTopicPrefix: rpc/response/ + + +# 插件配置 +pf4j: + pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录 \ No newline at end of file From d39e2c1bc4127ffc7b4b17cb9b4a080bc2898b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Tue, 7 Jan 2025 23:21:49 +0800 Subject: [PATCH 078/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-local.yaml | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index b6492a1f4..ebfc4faa1 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -45,7 +45,7 @@ spring: primary: master datasource: master: - url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 @@ -53,8 +53,8 @@ spring: # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 - username: ruoyi-vue-pro - password: ruoyi-@h2ju02hebp + username: root + password: 123456 # username: sa # SQL Server 连接的示例 # password: Yudao@2024 # SQL Server 连接的示例 # username: SYSDBA # DM 连接的示例 @@ -63,12 +63,12 @@ spring: # password: Yudao@2024 # OpenGauss 连接的示例 slave: # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true - username: ruoyi-vue-pro - password: ruoyi-@h2ju02hebp + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: root + password: 123456 tdengine: # IOT 数据库 # lazy: true # 开启懒加载,保证启动速度 - url: jdbc:TAOS-RS://chaojiniu.top:6041/ruoyi_vue_pro + url: jdbc:TAOS-RS://127.0.0.1:6041/ruoyi_vue_pro driver-class-name: com.taosdata.jdbc.rs.RestfulDriver username: root password: taosdata @@ -78,10 +78,10 @@ spring: # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: redis: - host: chaojiniu.top # 地址 + host: 400-infra.server.iocoder.cn # 地址 port: 6379 # 端口 - database: 15 # 数据库索引 - password: fsknKD7UvQYZsyf2hXXn # 密码,建议生产环境开启 + database: 1 # 数据库索引 + # password: 123456 # 密码,建议生产环境开启 --- #################### 定时任务相关配置 #################### @@ -269,11 +269,11 @@ justauth: iot: emq: # 账号 - username: haohao + username: root # 密码 - password: ahh@123456 + password: 123456 # 主机地址 - hostUrl: tcp://chaojiniu.top:1883 + hostUrl: tcp://127.0.0.1:1883 # 客户端Id,不能相同,采用随机数 ${random.value} client-id: ${random.int} # 默认主题 @@ -285,9 +285,9 @@ iot: # MQTT-RPC 配置 mqtt: - broker: tcp://chaojiniu.top:1883 - username: haohao - password: ahh@123456 + broker: tcp://127.0.0.1:1883 + username: root + password: 123456 clientId: mqtt-rpc-server-${random.int} requestTopic: rpc/request responseTopicPrefix: rpc/response/ From 0af6d5a7581532b4658160a19680c09ffd427279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 8 Jan 2025 17:59:32 +0800 Subject: [PATCH 079/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=96=B0=E5=A2=9E=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E9=80=BB=E8=BE=91=EF=BC=8C=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86=EF=BC=8C?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=B8=8D=E5=86=8D=E4=BD=BF=E7=94=A8=E7=9A=84?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=96=87=E4=BB=B6=E6=9B=B4=E6=96=B0=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 16779 -> 15105 bytes .../admin/plugin/vo/PluginInfoPageReqVO.java | 5 +- .../iot/framework/plugin/PluginStart.java | 51 ++++++++++++++++++ .../plugin/UnifiedConfiguration.java | 8 ++- .../iot/service/plugin/PluginInfoService.java | 5 +- .../service/plugin/PluginInfoServiceImpl.java | 1 - .../service/plugin/PluginInstanceService.java | 8 --- .../plugin/PluginInstanceServiceImpl.java | 46 +--------------- .../module/iot/plugin/HttpVertxPlugin.java | 16 +++++- 9 files changed, 80 insertions(+), 60 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar index 7193d630d82b0166448c05c7550933db82624dac..fa75769049a1e0036436209788e16c216edd4891 100644 GIT binary patch delta 6325 zcmZu$1z1#DyPlzAkd|(S7`nSlx>Ha_y1T(mNl1tcE!`pAAqYcBhe|7)Er{dM61EH>%j^_|4!IKVl3&vWrh{;<< z{kbe1pzV&%1bK3PZ#4qnT6N zzN`R6&_EjJg}$rxx@%@j8Pz;rKJ5eNyMz(VN{Yraqrd#fx+_~$yo`i`zd`OVdbibo z8Y_l*7(2EKvdB#Y+&@7>cg+`nVfl-hk5K2cv>Dz(MC2VTQp*~B@KnE1EWzD4P4=F2 zlKU^c&Dpz=T&ky7uh?8w0nhjGkId^D+)V0Zy*n^>+>W*jmM_x=w0Lx+kjpwh?;o<| z{sR4HvQIh?ykG{jThIlwqaYB>gMtdMFj`CpVht>g0tz%a6qunYp?rC0@+j*gn%bWr zh6rcHqWP;P&g~6kw+Iz`|J7xOdD+W zLD2|W)@aKqb)BfhSNGO6J~O3zL+k4_%Dz)`1!<=j7*wV7IhgKP*rt!Gznk*)I0sH| zeyIUBCnGnjS3Kb(UQ%%&7@3iCrJ{(^L7Z&)i1ymp;7yBGqEsZ3b`al+8#<8S1ZDtVD9G4ITf4MPoE zHU=KK1;pRxrK#lXLk1cI^V*<}@kMO)319WsW_=(l#qs9z*wIS9ZjD2lu=mfWHodM+ zX)`5{7Knz?A?fN;GE+qH!z2mDCx-L^D%kohwXaoO4I0dmcab zO{S;wbky|eyjBJCY7(7%WeKD)qjSInc^A}@y!&3wC`lMT!&Zi4QROJ9@)l3f3OVdd z@AS|yi1prVw<*%b(GI7KwhsSsVs{V;5*iMfRtw2!2>!MqyEtYrIu^cMp>J<6P^Gi$ z329VupEj_#>=b!TXOZ6+g%L`2fF~*JTb!`5Vdtf<(`5<4u?lo&FJn?tY5^QNsf~RN zv#!kT;FzPG2hN=NxZ_RhQ&f+oPr}*w=Wt~U$#Ve%wER(k@!9Qp49hZOs zX=ubEL?R=3{XsCk<>dg$pgJI3yG}|i8}C55oM}!xKag)oE~Uv7R_)SIpr9Tcv#XTz zbU5Swqaz+qm&?z|#Uz6AY6c1#NDZRG>FZ}d1On}>&Tja9%#f0$pSf%LQ{KZm9}ys2 zN~pDFk_@q(hRI5x4DvzUdkCsY4cw19gQ)}Q%usMH`7&+~HL7Q(=`QnEY zA$eNjX^UX_3;H7ldo%W$Ic7Y$Hw6pFXua~6T9`549d?YN1T@6;3kg(BT^hx-UxxBEhGJ}#=!5`T5kGF!fU1s0e z`fKDeos6}Llj^fh0kBC&H0Fb_X_RSy&}Do3KXeJKrWXW}vMZXj@f z-nH|Uu8qfXW9PCMs5-26zGjPC@YL@2TRPLylb)m>Zy5fn|3I*L5qFIsZQQ4phxqQ3 zyT)DjN!w)hK4%{4Zwri#_dqV+cvrRDQ?78&L61oh+a~CO-*_EtpAO>BXV&Q!00$n3 zFBN~C9Yep`HVI~9$+p&t(*sLv@PBVpyu?VDwKfR}~EFYn`V(mh$bgm6I2E9ru zYW-bW?}fKdWdU#@(+wA2^T%JkudWeav{=&{;r*ccwd#eV?ZzHjj{63&$n$04hQ+iZa}(k~iZl48T)E7Z)I|!y{-yi?OI-|MsmME#HkdJhmpTFkB1F zQmcWa(Hj^edkLc6JN8$%>X2l$Kdpqy1cpS=|ESBaSp;-b_ZCB%zuMq0Erp!h798g_ zCc%FD=MGC<2ql3TRx@{y*k-z;Yr4mC>{Oz}RxJAN<>z;ue=-b!sR`%zKwdIQ90n~e zspH;`Y)(=;yuoDCaQ3N36mM3N@E4=F1}`Q365D5!KbD{a#Zy;ww9rYb3w-r!c9IK< zU~|kXGl1xqt4RJJ;V$bzWslNk4Ou0gGx_!CjT?qx!>^A!Mnv68Yf(+sFEX4qNn0le zM|2%=MyE3j;(n#0-7E8|#DH@JL4EC!tg^QJt#$xy)Kjcx90fRrY(SLZThL;0}~FGSJFUvXKe(mZ=eSurxo>f)AZc zUk=$ykGD#tiJvo9Wtrn&h{o0k=pYkLX)8twzvLdl-?ka%U$;ang>k-frltmBm(d>N zPYP$36n@QBXt--TK7IX}xnh-VDn&9LU(C}Mwxu6_}N{7j@-=={T%?2x0?&WAUE z!&feloXT7RGnppGa{=r!NP0QB@uOEXgq#P#($!RuvKJysKKb^6(nMn`t1eZIl(8spzoxlN?dg zn2mlBB!VUSf=3FN$VlnS*0vH09Y!-C8D^w;{3a_Q2x5G>41wm%x(H4XM&GHzHJ&wQ zsrHr3uvd=nh^CH7YMwQ=$syUm<(WvYJ!~-cdz+E9J@ibE3tp5s(io?3`A}4{6WSsb zXw*#SlG0D}S;zl5e8|_ow##{CvfqiTJLJx{hI#JQ9%WU!YsfQ|@@DuVS#TO)nBtQu zK$}Z>b^4p;Ve&_bgXxmpJ|I{)Y&-V`3u3R*aVuV%k+XMSR*s-G++ak~Rb4)6_ozh4IZZe3(RPDlhH!<;`#L7-1 zdb1hZDEMsbLgGw-JKq?{DH_=18|ggIvL8gqF(3sga@3u`z72SLG>(O-qspsa`)zsE%Y(h<38eEg-oqgBS3uhM0`B*Nh0VQ0ZtgPt)o6*I<(H;V_j|~*xZG{H#UCPXe=DC^-lwHLHN&_Pe&i>U)YWI$%b-XwSg|=XP z9|jp%b5p!XDn>OgJ-&;Ie9hX#n>;I)r7(pU}%@D*qf4HmhtKA{f~RNTKPqpYMU{$&CKzx^34 z9Ch@R@YJ(LQ#qRVT<7pK`?>$SVsF(S`Jhr{c6n^->jU{!-#s>DUNZIJ$Ex9`YAAE9 zlesB&FthWki|U8d4Xko6D(sw^8w>@iYEyzaRUVeL^% zYtJfI;%lb{#y#7)G`)rro*g$v_l;d(AR*)Bw6#>Y%>`Uc6lub5KUlhsVV478LNb!( zWf1vo$>kqR^IxBhukQRd;=;nmy5fqI+`H|K=^5N7!N6 z)Mj;J0%i385l<-7T~*s2>@o7r$-+VJ6T}LMyZ+{HfN|vBg_H{5uMcaYf^$O$nXBJH z%{U~TtCKutO*xY)oGjyn#5GUk=6Y~|Vqh%r)8` z0u(*0@0NVV`en;4XA&;{#XWyS>Xgf<4~nL^vqNyNcf_EQmG$E_>)mV86Av3NBoFs* zG1wrmJx7*70WW2WPj7F`5j9~iil#Qa5Ktn~Ej!jCJ`=sl*WT!4UhPi~Qw$)J5~5L* zed3R0ume-{TbrRgL+89MrVLSAMc@u=R~CM>c+`s{Vx|RX?(|nGfyRpp^OqZp7gc)~ zV^w>U>1Q296l#ZST6`je6Z+A7n*!LU+Ytani2Bzij!gCmaXL_B0kMh0xsy93qTa7Y z56+1nus1TKFpYKaDc`T|VOD7>KaYb_n~IdmuU%pq;X>wzE--wCM#fuI1avn%zd@oa z^kW=$Qh3bNWmYl8$e%jHa5pzu2P3!#b7+;58m_p$KOm_uKVI3SooO@=e@{At^dWDB+L>aFu|7?NyT#rB$WB(5q^}Rx2^O!h#*>}Zb42|cl&tRfZoplu-h3x!Kz_%y+<~jia zlppa*kP8KSf>J187c%=p4#Bw=3a7>Zf#wm3Le>C2nv-cFMq)=7X+V1gLVWSC04@?M zbjel{3E(*vRyTzSp=OhH2DkyPH)>7BI-ozBOyreSr}7rSkvQ6l82-@e17RS^7z zc4I;&Q}qKLy}!Ay#6xp(2h-Qvg^l}7nl!U{9TgrNr&TUH78&`)dnvqcQ7&cnOzgxTDHAWU-pg*CM~A!UG9N z{btebF&z1T?ld`{dv7k-G7cRg$XX;aeVi%X|Pw9m&6$zK?0| zlH00xFRHN<>uc1PE=6cbiuc*1?fdicUJ19d*VwbbUWbKrtL>@B0mk)mAkC>ANS)MG*R`m0J=p7el7?f zcatt0#@AeK3kH-)CcPt@=C7{(RDX=O`cHp#?r;g7*R}=ZTDHZ0h5Wozx5CqSGIN;p zeyFus{my0J;me^s8VA$1{QPr@9VUmVMDHH+s{OjYA&ZP8BhC3T)Ag-Jl9cW12>-T% zAn!NT809eOqN}4=uxsChC;P~xZ+#{pBb17``CCu?Q~P_+4_gVll}+PszZ!@XAti*K zI0Wd&8{mh4W1vT)BilgSv=@s8o2ub2NV{hcOMO5Y) zH&1Hjk-SJ6%Zct@k38|Wo7fLMmDAG%qv4UE|0VAtw#7yMt?wc@Bt%fk=0gcuayBps zWaEB&LII=wm2&Gzk)Q>uA!;S4QDJW+Xwf{uhzN92#FYdD#o$QNq7|SRYJ|Kb1ofk- zbIZI#G4zP1e==FO3?bSr14XR-$?V=TdMJh-kw}G);FtQNmaG&lTKbQSk zH|5s5@Ryeuu_lFw8V$uVqW@8e038>l$8!HC@BdL`Z&&88t2Dw1mB=ake+AnAF7dB( z+F$v%SQ=4-k1B!rM+t2*&)qD1a-r`Dq^n&uyTvPdKd5rRKDK#`(J zdQ&_E5F0nSM-D76Dw*gvG$ngOLs$@iJ*F=oea{`lFsv(F_Sd`&l1sHmB-dEX5&W?5 zad?)g?XCO1M^T66az+scG@6QOP7HMWV*M;@l6 zy^a{KP#~B77?t+=z;K~DZyZ?6J1;M&3;M=J!#~crq8k>mrx;VIxMy}|lo@9d|9eKA z`F)ozb)-4(XRb^G@}2Xv)#b6h+@-suFADY$_kiZ?>o}halc}AFi%YW(ybsna?qlaD zRpTNODMJ_o7II`p6hjypMcy7ofFfv+%Ky!_nR_DA;z*T?1lg9R?TM%)V`NK<#`2Up ziW@NB%HDRiWp1sd0Nif|gdr;-`K-d{Q)rZ`8jhJH-qFLS;n@Gi zAXICYPM?*rEzBNm-&(SFQ*p{4D^gZZxonh8qq=k|%o>SdrynVc)VL&^#DWzo3$8!j zzR#3ylCSf?jI1}cl>DCPjU7rx*7tO>F)>o>6pF+*RNdbvHT2rJXd5(jebP}aF~Q`O zspr0F()#8ilMKXTrsuuLf;BjEd8m>|Ypo7?A816&{n^kjRh3c(i!ihaEez%riboR} zGR+3;9U@%k-Zyd2voXNs5^)(i0!#DsL#|dl?sq7oBpCW&%)V73&#I}NBmI)xgxoV9 zddV`EPjbpH+G*z0pjk6ab`hFKgoC5%l0@TqO=7CJGVO#F+J{e1sg`DgQq=4{wD$@? z$)J=d9ia1%4VEnX^4Ox#a-EYV>Yyg+BmRhUhSWx>yoR4bFxrRx#bp>Oj0Lbo3+#QH za<7`dCpji#$0#$$jQ>!LO9tUdaJ+e0pXYzn%xD-F!j<0kN^f><>NxUilnWSd#|SCk z)d62ADBV>GXcAgZPUDtoPU%qIMwOTD%E44XtT=FC$~hNlwVQBsrdmbS%TY{3DKbb) zRzOHd;o3P<8oz2js8_1j(ZtRu+c>~DE>CZrajU27%u}y+8Z7HYCpP5ebnAp0vi{`) zW`&(QvK4e@4mS`=7Sp;%hXKys>?`O)ddHLgZJB?t$d+h8J2KuAYhP1)*1ct}+P>B{ z%E@qOB@QH{Lf|z+BYcQHi702uTckraR>z^plpc@p>p)yVq!SLAPka^{(`9B#nsPs* zNUpXbrb(s8ZPA8d=<<_+hQOqPuuzxRVO*slm1{tyF&vAeP8}}ax;fZyXJp4zRlh}x zJ_zaBlk}=){muqG^Dg8UQ@us`>&^c8@P#jNA%5Izw~Jcn^PBI63}Q`ij@IBCRX9JP zbHjV)hG%~B3q@R0lC>P*E(V(KMCX4xAdIhW?G8hY$57Bukwq0~6{6V^7ibk=tn|Hw z>rPKFDz4M#{y|x(a>fMaz?zQL4XMyA!wGd5*`*UjE20Ox0`9kPDLO&H73*Litpz<}(uE}!XDmuLg#=~X zk+;N3RNQ5(Xuh*%a$oZl2NJGxBI>*{G@nA zdoX+(>Hk9VxXUOsoqBG@ol%KTWuQY+H?C5yX^Gd;3a?t)NOjp$zHCs=yd;p{sBohn zYGGXeC@gCux9ocKRk$sqpfy)0j3m>HD5b{rmn0n{h+H>l(SI05v*!eM!hxDen~SVqHn>Qr-E&Ud2$7rdw+sIA)W9R>_`= z6Q+o#zmy&ka;+;`J%3;9=R>%TcCJXosI2t)3{Q>QK{$jO934|RJvpjQma`W*sBFk- zFyGEL^;xkwm^)}4{hOhHyge&rdD+ZM^;TX*%T}9_ZkO9n{>0(8q<#|B<2^riG@=ZP zCBK@sEXu?4tn#or%o{rDx8%p43wJ5Q2rzG1-g?3AF?s56mM8CtCL3ZpSd*K^uFu8w z=GlBhyjS}i1t#+gd98ju8Z9Llj};SJXUoXfWnEUDYTuog!rYV?RCWP>ujJ*jhWVh? zb9Rm~j&oY6)qoPi@pV1jWH%T+Ni5Z5F}QMhVKR05oh@91iL=gZlEuePc~-KOWGgj$ z=Y}76gL(dq1lqY0UJ|FaiCZY){=#bHxfUXns7ckMN#K`A+EPF;F8ghpgM?eR!dMhN zRZRvYJK=PLIEVE1e6i%(D$(|gUa2H=^JmY+wAy{It1>v#0lz`5mJb2{%B>)4SXO$r z%^^L7wAau)1LAW2TKFOC5z#YyoZgXT1ph-~1@eKfoLbB&oI3Mhii3)BtBWfM70|GN zN#4as2R#4t*mE!41nG?#OHC25Q^2q%SE4{FvUiC_Q^j3yOyy!I2TJ^>1Kv`-ht+Zr zGvNwXlgoJh$$J#RrtMvCN2Z-o@y&@E^8VNrE!6=U7ChM-DMbY~#hjWwGdp>hlwPOP z;2NenyCGn@=-^iaIM0vVzVu81U2P8e7yD z*urm{z;(5Yw{`_3(t6U#@*kkCB$ClN7rY0gG3rFewEFL@BU+Of2I8cA z`OJp*HU+a+K77xn;2rH`IVe5oT^HT4IC(R9cu_Q~E?#+dq|1b)gGlBDec$RG>2+wS6HHwBaaw~?oJ5`-y0ZbapG!1*3wQ2cP`R9$VX+E#;1$R@a3ve7(VysMU+%q8rT+N zz8Xo~mc)u$@>wHgoAv+=_rgLnwuQGuPOhwbYbM{5H{OoNl3N9 z5#iR|+1cwc&O&i+FKwz^MZZhEemU`xnD`4KQ5C){Ok+6A07T-V$U0VfO?JLBN?_kX zdP-I|HsnEWTv9}ok#}O9#v6%uY1sK9ytAn3`0Wn$c_w-TZ&M)L!>TN8G)Een2QdAk zKk-BNhhy8@(#8kG$C6p;yvKazeZ^SCh*9yNcf`dj274w(7mFME{~Uzjo?Z#4_3|!_ zW^+IQKs5{i!1?dFRmIND(%ON7^{<0#wuY@TrYM%6IHLS=uNIbMQkaVQG6G^5%`4Vm z=`vawH7G7WJa_7oc=Pv**@?#Y8?V{AIIOLG*8P(BSz@nKBB_qAHKDTG5!SE$XK$9|Y;fJsGEB76wAbAIo|B#aG5 zCS^e%U@K!IbJ!Yd6!=hw1ii{>WQyW}E4nm*)eYiaR`o*Wh7axjGFN8HKQiwWMdE>> zVeh4Q1qEhkq(ijV(tq$QAICm;+0^{@u3y1g-lRxONQoI3Y6zDT5A-^1zVK|;nQ z)ZKxjswu(`B+5K-iDFb2#kS2dzBbsL#N*ZnxPb2%l#ZBV;5CORy0X53dD--#+4oH! zUwr~eCX>J=N_r9DUv&`fbr$o-elMC!FMD@Qb#+LDIf4p@A$LKoM#Le8+M2H07)x$S zY4o?hmF8=3F1l+b$PL3n;@_n35ml!)uRjL=Czu1Nb75sSrtK1~vRSx1=aN(1*$!%eXJ zvLw43(YmmK{NjR7E9Wgk8J;fN0@Xt-nVuHZA{{jFwM+E@b|7TPGy`{D9USsX! zK7KNQ8ios$4rGml9c_@4Dx}hkrX?deaSoK zhovRiX0{+F$w#_l-T z){1+zk?chyk{`Uw7O66#g3f|9ij*emK??g;x?Zoyf>liwR{C zb?=q#e^l$EtFjoF8ATJXH%%>LLfYmOCvA{n%AveP>P#(Yu~|I5@Tux@!I&HJB>IYz zGTt!|UyMsg)lKIihG)nr7CGKBpk=n_lk_GiIEKwg1Xp}<8g67`s^HUD8XA^z$fu-nvQK5l1%=)l^c+fXMk*L#L(x)O;M@eCvtlcWV_-e6?)~L7Ld?1NDc$ZW0q%+h-2KFPdx>?Z;x%pr# zEtX7l^xb1@@Og%kH@t2O7vhUn521rADg` zN!^X6qi1w27`DU+KT#e{zNaNzxhiOz$rlCSW#8IECPwPsW~8li*k8ory)B5;|EYe) z#E~y5;KQc(jS5$Q;(*aQ6olzXTn+UhNRt!VZyo_s`?6<;vwU z0&RZueh))C2e&y>re|%&q;y>==;El9i_zX+ku&*`MUPaka2$_}br>}=!&GVMhEyk2 z$|66tiY%wS=8+^n{KAUSp zICq#Q;0AY&IYC~7Rqd)Ub}PlB$F)Pbl})jZdWH&~xTr72x==@pL2R^Y&&prgZj{4- zCx#tkY=|f9a>muN4zv4(TO7sg%uhLwwtUP9Inh0AHb2@5m7J67{5Qy($Y=@qa1l!g_o z6ZW_zOPgSwI`1)jRja(hAC9&rMvmXDRAX?oa6_#tznH1A&K_7SIJ(ojt!$*Ep&ZC* zxv0z2Lse2|YGP(o;O! zy7q`1DMrU>q+}n4%lxq8oLJ41N=$8#C?vHRt1n}WxKDM0nDl~RO$S!-Cm`Du!bf!q#;G_q30?xwz0 zMsw&9c7#Kw6l8S&P1NrUA|>K%__m~SN1CGkCKIB!*d!r}bVgzO`#*tniQg{or#s*w7xBaUS;|vXf?{ zCRE-F!~ibxxE%ZqF^t1QtEaDa}#w zr*+UaB}r|oF;?oSac{Jvb5B31LeeQ$yf9t^RwU&ut@xyFMNSL zh9|AU?}G+7RFq@!RN6kNn&Y ziDRID7VQlD&*F|j=Qo?)sRrLb01W_yK#UlT!NUkehO8JYTSrPOt2s)?#{8@7ReN>P zN^nh6IXq55*c*YK_zSzNWj(TXrPJvaX<1v&ns+X<+BK26Ygk@&`D(0P%wJ475TS^GWneOnGQXNm(1G5pCO84V5^U5eqz-LHCLe#2l=J8)3wOCQ1 zmP6I=7X^)N7Uc~>=Iy5vuAH#9Eo!xf%H$~NZBZzQKRur0ayts&-36-AuIWP@{zvo!n1BQ zrm-68@tT)pP{ua`Dw?zs{J1{~q`@@$t-mio>$F zpp1f^HNw6Osd;Q8MymI{o}DafuvFI7cw5^DxAu1BY|brBNj zU(d;5wxUtwKU^xFhbv|wd@>%EOEfI2LsXtkJj%!68hM$dz${i6B+YMZR&3}+LeGXB z>~YA1lm|Ij(_XgCkP^|v*&qZPdm`yZ->gyfk>5E5r?4+jkCGCA;(G-;1*0XY55B+E z(TL|f8TWI=K(GEv%Elir`=Z|?()m{s#ZG*QJ2h~sD{GkN^mOf!1jq4YgQ5u4Def{Y z=_=|%_A8Wgi~mQ_&+a>89a6RDfTPd&PBgY-eL9W8NfIUWEx1(eBw38$yeXj&%i3J` zEMN8rNdT~-37;arQ1^}~%5rpM4xcmG_9SO9!eRb%Sw8+v zRg}CXfZ+1m3a*(q_n51#pdfKwlS3A-dzvd(m{6hTi#|^dKB=?}I-%~Lv;^`{~faLNi zfRTsg5rSCI0297StQ&l!$Z}B|6;V@S+E<{$beqp(!9LKAujk|D1;S}fNKvPOjw=zG z>{@}?Yzy=TOP_4Ly@P&QLR%V^rciJS{bFf^XNxK|qe>`XNj~rWkmafoR{-AnD#a%= zX-lixU(FOSt3>-^vkTXl!h-szJ_u=Mb9q$>I#!djT146z5F(HHONF@JTh{O52AO`@T0Zv3SpMiJ~ zR1T!)rzs%^0ci5sLITm}Kp=T$CjLb~{UHBWd3HqvJpqZH3T!VR6@R(6KDjIWWi`S? zggic3pYlQGBmgCVAoU;`r2i!S)Y3XV#9^>J2TNb`|il6<%@aZc|`vR8%XdQ9Q%rr;m=UidcPzi z%DkRPAv_cSfd3CCTcW?G4jY2T^Ly%ucnCm(6u+%+c*uVDdGSN7TIi|IZQU1HXr?pyt3Q@oc`Nc!{yd4O52|)F15I)}Dn(mXf#`bi>kV4XU{~FSNMFa@^ ztDpfMAMx3rfI@!^=XoRk`#1eW35fse@Vu06&kkY`CqC5QiT`<*{s&nUaKZfq)Ih-l P-~qDX0DuLa=f?j77 { // 1. 忽略租户上下文执行 + List pluginInfoList = pluginInfoService + .getPluginInfoListByStatus(IotPluginStatusEnum.RUNNING.getStatus()); // 2. 获取运行中的插件列表 + if (CollUtil.isEmpty(pluginInfoList)) { // 3. 检查插件列表是否为空 + log.info("[run] 没有需要启动的插件"); // 4. 日志记录没有插件需要启动 + return; + } + pluginInfoList.forEach(pluginInfo -> { // 5. 使用lambda表达式遍历插件列表 + try { + log.info("[run][启动插件] pluginKey = {}", pluginInfo.getPluginKey()); // 6. 日志记录插件启动信息 + pluginManager.startPlugin(pluginInfo.getPluginKey()); // 7. 启动插件 + } catch (Exception e) { + log.error("[run][启动插件失败] pluginKey = {}", pluginInfo.getPluginKey(), e); // 8. 记录启动失败的日志 + } + }); + }); + + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index 4f1d5e3e2..374e3856a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -31,7 +31,13 @@ public class UnifiedConfiguration { @DependsOn(SERVICE_REGISTRY_INITIALIZED_MARKER) public SpringPluginManager pluginManager() { log.info("[init][实例化 SpringPluginManager]"); - SpringPluginManager springPluginManager = new SpringPluginManager(); + SpringPluginManager springPluginManager = new SpringPluginManager() { + @Override + public void startPlugins() { + // 禁用插件启动,避免插件启动时,启动所有插件 + log.info("[init][禁用默认启动所有插件]"); + } + }; springPluginManager.addPluginStateListener(new CustomPluginStateListener()); return springPluginManager; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java index 2e920e32c..3a1529674 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInfoSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; import jakarta.validation.Valid; import org.springframework.web.multipart.MultipartFile; @@ -66,7 +67,7 @@ public interface PluginInfoService { * 更新插件的状态 * * @param id 插件id - * @param status 状态 + * @param status 状态 {@link IotPluginStatusEnum} */ void updatePluginStatus(Long id, Integer status); @@ -80,7 +81,7 @@ public interface PluginInfoService { /** * 根据状态获得插件信息列表 * - * @param status 状态 + * @param status 状态 {@link IotPluginStatusEnum} * @return 插件信息列表 */ List getPluginInfoListByStatus(Integer status); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java index 8e1fae88a..4cf922c20 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java @@ -102,7 +102,6 @@ public class PluginInfoServiceImpl implements PluginInfoService { // 3 上传新的插件文件,更新插件启用状态文件 String pluginKeyNew = pluginInstanceService.uploadAndLoadNewPlugin(file); - pluginInstanceService.updatePluginStatusFile(pluginKeyNew, false); // 4. 更新插件信息 updatePluginInfo(pluginInfoDo, pluginKeyNew, file); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java index cd1d5a654..9c360606a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java @@ -37,14 +37,6 @@ public interface PluginInstanceService { */ String uploadAndLoadNewPlugin(MultipartFile file); - /** - * 更新插件状态文件 - * - * @param pluginKeyNew 插件标识符 - * @param isEnabled 是否启用 - */ - void updatePluginStatusFile(String pluginKeyNew, boolean isEnabled); - /** * 更新插件状态 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java index a4bae8964..4a62dbcb9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java @@ -21,11 +21,7 @@ import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; -import java.net.Inet4Address; -import java.net.InetAddress; import java.nio.file.*; -import java.util.ArrayList; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -119,44 +115,6 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { return pluginKeyNew; } - @Override - public void updatePluginStatusFile(String pluginKeyNew, boolean isEnabled) { - // TODO @haohao:疑问,这里写 enabled.txt 和 disabled.txt 的目的是啥哈? - // pf4j 的插件状态文件,需要 2 个文件,一个 enabled.txt 一个 disabled.txt - Path enabledFilePath = Paths.get(pluginsDir, "enabled.txt"); - Path disabledFilePath = Paths.get(pluginsDir, "disabled.txt"); - Path targetFilePath = isEnabled ? enabledFilePath : disabledFilePath; - Path oppositeFilePath = isEnabled ? disabledFilePath : enabledFilePath; - - try { - PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginKeyNew); - if (pluginWrapper == null) { - throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED); - } - List targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) - : new ArrayList<>(); - List oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) - : new ArrayList<>(); - - if (!targetLines.contains(pluginKeyNew)) { - targetLines.add(pluginKeyNew); - Files.write(targetFilePath, targetLines, StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING); - log.info("已添加插件 {} 到 {}", pluginKeyNew, targetFilePath.getFileName()); - } - - if (oppositeLines.contains(pluginKeyNew)) { - oppositeLines.remove(pluginKeyNew); - Files.write(oppositeFilePath, oppositeLines, StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING); - log.info("已从 {} 移除插件 {}", oppositeFilePath.getFileName(), pluginKeyNew); - } - } catch (IOException e) { - log.error("[updatePluginStatusFile][更新插件状态文件失败]", e); - throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED, e); - } - } - @Override public void updatePluginStatus(PluginInfoDO pluginInfoDo, Integer status) { String pluginKey = pluginInfoDo.getPluginKey(); @@ -167,14 +125,12 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) && plugin.getPluginState() != PluginState.STARTED) { pluginManager.startPlugin(pluginKey); - updatePluginStatusFile(pluginKey, true); log.info("已启动插件: {}", pluginKey); } // 停止插件 else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) && plugin.getPluginState() == PluginState.STARTED) { pluginManager.stopPlugin(pluginKey); - updatePluginStatusFile(pluginKey, false); log.info("已停止插件: {}", pluginKey); } } else { @@ -208,7 +164,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { PluginInfoDO pluginInfo = pluginInfoMap.get(pluginKey); if (pluginInfo == null) { // 4.2 插件信息不存在,记录错误并跳过 - log.error("插件信息不存在,插件包标识符 = {}", pluginKey); + log.error("插件信息不存在,pluginKey = {}", pluginKey); continue; } diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java index c1d587489..1d6fcad92 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java @@ -5,12 +5,15 @@ import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import io.vertx.core.Vertx; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; -import org.pf4j.Plugin; import org.pf4j.PluginWrapper; +import org.pf4j.spring.SpringPlugin; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + import lombok.extern.slf4j.Slf4j; @Slf4j -public class HttpVertxPlugin extends Plugin { +public class HttpVertxPlugin extends SpringPlugin { private static final int PORT = 8092; private Vertx vertx; @@ -67,4 +70,13 @@ public class HttpVertxPlugin extends Plugin { }); } } + + @Override + protected ApplicationContext createApplicationContext() { + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + applicationContext.setClassLoader(getWrapper().getPluginClassLoader()); + applicationContext.refresh(); + + return applicationContext; + } } \ No newline at end of file From aad05817773d465c5fc335bc914c04ac0ad011c7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 8 Jan 2025 22:36:38 +0800 Subject: [PATCH 080/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=8F=92=E4=BB=B6=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 5 --- .../enums/plugin/IotPluginDeployTypeEnum.java | 5 +-- .../plugininstance/PluginInstanceDO.java | 7 ++-- .../service/plugin/PluginInfoServiceImpl.java | 2 +- .../service/plugin/PluginInstanceService.java | 2 +- .../plugin/PluginInstanceServiceImpl.java | 36 +++++++++---------- .../module/iot/controller/RpcController.java | 1 + 7 files changed, 27 insertions(+), 31 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b7a0b8667..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "java.compile.nullAnalysis.mode": "automatic", - "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable", - "java.configuration.updateBuildConfiguration": "interactive" -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java index 263873be7..11f8a6ef8 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java @@ -13,8 +13,8 @@ import java.util.Arrays; @Getter public enum IotPluginDeployTypeEnum implements IntArrayValuable { - DEPLOY_VIA_JAR(0, "通过 jar 部署"), // TODO @haohao:UPLOAD 和 ALONE 感觉有点冲突,前者是部署方式,后者是运行方式。这个后续再讨论下哈 - DEPLOY_STANDALONE(1, "独立部署"); + JAR(0, "JAR 部署"), + STANDALONE(1, "独立部署"); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginDeployTypeEnum::getDeployType).toArray(); @@ -48,4 +48,5 @@ public enum IotPluginDeployTypeEnum implements IntArrayValuable { public int[] array() { return ARRAYS; } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java index 507b91f2a..8b0ec95d1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java @@ -33,19 +33,22 @@ public class PluginInstanceDO extends BaseDO { */ private String mainId; /** - * 插件id + * 插件 ID *

* 关联 {@link PluginInfoDO#getId()} */ private Long pluginId; + /** - * 插件主程序所在ip + * 插件主程序所在 IP */ private String ip; /** * 插件主程序端口 */ private Integer port; + + // TODO @haohao:字段改成 heartbeatTime,LocalDateTime /** * 心跳时间,心路时间超过 30 秒需要剔除 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java index 4cf922c20..37b632845 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java @@ -100,7 +100,7 @@ public class PluginInfoServiceImpl implements PluginInfoService { // 2. 停止并卸载旧的插件 pluginInstanceService.stopAndUnloadPlugin(pluginInfoDo.getPluginKey()); - // 3 上传新的插件文件,更新插件启用状态文件 + // 3 上传新的插件文件,更新插件启用状态文件 String pluginKeyNew = pluginInstanceService.uploadAndLoadNewPlugin(file); // 4. 更新插件信息 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java index 9c360606a..4df9b1031 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java @@ -11,7 +11,7 @@ import org.springframework.web.multipart.MultipartFile; public interface PluginInstanceService { /** - * 上报插件实例 + * 上报插件实例(心跳) */ void reportPluginInstances(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java index 4a62dbcb9..65a6cf32b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java @@ -41,7 +41,8 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU public class PluginInstanceServiceImpl implements PluginInstanceService { // TODO @haohao:这个可以后续确认下,有没更合适的标识。例如说 mac 地址之类的 - // 简化的UUID + mac 地址 会不会好一些,一台机子有可能会部署多个插件 + // 简化的 UUID + mac 地址 会不会好一些,一台机子有可能会部署多个插件; + // 那就 mac@uuid ? public static final String MAIN_ID = IdUtil.fastSimpleUUID(); @Resource @@ -53,13 +54,13 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { @Value("${pf4j.pluginsDir}") private String pluginsDir; - @Value("${server.port:48080}") private int port; @Override public void stopAndUnloadPlugin(String pluginKey) { PluginWrapper plugin = pluginManager.getPlugin(pluginKey); + // TODO @haohao:改成 if return 会更简洁一点; if (plugin != null) { if (plugin.getPluginState().equals(PluginState.STARTED)) { pluginManager.stopPlugin(pluginKey); // 停止插件 @@ -75,6 +76,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { @Override public void deletePluginFile(PluginInfoDO pluginInfoDO) { File file = new File(pluginsDir, pluginInfoDO.getFileName()); + // TODO @haohao:改成 if return 会更简洁一点; if (file.exists()) { try { TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 @@ -82,9 +84,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName()); } } catch (InterruptedException e) { - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), - e); - Thread.currentThread().interrupt(); // 恢复中断状态 + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), e); } } } @@ -120,6 +120,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { String pluginKey = pluginInfoDo.getPluginKey(); PluginWrapper plugin = pluginManager.getPlugin(pluginKey); + // TODO @haohao:改成 if return 会更简洁一点; if (plugin != null) { // 启动插件 if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) @@ -143,46 +144,41 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { @Override public void reportPluginInstances() { - // 1. 获取 pf4j 插件列表 + // 1.1 获取 pf4j 插件列表 List plugins = pluginManager.getPlugins(); - // 2. 获取插件信息列表并转换为 Map 以便快速查找 + // 1.2 获取插件信息列表并转换为 Map 以便快速查找 List pluginInfos = pluginInfoMapper.selectList(); Map pluginInfoMap = pluginInfos.stream() .collect(Collectors.toMap(PluginInfoDO::getPluginKey, Function.identity())); - // 3. 获取本机 IP 和 MAC 地址 + // 1.3 获取本机 IP 和 MAC 地址 String ip = NetUtil.getLocalhostStr(); String mac = NetUtil.getLocalMacAddress(); String mainId = MAIN_ID + "-" + mac; - // 4. 遍历插件列表,并保存为插件实例 + // 2. 遍历插件列表,并保存为插件实例 for (PluginWrapper plugin : plugins) { String pluginKey = plugin.getPluginId(); - // 4.1 查找插件信息 + // 2.1 查找插件信息 PluginInfoDO pluginInfo = pluginInfoMap.get(pluginKey); if (pluginInfo == null) { - // 4.2 插件信息不存在,记录错误并跳过 log.error("插件信息不存在,pluginKey = {}", pluginKey); continue; } - // 4.3 查询插件实例 + // 2.2 情况一:如果插件实例不存在,则创建 PluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(mainId, pluginInfo.getId()); if (pluginInstance == null) { // 4.4 如果插件实例不存在,则创建 - pluginInstance = PluginInstanceDO.builder() - .pluginId(pluginInfo.getId()) - .mainId(MAIN_ID + "-" + mac) - .ip(ip) - .port(port) - .heartbeatAt(System.currentTimeMillis()) - .build(); + pluginInstance = PluginInstanceDO.builder().pluginId(pluginInfo.getId()).mainId(MAIN_ID + "-" + mac) + .ip(ip).port(port).heartbeatAt(System.currentTimeMillis()).build(); pluginInstanceMapper.insert(pluginInstance); } else { - // 4.5 如果插件实例存在,则更新心跳时间 + // 2.2 情况二:如果存在,则更新 heartbeatAt + // TODO @haohao:这里最好 new 去 update;避免并发更新(虽然目前没有) pluginInstance.setHeartbeatAt(System.currentTimeMillis()); pluginInstanceMapper.updateById(pluginInstance); } diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java index 8682a549c..4615dcf96 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.concurrent.CompletableFuture; +// TODO 芋艿:后续 review 下 /** * 插件实例 RPC 接口 * From deab8c1cc6bb7864d9c40e0c369f649f6f9bfa41 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 9 Jan 2025 12:36:30 +0800 Subject: [PATCH 081/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E6=97=A5?= =?UTF-8?q?=E5=BF=97=20TDengine=20=E8=A1=A8=E4=B8=8E=E6=A8=A1=E6=8B=9F?= =?UTF-8?q?=E8=AE=BE=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceDataController.java | 7 +++--- .../device/vo/device/IotDeviceSaveReqVO.java | 2 +- .../IotDeviceDataSimulatorSaveReqVO.java | 13 +++++----- .../vo/deviceData/IotDeviceLogPageReqVO.java | 5 +++- .../vo/deviceData/IotDeviceLogRespVO.java | 5 +++- .../thingmodel/IotThingModelController.java | 1 + .../thingmodel/vo/IotThingModelListReqVO.java | 8 +++---- .../dal/dataobject/device/IotDeviceLogDO.java | 24 ++++++++++++------- .../tdengine/ThingModelMessageDO.java | 4 ++-- .../dal/tdengine/IotDeviceLogDataMapper.java | 12 ++++++---- .../tdengine/TdThingModelMessageMapper.java | 6 +---- .../TDengineTableInitConfiguration.java | 9 ++++--- .../device/IotDeviceLogDataService.java | 3 +-- .../device/IotDeviceLogDataServiceImpl.java | 24 +++++++------------ .../IotDevicePropertyDataServiceImpl.java | 2 -- .../product/IotProductServiceImpl.java | 14 +++++------ .../IotThingModelMessageServiceImpl.java | 16 +++++-------- .../mapper/device/IotDeviceLogDataMapper.xml | 22 ++++++++--------- 18 files changed, 90 insertions(+), 87 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 801cbcb21..be451f17a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; @@ -13,7 +12,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -34,7 +32,7 @@ public class IotDeviceDataController { @Resource private IotDeviceLogDataService iotDeviceLogDataService; - @Resource + @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性 private IotDeviceLogDataService deviceLogDataService; // TODO @浩浩:这里的 /latest-list,包括方法名。 @@ -52,14 +50,17 @@ public class IotDeviceDataController { PageResult> list = deviceDataService.getHistoryDeviceProperties(deviceDataReqVO); return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); } + // TODO:数据权限 @PostMapping("/simulator") @Operation(summary = "模拟设备") public CommonResult simulatorDevice(@Valid @RequestBody IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { //TODO:先生成一下设备日志 后续完善模拟设备代码逻辑 + // TODO @super:应该 deviceDataService 里面有个 simulatorDevice,然后里面去 insert 日志! iotDeviceLogDataService.createDeviceLog(simulatorReqVO); return success(true); } + // TODO:数据权限 @GetMapping("/log/page") @Operation(summary = "获得设备日志分页") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java index e1268b003..7d9ac6a0d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java @@ -14,7 +14,7 @@ public class IotDeviceSaveReqVO { private Long id; @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.AUTO, example = "177") - @Size(max = 50, message = "设备编号长度不能超过50个字符") + @Size(max = 50, message = "设备编号长度不能超过 50 个字符") private String deviceKey; @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java index 3a4bfface..c4f9d1f55 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java @@ -3,27 +3,27 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +// TODO super: SaveReqVO => ReqVO @Schema(description = "管理后台 - IoT 模拟设备数据 Request VO") @Data public class IotDeviceDataSimulatorSaveReqVO { - @Schema(description = "消息ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "msg123") + // TODO @super:感觉后端随机更合适? + @Schema(description = "消息 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "msg123") private String id; + // TODO @super:不用传递 productKey,因为 deviceKey 可以推导出来 @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123") @NotEmpty(message = "产品ID不能为空") private String productKey; + // TODO @super:中文写作规范,中英文之间,要有空格。例如说,设备 ID。ps:这里应该是设备标识 @Schema(description = "设备ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123") @NotEmpty(message = "设备ID不能为空") private String deviceKey; + // TODO @super:type、subType,是不是不用传递,因为模拟只有属性??? @Schema(description = "消息/日志类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property") @NotEmpty(message = "消息类型不能为空") private String type; @@ -36,6 +36,7 @@ public class IotDeviceDataSimulatorSaveReqVO { @NotEmpty(message = "数据内容不能为空") private String content; + // TODO @芋艿:需要讨论下,reportTime 到底以那个为准! @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED) private Long reportTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogPageReqVO.java index 67099f331..a882a6d86 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogPageReqVO.java @@ -18,13 +18,16 @@ public class IotDeviceLogPageReqVO extends PageParam { @NotEmpty(message = "设备标识不能为空") private String deviceKey; + // TODO @super:对应的枚举类 @Schema(description = "消息类型", example = "property") private String type; @Schema(description = "标识符", example = "temperature") + // TODO @super:对应的枚举类 private String subType; @Schema(description = "创建时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; -} \ No newline at end of file + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogRespVO.java index 1201f7b74..48ea9b698 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogRespVO.java @@ -11,8 +11,10 @@ public class IotDeviceLogRespVO { @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private String id; + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123") private String productKey; + @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123") private String deviceKey; @@ -30,4 +32,5 @@ public class IotDeviceLogRespVO { @Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime ts; -} \ No newline at end of file + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java index d213329e2..e4913486d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java @@ -74,6 +74,7 @@ public class IotThingModelController { return success(IotThingModelConvert.INSTANCE.convertList(list)); } + // TODO @puhui @super:getThingModelListByProductId 和 getThingModelListByProductId 可以融合么? @GetMapping("/list") @Operation(summary = "获得产品物模型列表") @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java index 3652b36b9..dd77cfc5e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java @@ -6,11 +6,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; - - @Schema(description = "管理后台 - IoT 产品物模型List Request VO") @Data public class IotThingModelListReqVO { + @Schema(description = "功能标识") private String identifier; @@ -21,7 +20,8 @@ public class IotThingModelListReqVO { @InEnum(IotThingModelTypeEnum.class) private Integer type; - @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "产品ID不能为空") + @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "产品 ID 不能为空") private Long productId; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java index c82b231c5..dd811ee32 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java @@ -1,16 +1,15 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; -import cn.hutool.core.date.DateTime; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.time.LocalDateTime; - /** * IoT 设备日志数据 DO * + * 目前使用 TDengine 存储 + * * @author alwayssuper */ @Data @@ -18,33 +17,41 @@ import java.time.LocalDateTime; @NoArgsConstructor @AllArgsConstructor public class IotDeviceLogDO { + + // TODO @芋艿:消息 ID 的生成逻辑 /** - * 消息ID + * 消息 ID */ private String id; + // TODO @super:关联要 @下 /** - * 产品ID + * 产品标识 */ private String productKey; + // TODO @super:关联要 @下 /** - * 设备ID + * 设备标识 */ private String deviceKey; + // TODO @super:枚举类 /** - * 消息/日志类型 + * 日志类型 */ private String type; + // TODO @super:枚举类 /** * 标识符:用于标识具体的属性、事件或服务 */ private String subType; /** - * 数据内容:存储具体的消息数据内容,通常是JSON格式 + * 数据内容 + * + * 存储具体的消息数据内容,通常是 JSON 格式 */ private String content; @@ -58,5 +65,4 @@ public class IotDeviceLogDO { */ private Long ts; - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java index b647c6873..ae70da37b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java @@ -6,7 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; // TODO @芋艿:纠结下字段 -@Deprecated +@Deprecated // TODO @super:看看啥时候删除下哈。 /** * TD 物模型消息日志的数据库 */ @@ -25,7 +25,7 @@ public class ThingModelMessageDO { /** * 系统扩展参数 - * + * * 例如:设备状态、系统时间、固件版本等系统级信息 */ private Object system; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java index 51fd625ad..7d3a06633 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; -import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; @@ -12,7 +11,7 @@ import java.util.List; /** * IOT 设备日志数据 Mapper 接口 - * + * * 基于 TDengine 实现设备日志的存储 */ @Mapper @@ -22,11 +21,12 @@ public interface IotDeviceLogDataMapper { /** * 创建设备日志超级表 - * + * * 注意:初始化时只需创建一次 */ void createDeviceLogSTable(); + // TODO @super:是不是删除哈 /** * 创建设备日志子表 * @@ -34,11 +34,12 @@ public interface IotDeviceLogDataMapper { */ void createDeviceLogTable(@Param("deviceKey") String deviceKey); + // TODO @super:单个参数,不用加 @Param /** * 插入设备日志数据 - * + * * 如果子表不存在,会自动创建子表 - * + * * @param log 设备日志数据 */ void insert(@Param("log") IotDeviceLogDO log); @@ -58,4 +59,5 @@ public interface IotDeviceLogDataMapper { * @return 日志总数 */ Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java index b04be1199..cbc6e8836 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java @@ -1,10 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessageDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; -import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -13,7 +9,7 @@ import org.apache.ibatis.annotations.Param; * 处理 TD 中物模型消息日志的操作 */ @Mapper -@Deprecated +@Deprecated // TODO super:什么时候,删除下哈。 @TDengineDS @InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 public interface TdThingModelMessageMapper { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java index e14fa2948..e0057e180 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java @@ -16,7 +16,7 @@ import org.springframework.core.annotation.Order; @Slf4j @RequiredArgsConstructor @Configuration -@Order(Integer.MAX_VALUE) // 保证在最后执行 +@Order public class TDengineTableInitConfiguration implements ApplicationRunner { private final IotDeviceLogDataService deviceLogService; @@ -26,15 +26,18 @@ public class TDengineTableInitConfiguration implements ApplicationRunner { try { // 初始化设备日志表 deviceLogService.initTDengineSTable(); - log.info("初始化 设备日志表 TDengine 表结构成功"); + // TODO @super:这个日志,是不是不用打,不然重复啦!!! + log.info("[run]初始化 设备日志表 TDengine 表结构成功"); } catch (Exception ex) { + // TODO @super:初始化失败,打印 error 日志,退出系统。。不然跑起来,就初始啦!!! if (ex.getMessage().contains("Table already exists")) { log.info("TDengine 设备日志超级表已存在,跳过创建"); return; - }else{ + } else{ log.error("初始化 设备日志表 TDengine 表结构失败", ex); } throw ex; } } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java index 72cbf63e9..1a3b48503 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDevi import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; - /** * IoT 设备日志数据 Service 接口 * @@ -15,7 +14,7 @@ public interface IotDeviceLogDataService { /** * 初始化 TDengine 超级表 - * + * *系统启动时,会自动初始化一次 */ void initTDengineSTable(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java index bf883526d..d0659e507 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.service.device; -import cn.hutool.core.date.DateTime; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; @@ -12,8 +11,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.time.LocalDateTime; -import java.time.ZoneId; import java.util.List; /** @@ -29,34 +26,30 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ @Resource private IotDeviceLogDataMapper iotDeviceLogDataMapper; - + // TODO @super:方法名。defineDeviceLog。。未来,有可能别人使用别的记录日志,例如说 es 之类的。 @Override public void initTDengineSTable() { - try { - // 创建设备日志超级表 - iotDeviceLogDataMapper.createDeviceLogSTable(); - log.info("创建设备日志超级表成功"); - } catch (Exception ex) { - throw ex; - } + // TODO @super:改成不存在才创建。 + iotDeviceLogDataMapper.createDeviceLogSTable(); } @Override public void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { - //TODO:讨论一下,iotkit这块TS和上报时间都是外部传入的 但是看TDengine文档 他是建议对TS在SQL中直接NOW 咱们的TS数据获取是走哪一种 - // 1. 转换请求对象为 DO IotDeviceLogDO iotDeviceLogDO = BeanUtils.toBean(simulatorReqVO, IotDeviceLogDO.class); - + // 2. 处理时间字段 + // TODO @super:一次性的字段,不用单独给个变量 long currentTime = System.currentTimeMillis(); // 2.1 设置时序时间为当前时间 - iotDeviceLogDO.setTs(currentTime); + iotDeviceLogDO.setTs(currentTime); // TODO @super:TS在SQL中直接NOW 咱们的TS数据获取是走哪一种;走 now() // 3. 插入数据 + // TODO @super:不要直接调用对方的 IotDeviceLogDataMapper,通过 service 哈! iotDeviceLogDataMapper.insert(iotDeviceLogDO); } + // TODO @super:在 iotDeviceLogDataService 写 @Override public PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { // 查询数据 @@ -65,4 +58,5 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ // 构造分页结果 return new PageResult<>(list, total); } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index 5ca4cffe7..0f9523414 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -18,7 +18,6 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdThingModelMessageMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; @@ -111,7 +110,6 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe return; } newFields.add(0, new TDengineTableField(TDengineTableField.FIELD_TS, TDengineTableField.TYPE_TIMESTAMP)); - // 2.1.1 创建产品超级表 devicePropertyDataMapper.createProductPropertySTable(product.getProductKey(), newFields); return; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 41537664b..ad3ff94e2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; -import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; @@ -116,14 +115,15 @@ public class IotProductServiceImpl implements IotProductService { public void updateProductStatus(Long id, Integer status) { // 1. 校验存在 validateProductExists(id); - // 2. 更新 - IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); - // 3. 产品是发布状态 - if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { - // 3.1 创建产品超级表数据模型 - devicePropertyDataService.defineDevicePropertyData(id); + // 2. 产品是发布状态 + if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { + // 创建产品超级表数据模型 + devicePropertyDataService.defineDevicePropertyData(id); } + + // 3. 更新 + IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); productMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index 52e90f30f..e094b34cb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -7,20 +7,20 @@ import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdThingModelMessageMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; -import cn.iocoder.yudao.module.iot.util.IotTdDatabaseUtils; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -61,13 +61,9 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Resource private TdEngineDMLMapper tdEngineDMLMapper; - @Resource - private TdThingModelMessageMapper tdThingModelMessageMapper; - @Resource private DeviceDataRedisDAO deviceDataRedisDAO; - - + // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 @Override @TenantIgnore diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml index dd0f80a94..09e5dd468 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml @@ -7,19 +7,19 @@ CREATE STABLE device_log ( - ts TIMESTAMP, - id NCHAR(50), - product_key NCHAR(50), - type NCHAR(50), - subType NCHAR(50), - content NCHAR(1024), - report_time TIMESTAMP - )TAGS ( - device_key NCHAR(50) - ) + ts TIMESTAMP, + id NCHAR(50), + product_key NCHAR(50), + type NCHAR(50), + + subType NCHAR(50), + content NCHAR(1024), + report_time TIMESTAMP + ) TAGS ( + device_key NCHAR(50) + ) - CREATE TABLE device_log_${deviceKey} USING device_log TAGS('${deviceKey}') From d9dda54ccedb9dbf9ea13dc1190f95a136f55db5 Mon Sep 17 00:00:00 2001 From: alwayssuper <12851801+alwayssuper@user.noreply.gitee.com> Date: Fri, 10 Jan 2025 20:42:00 +0800 Subject: [PATCH 082/228] local --- .../dal/tdengine/IotDeviceLogDataMapper.java | 39 +++++++++++++++++++ .../device/IotDeviceLogDataService.java | 22 +++++++++++ .../src/main/resources/application-local.yaml | 31 ++++++++++----- .../src/main/resources/application.yaml | 5 ++- 4 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java new file mode 100644 index 000000000..194218b7f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.iot.dal.tdengine; + +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; +import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** + * IoT 设备日志 Mapper + * + * @author alwayssuper + */ +@Mapper +@TDengineDS +@InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 +public interface IotDeviceLogDataMapper { + + /** + * 创建设备日志超级表 + * 初始化只创建一次 + */ + void createDeviceLogSTable(); + + /** + * 创建设备日志子表 + * + * @param deviceKey 设备标识 + */ + void createDeviceLogTable( @Param("deviceKey") String deviceKey); + + /** + * 插入设备日志数据 + * + * @param log 设备日志数据 + */ + void insert(@Param("log") IotDeviceLogDO log); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java new file mode 100644 index 000000000..166727dec --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; + +/** + * IoT 设备日志数据 Service 接口 + * + * @author alwayssuper + */ +public interface IotDeviceLogDataService { + + /** + * 初始化 TDengine 表 + */ + void initTDengineSTable(); + + /** + * 模拟设备创建设备日志 + * @param simulatorReqVO 模拟设备信息 + */ + void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO); +} diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index e5ae6d195..fec1ad350 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -45,7 +45,7 @@ spring: primary: master datasource: master: - url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 @@ -53,8 +53,8 @@ spring: # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 - username: root - password: ahh@123456 + username: ruoyi-vue-pro + password: ruoyi-@h2ju02hebp # username: sa # SQL Server 连接的示例 # password: Yudao@2024 # SQL Server 连接的示例 # username: SYSDBA # DM 连接的示例 @@ -63,17 +63,25 @@ spring: # password: Yudao@2024 # OpenGauss 连接的示例 slave: # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: ruoyi-vue-pro + password: ruoyi-@h2ju02hebp + tdengine: # IOT 数据库 +# lazy: true # 开启懒加载,保证启动速度 + url: jdbc:TAOS-RS://chaojiniu.top:6041/ruoyi_vue_pro + driver-class-name: com.taosdata.jdbc.rs.RestfulDriver username: root - password: ahh@123456 + password: taosdata + druid: + validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: redis: - host: 127.0.0.1 # 地址 + host: chaojiniu.top # 地址 port: 6379 # 端口 - database: 0 # 数据库索引 -# password: dev # 密码,建议生产环境开启 + database: 15 # 数据库索引 + password: fsknKD7UvQYZsyf2hXXn # 密码,建议生产环境开启 --- #################### 定时任务相关配置 #################### @@ -175,8 +183,10 @@ logging: cn.iocoder.yudao.module.crm.dal.mysql: debug cn.iocoder.yudao.module.erp.dal.mysql: debug cn.iocoder.yudao.module.iot.dal.mysql: debug + cn.iocoder.yudao.module.iot.dal.tdengine: DEBUG cn.iocoder.yudao.module.ai.dal.mysql: debug org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 + com.taosdata: DEBUG # TDengine 的日志级别 debug: false @@ -259,7 +269,7 @@ justauth: iot: emq: # 账号 - username: anhaohao + username: haohao # 密码 password: ahh@123456 # 主机地址 @@ -271,4 +281,5 @@ iot: # 保持连接 keepalive: 60 # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) - clearSession: true \ No newline at end of file + clearSession: true + diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index baf68657e..933e02435 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -328,4 +328,7 @@ yudao: key: pLXUGAwK5305 customer: E77DF18BE109F454A5CD319E44BF5177 -debug: false \ No newline at end of file +debug: false +# 插件配置 +pf4j: + pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录 \ No newline at end of file From 62a868f497874f5d755ec1bff4b74a08c8bb05a5 Mon Sep 17 00:00:00 2001 From: alwayssuper <12851801+alwayssuper@user.noreply.gitee.com> Date: Sun, 12 Jan 2025 20:13:41 +0800 Subject: [PATCH 083/228] feat:simulator1 --- .../dal/tdengine/IotDeviceLogDataMapper.java | 34 +++++-------------- .../tdengine/TdThingModelMessageMapper.java | 31 ----------------- .../TDengineTableInitConfiguration.java | 13 +++---- .../device/IotDeviceLogDataService.java | 2 +- .../device/IotDeviceLogDataServiceImpl.java | 19 +++++++++-- .../mapper/device/IotDeviceLogDataMapper.xml | 9 +++-- .../src/main/resources/application-local.yaml | 6 ++-- 7 files changed, 40 insertions(+), 74 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java index 9584262df..42dcc0cf3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java @@ -21,32 +21,10 @@ public interface IotDeviceLogDataMapper { /** * 创建设备日志超级表 -<<<<<<< HEAD * 初始化只创建一次 */ void createDeviceLogSTable(); -======= - * - * 注意:初始化时只需创建一次 - */ - void createDeviceLogSTable(); - - // TODO @super:是不是删除哈 ->>>>>>> deab8c1cc6bb7864d9c40e0c369f649f6f9bfa41 - /** - * 创建设备日志子表 - * - * @param deviceKey 设备标识 - */ -<<<<<<< HEAD - void createDeviceLogTable( @Param("deviceKey") String deviceKey); - - /** - * 插入设备日志数据 - * -======= - void createDeviceLogTable(@Param("deviceKey") String deviceKey); // TODO @super:单个参数,不用加 @Param /** @@ -54,10 +32,9 @@ public interface IotDeviceLogDataMapper { * * 如果子表不存在,会自动创建子表 * ->>>>>>> deab8c1cc6bb7864d9c40e0c369f649f6f9bfa41 * @param log 设备日志数据 */ - void insert(@Param("log") IotDeviceLogDO log); + void insert(IotDeviceLogDO log); /** * 获得设备日志分页 @@ -65,7 +42,7 @@ public interface IotDeviceLogDataMapper { * @param reqVO 分页查询条件 * @return 设备日志列表 */ - List selectPage(@Param("reqVO") IotDeviceLogPageReqVO reqVO); + List selectPage(IotDeviceLogPageReqVO reqVO); /** * 获得设备日志总数 @@ -73,6 +50,11 @@ public interface IotDeviceLogDataMapper { * @param reqVO 查询条件 * @return 日志总数 */ - Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO); + Long selectCount(IotDeviceLogPageReqVO reqVO); + /** + * 查询设备日志表是否存在 + * + */ + Object checkDeviceLogTableExists(); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java deleted file mode 100644 index cbc6e8836..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdThingModelMessageMapper.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.tdengine; - -import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; -import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -/** - * 处理 TD 中物模型消息日志的操作 - */ -@Mapper -@Deprecated // TODO super:什么时候,删除下哈。 -@TDengineDS -@InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 -public interface TdThingModelMessageMapper { - - /** - * 创建物模型消息日志超级表超级表 - * - */ - - void createSuperTable(@Param("productKey") String productKey); - - /** - * 创建子表 - * - */ - - void createTableWithTag(@Param("productKey") String productKey,@Param("deviceKey") String deviceKey); - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java index e0057e180..c9f08903e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java @@ -25,18 +25,13 @@ public class TDengineTableInitConfiguration implements ApplicationRunner { public void run(ApplicationArguments args) { try { // 初始化设备日志表 - deviceLogService.initTDengineSTable(); + deviceLogService.defineDeviceLog(); // TODO @super:这个日志,是不是不用打,不然重复啦!!! - log.info("[run]初始化 设备日志表 TDengine 表结构成功"); } catch (Exception ex) { // TODO @super:初始化失败,打印 error 日志,退出系统。。不然跑起来,就初始啦!!! - if (ex.getMessage().contains("Table already exists")) { - log.info("TDengine 设备日志超级表已存在,跳过创建"); - return; - } else{ - log.error("初始化 设备日志表 TDengine 表结构失败", ex); - } - throw ex; + // 初始化失败时打印错误日志并退出系统 + log.error("[TDengine] 初始化设备日志表结构失败,系统无法正常运行,即将退出", ex); + System.exit(1); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java index 1a3b48503..a92d46bf4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java @@ -17,7 +17,7 @@ public interface IotDeviceLogDataService { * *系统启动时,会自动初始化一次 */ - void initTDengineSTable(); + void defineDeviceLog(); /** * 插入设备日志 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java index d0659e507..769821e3e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java @@ -28,9 +28,24 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ // TODO @super:方法名。defineDeviceLog。。未来,有可能别人使用别的记录日志,例如说 es 之类的。 @Override - public void initTDengineSTable() { + public void defineDeviceLog() { // TODO @super:改成不存在才创建。 - iotDeviceLogDataMapper.createDeviceLogSTable(); +// try { +// // 创建超级表(使用 IF NOT EXISTS 语句避免重复创建错误) +// iotDeviceLogDataMapper.createDeviceLogSTable(); +// } catch (Exception e) { +// if (e.getMessage().contains("already exists")) { +// log.info("[TDengine] 设备日志超级表已存在,跳过创建"); +// return; +// } +// throw e; +// } + if(iotDeviceLogDataMapper.checkDeviceLogTableExists()==null){ + log.info("[TDengine] 设备日志超级表不存在,开始创建 {}",iotDeviceLogDataMapper.checkDeviceLogTableExists()); + iotDeviceLogDataMapper.createDeviceLogSTable(); + }else{ + log.info("[TDengine] 设备日志超级表已存在,跳过创建"); + } } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml index 09e5dd468..1554b7d1e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml @@ -6,13 +6,13 @@ - CREATE STABLE device_log ( + CREATE STABLE IF NOT EXISTS device_log ( ts TIMESTAMP, id NCHAR(50), product_key NCHAR(50), type NCHAR(50), - subType NCHAR(50), + sub_type NCHAR(50), content NCHAR(1024), report_time TIMESTAMP ) TAGS ( @@ -75,4 +75,9 @@ + + + \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 518aa69a4..08918a667 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -283,9 +283,9 @@ iot: # MQTT-RPC 配置 mqtt: - broker: tcp://127.0.0.1:1883 - username: root - password: 123456 + broker: tcp://chaojiniu.top:1883 + username: haohao + password: ahh@123456 clientId: mqtt-rpc-server-${random.int} requestTopic: rpc/request responseTopicPrefix: rpc/response/ From 890d304340f1d20c52cf5288d47956eaed5814ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 15 Jan 2025 22:37:07 +0800 Subject: [PATCH 084/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=9B=B4=E6=96=B0=20Vert.x=20?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E8=87=B3=204.5.1=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20EMQX=20=E6=8F=92=E4=BB=B6=E5=8F=8A=E5=85=B6=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E9=85=8D=E7=BD=AE=EF=BC=8C=E9=87=8D=E6=9E=84=20MQTT?= =?UTF-8?q?=20=E6=8F=92=E4=BB=B6=E4=BB=A5=E6=94=AF=E6=8C=81=20Vert.x=20MQT?= =?UTF-8?q?T=20=E6=9C=8D=E5=8A=A1=E5=99=A8=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E5=90=AF=E5=8A=A8=E5=92=8C=E5=81=9C=E6=AD=A2?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E6=9B=B4=E6=96=B0=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0=E4=BF=A1=E6=81=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 6 + .../plugin.properties | 6 + .../yudao-module-iot-emqx-plugin/pom.xml | 164 +++++++++++++ .../src/main/assembly/assembly.xml | 31 +++ .../yudao/module/iot/plugin/EmqxPlugin.java | 45 ++++ .../yudao-module-iot-http-plugin/pom.xml | 13 +- .../plugin.properties | 7 +- .../yudao-module-iot-mqtt-plugin/pom.xml | 7 +- .../yudao/module/iot/plugin/MqttPlugin.java | 39 ++- .../iot/plugin/MqttServerExtension.java | 231 ++++++++++++++++++ 10 files changed, 508 insertions(+), 41 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index fb3cf8562..0a9d0bf45 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -626,6 +626,12 @@ vertx-web ${vertx.version} + + + io.vertx + vertx-mqtt + ${vertx.version} + diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties new file mode 100644 index 000000000..a23bafcf7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties @@ -0,0 +1,6 @@ +plugin.id=emqx-plugin +plugin.class=cn.iocoder.yudao.module.iot.plugin.EmqxPlugin +plugin.version=0.0.1 +plugin.provider=ahh +plugin.dependencies= +plugin.description=emqx-plugin-0.0.1 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml new file mode 100644 index 000000000..43d67f520 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml @@ -0,0 +1,164 @@ + + + + yudao-module-iot-plugin + cn.iocoder.boot + ${revision} + + 4.0.0 + jar + + yudao-module-iot-emqx-plugin + + ${project.artifactId} + + 物联网 插件模块 - emqx 插件 + + + + + emqx-plugin + cn.iocoder.yudao.module.iot.plugin.EmqxPlugin + 0.0.1 + ahh + emqx-plugin-0.0.1 + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.6 + + + unzip jar file + package + + + + + + + run + + + + + + + maven-assembly-plugin + 2.3 + + + + src/main/assembly/assembly.xml + + + false + + + + make-assembly + package + + attached + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.description} + ${plugin.dependencies} + + + + + + + maven-deploy-plugin + + true + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.pf4j + pf4j-spring + provided + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + io.vertx + vertx-core + + + + io.vertx + vertx-web + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml new file mode 100644 index 000000000..daec9e431 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml @@ -0,0 +1,31 @@ + + plugin + + zip + + false + + + false + runtime + lib + + *:jar:* + + + + + + + target/plugin-classes + classes + + + diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java new file mode 100644 index 000000000..e64695b06 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; + +import javax.annotation.Resource; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Slf4j +public class EmqxPlugin extends Plugin { + + private ExecutorService executorService; + @Resource + private DeviceDataApi deviceDataApi; + + public EmqxPlugin(PluginWrapper wrapper) { + super(wrapper); + this.executorService = Executors.newSingleThreadExecutor(); + } + + @Override + public void start() { + log.info("EmqxPlugin.start()"); + + if (executorService.isShutdown() || executorService.isTerminated()) { + executorService = Executors.newSingleThreadExecutor(); + } + + deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); + if (deviceDataApi == null) { + log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); + return; + } + + } + + @Override + public void stop() { + log.info("EmqxPlugin.stop()"); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index 29c0200f1..22cb43968 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -147,20 +147,11 @@ ${lombok.version} provided - - - io.vertx - vertx-core - - + io.vertx vertx-web - - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 + 4.5.11 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties index 31050c5ba..939e0f692 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties @@ -1,6 +1,7 @@ plugin.id=mqtt-plugin +plugin.description=Vert.x MQTT plugin plugin.class=cn.iocoder.yudao.module.iot.plugin.MqttPlugin -plugin.version=0.0.1 +plugin.version=1.0.0 +plugin.requires= plugin.provider=ahh -plugin.dependencies= -plugin.description=mqtt-plugin-0.0.1 +plugin.license=Apache-2.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml index 9607e0f93..462fbd090 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml @@ -145,10 +145,11 @@ ${lombok.version} provided - + - org.eclipse.paho - org.eclipse.paho.client.mqttv3 + io.vertx + vertx-mqtt + 4.5.11 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java index b3749e402..54ff31f36 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java @@ -1,45 +1,36 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.ServiceRegistry; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import lombok.extern.slf4j.Slf4j; import org.pf4j.Plugin; import org.pf4j.PluginWrapper; -import javax.annotation.Resource; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - @Slf4j public class MqttPlugin extends Plugin { - private ExecutorService executorService; - @Resource - private DeviceDataApi deviceDataApi; + private MqttServerExtension mqttServerExtension; public MqttPlugin(PluginWrapper wrapper) { super(wrapper); - this.executorService = Executors.newSingleThreadExecutor(); } @Override public void start() { - log.info("MqttPlugin.start()"); - - if (executorService.isShutdown() || executorService.isTerminated()) { - executorService = Executors.newSingleThreadExecutor(); - } - - deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); - if (deviceDataApi == null) { - log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); - return; - } - + log.info("MQTT Plugin started."); + mqttServerExtension = new MqttServerExtension(); + mqttServerExtension.startMqttServer(); } @Override public void stop() { - log.info("MqttPlugin.stop()"); + log.info("MQTT Plugin stopped."); + if (mqttServerExtension != null) { + mqttServerExtension.stopMqttServer().onComplete(ar -> { + if (ar.succeeded()) { + log.info("Stopped MQTT Server successfully"); + } else { + log.error("Failed to stop MQTT Server: {}", ar.cause().getMessage()); + } + }); + } } -} \ No newline at end of file +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java new file mode 100644 index 000000000..868d238ee --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java @@ -0,0 +1,231 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import io.netty.handler.codec.mqtt.MqttProperties; +import io.netty.handler.codec.mqtt.MqttQoS; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.mqtt.MqttEndpoint; +import io.vertx.mqtt.MqttServer; +import io.vertx.mqtt.MqttServerOptions; +import io.vertx.mqtt.MqttTopicSubscription; +import io.vertx.mqtt.messages.MqttDisconnectMessage; +import io.vertx.mqtt.messages.MqttPublishMessage; +import io.vertx.mqtt.messages.MqttSubscribeMessage; +import io.vertx.mqtt.messages.MqttUnsubscribeMessage; +import io.vertx.mqtt.messages.codes.MqttSubAckReasonCode; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.Extension; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +/** + * 根据官方示例,整合常见 MQTT 功能到 PF4J 的 Extension 类中 + */ +@Slf4j +@Extension +public class MqttServerExtension { + + private Vertx vertx; + private MqttServer mqttServer; + + /** + * 启动 MQTT 服务端 + * 可根据需要决定是否启用 SSL/TLS、WebSocket、多实例部署等 + */ + public void startMqttServer() { + // 初始化 Vert.x + vertx = Vertx.vertx(); + + // ========== 如果需要 SSL/TLS,请参考下面注释,启用注释并替换端口、证书路径等 ========== + // MqttServerOptions options = new MqttServerOptions() + // .setPort(8883) + // .setKeyCertOptions(new PemKeyCertOptions() + // .setKeyPath("./src/test/resources/tls/server-key.pem") + // .setCertPath("./src/test/resources/tls/server-cert.pem")) + // .setSsl(true); + + // ========== 如果需要 WebSocket,请设置 setUseWebSocket(true) ========== + // options.setUseWebSocket(true); + + // ========== 默认不启用 SSL 的示例 ========== + MqttServerOptions options = new MqttServerOptions() + .setPort(1883) + .setHost("0.0.0.0") + .setUseWebSocket(false); // 如果需要 WebSocket,请改为 true + + mqttServer = MqttServer.create(vertx, options); + + // 指定 endpointHandler,处理客户端连接等 + mqttServer.endpointHandler(endpoint -> { + handleClientConnect(endpoint); + handleDisconnect(endpoint); + handleSubscribe(endpoint); + handleUnsubscribe(endpoint); + handlePublish(endpoint); + handlePing(endpoint); + }); + + // 启动监听 + mqttServer.listen(ar -> { + if (ar.succeeded()) { + log.info("MQTT server is listening on port {}", mqttServer.actualPort()); + } else { + log.error("Error on starting the server", ar.cause()); + } + }); + } + + /** + * 优雅关闭 MQTT 服务端 + */ + public Future stopMqttServer() { + if (mqttServer != null) { + return mqttServer.close().onComplete(ar -> { + if (ar.succeeded()) { + log.info("MQTT server closed."); + if (vertx != null) { + vertx.close(); + log.info("Vert.x instance closed."); + } + } else { + log.error("Failed to close MQTT server: {}", ar.cause().getMessage()); + } + }); + } + return Future.succeededFuture(); + } + + // ==================== 以下为官方示例中常见事件的处理封装 ==================== + + /** + * 处理客户端连接 (CONNECT) + */ + private void handleClientConnect(MqttEndpoint endpoint) { + // 打印 CONNECT 的主要信息 + log.info("MQTT client [{}] request to connect, clean session = {}", + endpoint.clientIdentifier(), endpoint.isCleanSession()); + + if (endpoint.auth() != null) { + log.info("[username = {}, password = {}]", endpoint.auth().getUsername(), endpoint.auth().getPassword()); + } + log.info("[properties = {}]", endpoint.connectProperties()); + + if (endpoint.will() != null) { + log.info("[will topic = {}, msg = {}, QoS = {}, isRetain = {}]", + endpoint.will().getWillTopic(), + new String(endpoint.will().getWillMessageBytes()), + endpoint.will().getWillQos(), + endpoint.will().isWillRetain()); + } + + log.info("[keep alive timeout = {}]", endpoint.keepAliveTimeSeconds()); + + // 接受远程客户端的连接 + endpoint.accept(false); + } + + /** + * 处理客户端主动断开 (DISCONNECT) + */ + private void handleDisconnect(MqttEndpoint endpoint) { + endpoint.disconnectMessageHandler((MqttDisconnectMessage disconnectMessage) -> { + log.info("Received disconnect from client [{}], reason code = {}", + endpoint.clientIdentifier(), disconnectMessage.code()); + }); + } + + /** + * 处理客户端订阅 (SUBSCRIBE) + */ + private void handleSubscribe(MqttEndpoint endpoint) { + endpoint.subscribeHandler((MqttSubscribeMessage subscribe) -> { + List reasonCodes = new ArrayList<>(); + for (MqttTopicSubscription s : subscribe.topicSubscriptions()) { + log.info("Subscription for {} with QoS {}", s.topicName(), s.qualityOfService()); + // 将客户端请求的 QoS 转换为返回给客户端的 reason code(可能是错误码或实际 granted QoS) + reasonCodes.add(MqttSubAckReasonCode.qosGranted(s.qualityOfService())); + } + // 回复 SUBACK,MQTT 5.0 时可指定 reasonCodes、properties + endpoint.subscribeAcknowledge(subscribe.messageId(), reasonCodes, MqttProperties.NO_PROPERTIES); + }); + } + + /** + * 处理客户端取消订阅 (UNSUBSCRIBE) + */ + private void handleUnsubscribe(MqttEndpoint endpoint) { + endpoint.unsubscribeHandler((MqttUnsubscribeMessage unsubscribe) -> { + for (String topic : unsubscribe.topics()) { + log.info("Unsubscription for {}", topic); + } + // 回复 UNSUBACK,MQTT 5.0 时可指定 reasonCodes、properties + endpoint.unsubscribeAcknowledge(unsubscribe.messageId()); + }); + } + + /** + * 处理客户端发布的消息 (PUBLISH) + */ + private void handlePublish(MqttEndpoint endpoint) { + // 接收 PUBLISH 消息 + endpoint.publishHandler((MqttPublishMessage message) -> { + String payload = message.payload().toString(Charset.defaultCharset()); + log.info("Received message [{}] on topic [{}] with QoS [{}]", + payload, message.topicName(), message.qosLevel()); + + // 根据不同 QoS,回复客户端 + if (message.qosLevel() == MqttQoS.AT_LEAST_ONCE) { + endpoint.publishAcknowledge(message.messageId()); + } else if (message.qosLevel() == MqttQoS.EXACTLY_ONCE) { + endpoint.publishReceived(message.messageId()); + } + }); + + // 如果 QoS = 2,需要处理 PUBREL + endpoint.publishReleaseHandler(messageId -> { + endpoint.publishComplete(messageId); + }); + } + + /** + * 处理客户端 PINGREQ + */ + private void handlePing(MqttEndpoint endpoint) { + endpoint.pingHandler(v -> { + // 这里仅做日志, PINGRESP 已自动发送 + log.info("Ping received from client [{}]", endpoint.clientIdentifier()); + }); + } + + // ==================== 如果需要服务端向客户端发布消息,可用以下示例 ==================== + + /** + * 服务端主动向已连接的某个 endpoint 发布消息的示例 + * 如果使用 MQTT 5.0,可以传递更多消息属性 + */ + public void publishToClient(MqttEndpoint endpoint, String topic, String content) { + endpoint.publish(topic, + Buffer.buffer(content), + MqttQoS.AT_LEAST_ONCE, // QoS 自行选择 + false, + false); + + // 处理 QoS 1 和 QoS 2 的 ACK + endpoint.publishAcknowledgeHandler(messageId -> { + log.info("Received PUBACK from client [{}] for messageId = {}", endpoint.clientIdentifier(), messageId); + }).publishReceivedHandler(messageId -> { + endpoint.publishRelease(messageId); + }).publishCompletionHandler(messageId -> { + log.info("Received PUBCOMP from client [{}] for messageId = {}", endpoint.clientIdentifier(), messageId); + }); + } + + // ==================== 如果需要多实例部署,用于多核扩展,可参考以下思路 ==================== + // 例如,在宿主应用或插件中循环启动多个 MqttServerExtension 实例,或使用 Vert.x 的 deployVerticle: + // DeploymentOptions options = new DeploymentOptions().setInstances(10); + // vertx.deployVerticle(() -> new MyMqttVerticle(), options); + +} From 552432455415142c5b57f403b52bba7eacc008e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 19 Jan 2025 09:53:57 +0800 Subject: [PATCH 085/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E5=88=A0=E9=99=A4=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=20MQTT=20RPC=20=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=92=8C=E5=AE=9E=E7=8E=B0=EF=BC=8C=E5=8C=85?= =?UTF-8?q?=E6=8B=AC=20MqttConfig=E3=80=81RpcServer=E3=80=81RpcClient=20?= =?UTF-8?q?=E5=92=8C=20RpcController=20=E7=B1=BB=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=E4=BB=A5=E6=B8=85?= =?UTF-8?q?=E7=90=86=E6=9C=AA=E4=BD=BF=E7=94=A8=E7=9A=84=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/mqttrpc/config/MqttConfig.java | 40 ------- .../module/iot/mqttrpc/server/RpcServer.java | 100 ------------------ .../module/iot/controller/RpcController.java | 38 ------- .../module/iot/mqttrpc/client/RpcClient.java | 93 ---------------- .../module/iot/mqttrpc/config/MqttConfig.java | 41 ------- 5 files changed, 312 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java deleted file mode 100644 index c7a050003..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties(prefix = "mqtt") -public class MqttConfig { - /** - * MQTT 代理地址 - */ - private String broker; - - /** - * MQTT 用户名 - */ - private String username; - - /** - * MQTT 密码 - */ - private String password; - - /** - * MQTT 客户端 ID - */ - private String clientId; - - /** - * MQTT 请求主题 - */ - private String requestTopic; - - /** - * MQTT 响应主题前缀 - */ - private String responseTopicPrefix; -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java deleted file mode 100644 index 90ce2a387..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java +++ /dev/null @@ -1,100 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.server; - -import cn.hutool.core.lang.UUID; -import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest; -import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse; -import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils; -import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.client.mqttv3.*; -import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import java.util.HashMap; -import java.util.Map; - -// TODO @芋艿:server 逻辑,再瞅瞅; -// TODO @haohao:如果只写在 iot biz 里,那么后续 server => client 貌似不方便?微信再讨论下~; -@Service -@Slf4j -public class RpcServer { - - private final MqttConfig mqttConfig; - private final MqttClient mqttClient; - private final Map methodRegistry = new HashMap<>(); - - public RpcServer(MqttConfig mqttConfig) throws MqttException { - this.mqttConfig = mqttConfig; - this.mqttClient = new MqttClient(mqttConfig.getBroker(), "rpc-server-" + UUID.randomUUID(), new MemoryPersistence()); - MqttConnectOptions options = new MqttConnectOptions(); - options.setAutomaticReconnect(true); - options.setCleanSession(true); - options.setUserName(mqttConfig.getUsername()); - options.setPassword(mqttConfig.getPassword().toCharArray()); - this.mqttClient.connect(options); - } - - @PostConstruct - public void init() throws MqttException { - mqttClient.subscribe(mqttConfig.getRequestTopic(), this::handleRequest); - log.info("RPC Server subscribed to topic: {}", mqttConfig.getRequestTopic()); - } - - private void handleRequest(String topic, MqttMessage message) { - RpcRequest request = SerializationUtils.deserialize(new String(message.getPayload()), RpcRequest.class); - RpcResponse response = new RpcResponse(); - response.setCorrelationId(request.getCorrelationId()); - - try { - MethodInvoker invoker = methodRegistry.get(request.getMethod()); - if (invoker == null) { - throw new NoSuchMethodException("Unknown method: " + request.getMethod()); - } - Object result = invoker.invoke(request.getParams()); - response.setResult(result); - } catch (Exception e) { - response.setError(e.getMessage()); - log.error("Error processing RPC request: {}", e.getMessage(), e); - } - - String replyPayload = SerializationUtils.serialize(response); - MqttMessage replyMessage = new MqttMessage(replyPayload.getBytes()); - replyMessage.setQos(1); - try { - mqttClient.publish(request.getReplyTo(), replyMessage); - log.info("Published response to {}", request.getReplyTo()); - } catch (MqttException e) { - log.error("Failed to publish response: {}", e.getMessage(), e); - } - } - - /** - * 注册可调用的方法 - * - * @param methodName 方法名称 - * @param invoker 方法调用器 - */ - public void registerMethod(String methodName, MethodInvoker invoker) { - methodRegistry.put(methodName, invoker); - log.info("Registered method: {}", methodName); - } - - @PreDestroy - public void cleanup() throws MqttException { - mqttClient.disconnect(); - log.info("RPC Server disconnected"); - } - - /** - * 方法调用器接口 - */ - @FunctionalInterface - public interface MethodInvoker { - - Object invoke(Object[] params) throws Exception; - - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java deleted file mode 100644 index 4615dcf96..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java +++ /dev/null @@ -1,38 +0,0 @@ - -package cn.iocoder.yudao.module.iot.controller; - -import cn.iocoder.yudao.module.iot.mqttrpc.client.RpcClient; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import java.util.concurrent.CompletableFuture; - -// TODO 芋艿:后续 review 下 -/** - * 插件实例 RPC 接口 - * - * @author 芋道源码 - */ -@RestController -@RequestMapping("/rpc") -@RequiredArgsConstructor -public class RpcController { - - @Resource - private RpcClient rpcClient; - - @PostMapping("/add") - public CompletableFuture add(@RequestParam int a, @RequestParam int b) throws Exception { - return rpcClient.call("add", new Object[]{a, b}, 10); - } - - @PostMapping("/concat") - public CompletableFuture concat(@RequestParam String str1, @RequestParam String str2) throws Exception { - return rpcClient.call("concat", new Object[]{str1, str2}, 10); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java deleted file mode 100644 index b73f88c53..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java +++ /dev/null @@ -1,93 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.client; - -import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest; -import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse; -import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils; -import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; -import org.eclipse.paho.client.mqttv3.MqttException; -import org.eclipse.paho.client.mqttv3.MqttMessage; -import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import java.util.UUID; -import java.util.concurrent.*; - -// TODO @芋艿:需要考虑,怎么公用! -@Service -@Slf4j -public class RpcClient { - - private final MqttConfig mqttConfig; - private final MqttClient mqttClient; - private final ConcurrentMap> pendingRequests = new ConcurrentHashMap<>(); - private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - public RpcClient(MqttConfig mqttConfig) throws MqttException { - this.mqttConfig = mqttConfig; - this.mqttClient = new MqttClient(mqttConfig.getBroker(), mqttConfig.getClientId(), new MemoryPersistence()); - MqttConnectOptions options = new MqttConnectOptions(); - options.setAutomaticReconnect(true); - options.setCleanSession(true); - options.setUserName(mqttConfig.getUsername()); - options.setPassword(mqttConfig.getPassword().toCharArray()); - this.mqttClient.connect(options); - } - - @PostConstruct - public void init() throws MqttException { - mqttClient.subscribe(mqttConfig.getResponseTopicPrefix() + "#", this::handleResponse); - log.info("RPC Client subscribed to topics: {}", mqttConfig.getResponseTopicPrefix() + "#"); - } - - private void handleResponse(String topic, MqttMessage message) { - String correlationId = topic.substring(mqttConfig.getResponseTopicPrefix().length()); - RpcResponse response = SerializationUtils.deserialize(new String(message.getPayload()), RpcResponse.class); - CompletableFuture future = pendingRequests.remove(correlationId); - if (future != null) { - if (response.getError() != null) { - future.completeExceptionally(new RuntimeException(response.getError())); - } else { - future.complete(response); - } - } else { - log.warn("Received response for unknown correlationId: {}", correlationId); - } - } - - public CompletableFuture call(String method, Object[] params, int timeoutSeconds) throws MqttException { - String correlationId = UUID.randomUUID().toString(); - String replyTo = mqttConfig.getResponseTopicPrefix() + correlationId; - - RpcRequest request = new RpcRequest(method, params, correlationId, replyTo); - String payload = SerializationUtils.serialize(request); - MqttMessage message = new MqttMessage(payload.getBytes()); - message.setQos(1); - mqttClient.publish(mqttConfig.getRequestTopic(), message); - - CompletableFuture futureResponse = new CompletableFuture<>(); - pendingRequests.put(correlationId, futureResponse); - - // 设置超时 - scheduler.schedule(() -> { - CompletableFuture removed = pendingRequests.remove(correlationId); - if (removed != null) { - removed.completeExceptionally(new TimeoutException("RPC call timed out")); - } - }, timeoutSeconds, TimeUnit.SECONDS); - - // 返回最终的结果 - return futureResponse.thenApply(RpcResponse::getResult); - } - - @PreDestroy - public void cleanup() throws MqttException { - mqttClient.disconnect(); - scheduler.shutdown(); - log.info("RPC Client disconnected"); - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java deleted file mode 100644 index 89569b0c3..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties(prefix = "mqtt") -public class MqttConfig { - - /** - * MQTT 代理地址 - */ - private String broker; - - /** - * MQTT 用户名 - */ - private String username; - - /** - * MQTT 密码 - */ - private String password; - - /** - * MQTT 客户端 ID - */ - private String clientId; - - /** - * MQTT 请求主题 - */ - private String requestTopic; - - /** - * MQTT 响应主题前缀 - */ - private String responseTopicPrefix; -} From 9f3730d5d943e4bd30acfcc21223a43791cb995a Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Mon, 20 Jan 2025 16:31:37 +0800 Subject: [PATCH 086/228] =?UTF-8?q?[fix]=EF=BC=9Acode=20=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotDeviceDataSimulatorSaveReqVO.java | 10 ++- .../dal/dataobject/device/IotDeviceLogDO.java | 5 ++ .../dal/tdengine/IotDeviceLogDataMapper.java | 19 +++- .../device/IotDeviceLogDataServiceImpl.java | 6 +- .../iot/service/plugin/ExampleService.java | 86 +++++++++---------- .../mapper/device/IotDeviceLogDataMapper.xml | 6 +- 6 files changed, 77 insertions(+), 55 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java index c4f9d1f55..5e2b08543 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java @@ -14,16 +14,18 @@ public class IotDeviceDataSimulatorSaveReqVO { private String id; // TODO @super:不用传递 productKey,因为 deviceKey 可以推导出来 - @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123") - @NotEmpty(message = "产品ID不能为空") + // TODO 讨论: 日志记录的时候要记录一下productKey,目前是前端已经有productKey了,所以前端传入,如果不传入的话,后端要根据deviceKey查询productKey,感觉直传是不是效率高一些 + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123") + @NotEmpty(message = "产品标识不能为空") private String productKey; // TODO @super:中文写作规范,中英文之间,要有空格。例如说,设备 ID。ps:这里应该是设备标识 - @Schema(description = "设备ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123") - @NotEmpty(message = "设备ID不能为空") + @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123") + @NotEmpty(message = "设备标识不能为空") private String deviceKey; // TODO @super:type、subType,是不是不用传递,因为模拟只有属性??? + // TODO 讨论: 不只模拟属性 @Schema(description = "消息/日志类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property") @NotEmpty(message = "消息类型不能为空") private String type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java index dd811ee32..609c9c43a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -27,12 +28,16 @@ public class IotDeviceLogDO { // TODO @super:关联要 @下 /** * 产品标识 + *

+ * 关联 {@link IotProductDO#getProductKey()} */ private String productKey; // TODO @super:关联要 @下 /** * 设备标识 + *

+ * 关联 {@link IotDeviceDO#getDeviceKey()}} */ private String deviceKey; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java index 42dcc0cf3..40516c794 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java @@ -27,6 +27,19 @@ public interface IotDeviceLogDataMapper { // TODO @super:单个参数,不用加 @Param + //讨论:艿菇这里有些特殊情况,我也学习了一下这块知识: + // 如果使用的是Java 8及以上版本,并且编译器保留了参数名(通过编译器选项-parameters启用),则可以去掉@Param注解。MyBatis会自动使用参数的实际名称 + // 但在TDengine中 @Param去掉后TDengine会报错,以下是大模型的回答: + // 不用加 @Param在普通的 MySQL 场景下是正确的 - 对于 MyBatis,当方法只有一个参数时,确实可以不用添加 @Param 注解。 + //但是在 TDengine 的场景下,情况不同: + //TDengine 的特殊性: + //TDengine 使用特殊的 SQL 语法 + //需要处理超级表(STable)和子表的概念 + //参数绑定的方式与普通 MySQL 不同 + //为什么这里必须要 @Param: + //XML 中使用了 ${log.deviceKey} 这样的参数引用方式 + //需要在 SQL 中动态构建表名(device_log_${log.deviceKey}) + //没有 @Param("log") 的话,MyBatis 无法正确解析参数 /** * 插入设备日志数据 * @@ -34,7 +47,7 @@ public interface IotDeviceLogDataMapper { * * @param log 设备日志数据 */ - void insert(IotDeviceLogDO log); + void insert(@Param("log") IotDeviceLogDO log); /** * 获得设备日志分页 @@ -42,7 +55,7 @@ public interface IotDeviceLogDataMapper { * @param reqVO 分页查询条件 * @return 设备日志列表 */ - List selectPage(IotDeviceLogPageReqVO reqVO); + List selectPage(@Param("reqVO") IotDeviceLogPageReqVO reqVO); /** * 获得设备日志总数 @@ -50,7 +63,7 @@ public interface IotDeviceLogDataMapper { * @param reqVO 查询条件 * @return 日志总数 */ - Long selectCount(IotDeviceLogPageReqVO reqVO); + Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO); /** * 查询设备日志表是否存在 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java index 769821e3e..85f950d5d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java @@ -55,16 +55,18 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ // 2. 处理时间字段 // TODO @super:一次性的字段,不用单独给个变量 - long currentTime = System.currentTimeMillis(); +// long currentTime = System.currentTimeMillis(); // 2.1 设置时序时间为当前时间 - iotDeviceLogDO.setTs(currentTime); // TODO @super:TS在SQL中直接NOW 咱们的TS数据获取是走哪一种;走 now() +// iotDeviceLogDO.setTs(currentTime); // TODO @super:TS在SQL中直接NOW 咱们的TS数据获取是走哪一种;走 now() // 3. 插入数据 // TODO @super:不要直接调用对方的 IotDeviceLogDataMapper,通过 service 哈! + // 讨论:艿菇 这就是iotDeviceLogDataService的Impl iotDeviceLogDataMapper.insert(iotDeviceLogDO); } // TODO @super:在 iotDeviceLogDataService 写 + // 讨论:艿菇 这就是iotDeviceLogDataService的Impl @Override public PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { // 查询数据 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java index 22ebe8b4f..13810bbd5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java @@ -1,43 +1,43 @@ -package cn.iocoder.yudao.module.iot.service.plugin; - -import cn.iocoder.yudao.module.iot.mqttrpc.server.RpcServer; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; - -@Service -@RequiredArgsConstructor -public class ExampleService { - - private final RpcServer rpcServer; - - @PostConstruct - public void registerMethods() { - rpcServer.registerMethod("add", params -> { - if (params.length != 2) { - throw new IllegalArgumentException("add方法需要两个参数"); - } - int a = ((Number) params[0]).intValue(); - int b = ((Number) params[1]).intValue(); - return add(a, b); - }); - - rpcServer.registerMethod("concat", params -> { - if (params.length != 2) { - throw new IllegalArgumentException("concat方法需要两个参数"); - } - String str1 = params[0].toString(); - String str2 = params[1].toString(); - return concat(str1, str2); - }); - } - - private int add(int a, int b) { - return a + b; - } - - private String concat(String a, String b) { - return a + b; - } -} \ No newline at end of file +//package cn.iocoder.yudao.module.iot.service.plugin; +// +//import cn.iocoder.yudao.module.iot.mqttrpc.server.RpcServer; +//import lombok.RequiredArgsConstructor; +//import org.springframework.stereotype.Service; +// +//import javax.annotation.PostConstruct; +// +//@Service +//@RequiredArgsConstructor +//public class ExampleService { +// +// private final RpcServer rpcServer; +// +// @PostConstruct +// public void registerMethods() { +// rpcServer.registerMethod("add", params -> { +// if (params.length != 2) { +// throw new IllegalArgumentException("add方法需要两个参数"); +// } +// int a = ((Number) params[0]).intValue(); +// int b = ((Number) params[1]).intValue(); +// return add(a, b); +// }); +// +// rpcServer.registerMethod("concat", params -> { +// if (params.length != 2) { +// throw new IllegalArgumentException("concat方法需要两个参数"); +// } +// String str1 = params[0].toString(); +// String str2 = params[1].toString(); +// return concat(str1, str2); +// }); +// } +// +// private int add(int a, int b) { +// return a + b; +// } +// +// private String concat(String a, String b) { +// return a + b; +// } +//} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml index 1554b7d1e..4a60f8f78 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml @@ -27,11 +27,11 @@ - INSERT INTO device_log_${log.deviceKey} (ts, id, product_key, type, subType, content, report_time) + INSERT INTO device_log_${log.deviceKey} (id, product_key, type, subType, content, report_time) USING device_log TAGS ('${log.deviceKey}') VALUES ( - #{log.ts}, + NOW, #{log.id}, #{log.productKey}, #{log.type}, @@ -77,7 +77,7 @@ \ No newline at end of file From a85890d958417e90564fe4ab075fdf6216cd1c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 20 Jan 2025 17:03:27 +0800 Subject: [PATCH 087/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=B7=BB=E5=8A=A0=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E9=85=8D=E7=BD=AE=EF=BC=8C=E9=87=8D=E6=9E=84?= =?UTF-8?q?=20SpringPluginManager=20=E5=AE=9E=E4=BE=8B=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91=EF=BC=8C=E5=88=A0=E9=99=A4=E4=B8=8D=E5=86=8D=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=9A=84=20ExampleService=20=E7=B1=BB=E4=BB=A5?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/UnifiedConfiguration.java | 6 ++- .../iot/service/plugin/ExampleService.java | 43 ------------------- 2 files changed, 5 insertions(+), 44 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index 374e3856a..e02ec9be0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -5,11 +5,13 @@ import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.framework.plugin.listener.CustomPluginStateListener; import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import javax.annotation.Resource; +import java.nio.file.Paths; @Slf4j @Configuration @@ -19,6 +21,8 @@ public class UnifiedConfiguration { @Resource private DeviceDataApi deviceDataApi; + @Value("${pf4j.pluginsDir:pluginsDir}") + private String pluginsDir; @Bean(SERVICE_REGISTRY_INITIALIZED_MARKER) public Object serviceRegistryInitializedMarker() { @@ -31,7 +35,7 @@ public class UnifiedConfiguration { @DependsOn(SERVICE_REGISTRY_INITIALIZED_MARKER) public SpringPluginManager pluginManager() { log.info("[init][实例化 SpringPluginManager]"); - SpringPluginManager springPluginManager = new SpringPluginManager() { + SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { @Override public void startPlugins() { // 禁用插件启动,避免插件启动时,启动所有插件 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java deleted file mode 100644 index 22ebe8b4f..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.plugin; - -import cn.iocoder.yudao.module.iot.mqttrpc.server.RpcServer; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; - -@Service -@RequiredArgsConstructor -public class ExampleService { - - private final RpcServer rpcServer; - - @PostConstruct - public void registerMethods() { - rpcServer.registerMethod("add", params -> { - if (params.length != 2) { - throw new IllegalArgumentException("add方法需要两个参数"); - } - int a = ((Number) params[0]).intValue(); - int b = ((Number) params[1]).intValue(); - return add(a, b); - }); - - rpcServer.registerMethod("concat", params -> { - if (params.length != 2) { - throw new IllegalArgumentException("concat方法需要两个参数"); - } - String str1 = params[0].toString(); - String str2 = params[1].toString(); - return concat(str1, str2); - }); - } - - private int add(int a, int b) { - return a + b; - } - - private String concat(String a, String b) { - return a + b; - } -} \ No newline at end of file From 3647fd36860035eda823fa8207b5bc6a312037b3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 20 Jan 2025 19:28:03 +0800 Subject: [PATCH 088/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E7=A7=BB=E9=99=A4=20ServiceRegis?= =?UTF-8?q?try=EF=BC=8C=E4=BD=BF=E7=94=A8=20SpringUtils=20=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 15105 -> 8535 bytes .../yudao/module/iot/api/ServiceRegistry.java | 37 ----------------- .../module/iot/mqttrpc/common/RpcRequest.java | 39 ------------------ .../iot/mqttrpc/common/RpcResponse.java | 33 --------------- .../mqttrpc/common/SerializationUtils.java | 19 --------- .../iot/framework/plugin/PluginStart.java | 20 ++++----- .../plugin/UnifiedConfiguration.java | 21 +++------- .../listener/CustomPluginStateListener.java | 1 + .../module/iot/plugin/HttpVertxPlugin.java | 8 ++-- 9 files changed, 19 insertions(+), 159 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar index fa75769049a1e0036436209788e16c216edd4891..8b5e72b4a4a93219518d66cbf05cc05a5e486a5e 100644 GIT binary patch delta 4241 zcmZ`+2UHW?woai41_&KQs(@5!p@ky7BPG;GZ-P`o=@Mz7C80#BB4X%WP!v&-CcPJt z5(Gg&M5=&*aFP38-}Bw|X04fT_L*;=GkdSI_Ss)#;0HA-V|_3QCE)i}kONDl;-wszoKk_?Ihcr`_*->3SE#gr0dg>N+1TZ;D&TN5f2awLQINIn+6Kv*u-HvB#SDNC^ z+`+FNk?5M+%~|`hXr2CDFR<;@x9Cxr<9-LBISlvB$o+w{N~-Z@>vY{4X46Y-Z7~_% zj^vH?@-C7dCQDwVl`5NJKM-!=Dtj9ke*3O10W+cCt;gN2 zx&rSA;9r3v&m#Wk0X{`%AF=<3fVTr)1fS*xe-|inh7~}mGn@y?p5aB1BI&u`*{cf# zUp+^A`hryMBXI+r0|1Pm0Dv5R1IURtl!2m*z3$xb@VVmb9CyIPTS8AW{#qt^FQM$Qa^_ZjKVuCUXkL3-Wcx z1iB5Khp!J8c^oSKVzYX7b@A%*$a?R$E19;zrYMJj?0~mDhqeP9#V5J1s6Lq-^~8yw zT=Y9rpF$cSs|Laq8V7+K=HKEASse>|Y~efZR#Ghfd+z8jitqjMuBJTMxk6)oleeW3 zo%1Msf!jXHNDJtKUQ<;c>V3>QpFx*|Hbbz&)J<|n@(CI?c7>q89_!1#yRd#8RO5o=g6+k*tMJtFDey2 z%5pB<&J7tHx=kk7o6BF7R!P%KI#N+yKVvMlw4kzX!g2dTjOBW!Nu(ZnF~6Z3#mYfF zecpX*kqlkz*54Gi7fVy*`>5*Me8$V~3yyt(6;_KgBcC^=sxA7R%P{s4&Ih|)1HQSh z!d#E~V|zw8-zqEJ+V1b{+8@o{-+!L1&%EO2cANKjxOBi*NepBv`WZ-zb)Bv?C& zMQ`eJAO%(!6x@V=&?ZTWE`R$hQAq5m{q>d0@?k{kMtD4%*+PbHZgYYl?MPtE6w>wC zT)7!`{+=VE=%$Uqix@yF?xeVww|CQ#b2mvQ=$_+?6QWR2k@mv+2bbGVk`9uXFXrpq z$8ETpBj4|iR7&crZOWhfih{+tgtN!7j*IE`)wIkHXf&)9NY1BRb21% z-UTA45}auhN!RZMjd8tecL`@3FjbzI&hD^yv>VF%GKTg7u4f-7u2&nJ*S>ZP3a1&+ z-+zl?-T<4zXPdC7z}|C#{t9IX>n~G74k_DEng-<%Ng6SeR;IZr{|d?D`DK({BW!!? z<9>qd_QqCA(*AYJbvx8`0R`^Qyw?)4%1mfSYD3%t_pX1bnJiB_wu%{wDt$jYX@nl}BYl8lZ?1Sh zJ0`Cun6X-dVL;EDpy79e#6xF{aHPT+J2)%D>=o4#8+xsmrO9RDC2X|qv#8&rVk_5{ zm4@y(*^QzY`<|EgW>Yema92cc4oXzAXvWrFmhW?UcyU;ZKW7|HKoh98WSn*Cr2VJ8 zR41Iehx?lCPys3-QEbys&`dlT4{_k!8At`Th^mbCLJg!?d!LW3gbU%HQ+h{|feaSC zo=m;#Uw&O9CdWx3=%CLyPKYv%sB6kabs2%mRwzmByrNA-{j5Bd1c7rWfq1?~=h!`h zY4U&dd3w`miThH<>Q@I}ol2(R@)r`*O*MJFT|tSoD09oiNCyjF*Ul;WQTj{O)jb%b zD)9-$yK<&LNm_Erw_PyyoZQj)CDKN5W`y!|nW!z#XXtESW8?`mtyV|r0L{GaJC%($=_ohG<)9tI_Qa5N4kB19( zdPCYuc(B$x$S;p=j?SxBk7yor7yb}M_H4>T=pP2T=f%<<5adT^M!c?-YXt2yG2A`D zy_Fdha#CdE%{SVa!nxbnK9}!Q9yS#BD?{T~?cH-L2&^&ukT&WX7FFT#Du6`y#eR zsEA3O-JhFW43ld-SD!gZQR8JFy_X3Ms~=H+2_B$ba-Hub+s3XnqX<&ef^uj}^ffTL8zxpgF5gQSrT^vLvg+xprl5$6RIy!S z!AMv+%UQ^xm%b8>NL%o%k5gVCv}cXDQ7Zyl310f~aDjr6S5E`!W?kjtcz}DF%-3@2Pg_O3F>Z^*1@-luv2;q3mysniAFq#gSa`A8Ab&q%y zN|!D51txV9Ii75MYvKQPO$ceJ6F8$2^19m`ypXwI`00mK-C#30g*M6|AxHj+SwlBBs zCbxv4mLY=Oi&4RHC5>sJK_>y_ zgULW0Ij9=ODZGK{)M%G zcVpMRWZ0gCOfNsW#*aAqoU}A6n{w%WI=^C}BdF*Ww`7iecKKy&2TNEjvXnQ?KNqIm zeqOL_Yf3~{-U$??!Iwjk?>z0zBF%%6etPgW`J}PU2=j z%EKoJSOUZ4LgaYW2Wl3tp^J(I)NPOOICvaBia*)zxvutjt2gGs8>ApXD7~UWJ|+C% z=K#vS>2T-RdtZr@x^!AD8?oPs*y3MlY-VlgOTWuSvF_JOt zCab96z`e@n(RMv}>YcSs+(`*ParEh)3UV8ES+Akgw*_Y~p;}^6zE8DJM!B+9m^>@D z5gw?z$1PV{QwFV&j&`Q6wb{*iGg#A_bVHFY!S1#*33YM4O^OiT=r0?!L|L_}_nm7} z11uWP?MMpwq|=Ac{aVY|IPF`-RaXN4eH%{+&+2=@)xgI*h2QpiWec)u$2Fb`sP zjjftUkGh!S*p6~?^)qx4zafv6=plnIrU`V?=vuk}58YPEMM%2R#XJisY|d?&oc!bu zZsWg3npdaE*LB5gBDTNgai{>ADu9%4Bx!K@(~#xm+F=~FGqIO6pK2NnyzM)4c=Ir9 zB&d`U{2B~N=1$rqPPL(ec{y=|{$z&*@@REHZPub}$J1p7r3e-#Micjq zlnK&k0PXxGOKJ)0|Ju5A)kkjCI)lB_!Z1@ciW8T955^qytnODYLfC?TqfCuLy6J?* z;e}+ff{*>4n+8wSEM{Th>R-hKi6BnZN1TeBgwtCOfX{;)ps0FODO@vPv6yS5P=O<`P)z~+)AgpnUtsgKjJ7}r|vci-rB@}RN3 zz2fIhC53){19D`w31DrJKsTn-Qo|etgL{(5T*ci{$6NIZr5O^xrs=R-?Y6-}S1Y9y zREZzzPk_eM`alo^_>br@>=E0D$UW#6asUAJKMucx&HwG7 khWCThoc;gb8}EOZ1(6`OQ=%C)Er1qaO$q=kv;F?~FHk~mHvj+t delta 10401 zcma*N1z1$y7B)@|-QC^Y-KlhUICOVOjdX_$-CYXO(%oIsD2#w0Qj!A72Y7$p>;2#7 z|9xkkIs43d-nI7GYu7t_ttIJTZ!~o!SU6;;$19?R;WZj9T6hbCA!W6G@Z^K&`D<}9 zkcu-b6>9j^v-Mz<7b>fAsVj8*Mb)@=x+^rUu{tnO`5NxG$(doz$$Fm}^78|=^TfFb zUiPIhU28bL*mO*9EG3%f$Rjni$Hxe6kdfAz8Tsjj+g{Nq=cdi$cZzDX?B4utd#s4r zMaQ;@n?_>7$LI_O)-g{o+xRCn2Zrj7r~&d}a0og)j`14}=&4@qNHqK?C5DbvY@@gC z1`O@}Eb`~@o%D|KAlJocbAy^%C*2xx_ZGmO)A4Tp>W`E@Wj0lj{#Dgmqa*s9pHTm9 z?L#xc?9k+}kEI$k{Zr`+&H7Z9L-W8scmuovE$~zlz=+~J`N#0dQUAIzB;!!fTevuT zy1O_!TDf!lW&1BA?E{j=$<5Q#-PPhhU=LON1!H-DG5-U5Fl=pS^M65;{y{t1SvhsC|B3X2WJ>BXo%m`;N!L2t4gF7 z(D1Y*`jjd3{3`a!i0Ck+YZ>2@%N*=jIZTh4+gXCMXLwZ#nJ^1Df|CfbrRQ3nzsg8A ztfDqp7*rP?b_YfmvJWWHcl8C92MkRaCmHS&#$w1V$KoC6dmp4o#J(aGJGjbW0d< zM0~@njzt#s782V;YV}dAj@Lq3#_nLEIt#EcZn!Q=>W3M>a4TJ-h_7}7nL|=9$&RY` zYv7=#cXgZn+GMXCOS?b%Y3)4gdWWn$*&S-4Tv-Ef8P_jGE6F3Bi!_Ju=KL3lS;8lw zL(p{bemBUEH*h!S9-0nxvs!xkPBjR0wea(x_=??(_xE)^veV=;6*st2Fe^QaMK;5;OT#1dP@atILo zqT(X|fYK;S0uJMG6XYou(ewwIp8Uu~i;D&=L%ubsGPLf3daiU^upm{}2! z4cH5$1tnx+!`QeD>rxBLILY8EIU?)C@3)1tFvMaJ))@D3{bzKu%<-)ZmsffbQbA?P zX@{B!Es*nBIxXK263+uRuwpn*#enh}mh&2WG1~O}1uhEe8x)i2NT3oTm+0v|Zss?) zj^$vJqJ=|iU*;2A0s3XO?^ggKvb~ZJFj4{(ww}VZ`+i*9VX=voVi=?WLEG{{rO zi#1OttFRBkG2D8nY&`&$pfm&og95eBF-8QV2$-t5du=LmdwrM_FE{Cky2BJ9!gz4b zh}}(M)NKer#i7jb^*BI?I43D)!eJ_w9EC}Ft@G-UmmeYV;1=c$-5xi*#<9SRgs-+`z}QPE0R+E^ zpdBG+*I0JzFm1(EA0JPyT7Ex1qvsPEXyr!NrGynEML%_!p%-q$ctN4ZF&O8rZCY^SOzt_9T=)D+-=CX6eDtYusJ@Dhy4ub_55bSxzVo`u zY`T_KBD>tmuAx?ot5S04V2R6@Kk~v6VfT>tvu=jVJX}x5oj+}dLdyG$G8vBd#N)2- zS(MxcV-rv6!n((<;rc}wjGl{tlL{JgvYsk8gSA>Dk*WLZw>GP&IdElGILN{E;Fl$s$q1n53;Y8Xm zpPjNMfr4M0^M*yvS+u+9V5Il<(4KV-YgW+Ge!8Q@zr#6mv2g2WWBnz-Jg_^5n??XE zp^8p@Uzf$N%TNdkBi6d+lEGFhJyFKG+zLHZu|gfBcaX@Uc-3|4v#m=aj9*&o}z}8Yed-WC9&y0 z7h4Ai;KkT8BS9dv1Hr5VS){V@wKpu^O|jpVovcAfXX*@IE#l0;fBz!?cBqVWrbuzD zTM6uJ__a?N%1T@fySp37jyYO!gDo?o!dv2$Zy3tgOrcFH?GBMA(Ugx5z^Hq4G*DAb>?Bju$ z&JL2eay*flc^3F(V&%t=gEb5&U+7H2FiJ;BT4;?u%34b#dytY6eyh@_TRD0=1N^|q zVl53NJ~-ll*-!*|n&1I9Tb`~)$Q!dLGJcPvU>d793h$rOw-RrhEytp|&s-C#N+ zzlCW;Mq_XAW3-k+l3uaHw&BdccEa5d9~cz+GGPL9IETNiA;7_FtyCJ%Cn%F9&$#qV z!lCwTO1O6_GJt}k21z4(RKJqSNVPUIT3vdiTiN_VJWV}>12hIKp~2LQyAN)~WTJmM zNj-LF?ZFIAc!ARIXyGaXO~V;eqhqvej}{BgTBYO6xeBiz4_LZ%6unbKtjwq{Jwc4K zt>GE_s+#pB@7yHT263XSen~I%WsQXu;`z2?@B6#@(GAf1Ug6;D1D;qt-csl*q;rAf zns=LM&h8hg_&yoqW5#X-J6I9@1I|p#biFXdFdS=`O{>Nq`Ec8Ez|PTrshh~?FwI)~ zCArC`a6bvA%+)Gl4BY z1h$lplb{KJBb@GPMRhsxFwY^`ho!l_5X8Yxr1U35aa*y^Fi)vuJ3ZZVhh!IIz0orl2XX7kb{mBi2j7QdbJ5{ScfSp z>l;QBP6MZvRZk+I{5fL<0n*DVDsQHTNai7IdLaVWSZ38#X7$XWRp$eDsI;}wn+!)? zuEbh(y}D)TLGU8;iB})&XJLV&VukYVo|9pv6xdqrhIBp|Lr}hb9<3ou)bv;5X%Ot= z%s_hl6Y-mOe#hR0e&U@!<)SNI0-&IXA9$z8;~e=zSAUaRl?O`vFi{?O?(a#`q_^RL zqk}6Uuwf~%UxviSX2N0ylibJ@OIg9BQ}|uuxl$Ax<4W9EgD_%!? z7;9eri`m|t8=HH$erI`@s&C4c933{+XVPbkPZCB9yuPs=aS~R0-fvd9Dmz#t{2GWt z7J}%lviq&)plb9n0^!>yYx`O z@1wC#0WQ9=JbeU zQ?ZCG_U4mW=LFCj)NrzHabLI1m>u1JiQZ>}9R=+g4>n%Aw;SwCWobAS*nG8L!?p%< z7+$F?$u1d;*Mq{Tlmi0VUZS-dG`&BMU56x4`I5EHIqQv$bCu$;-0%0%cmzeqsXoK;TiyTci&(Tlc(dE30X8rv|HbgIdt4}j*VKZBnAaQ*s2Up5Tpf!E8C`*y+u)s zT*dMAo9aBM+IE)Nju64^BC{-H65mSMU{96677?s%L-pjNqstM7e0F%1?w@} zmkulp=3P(SLJy_6ub|-8Ci>>@#fZ3UEx6i%eMBlVN zcA*dksuunfH}s!1Z(%40L0{6469#O~CTm4tgr0#6I6{is9!AlKgzSq}#J7Yf0AjpWa; zs7eIEcAH(3I&SzELgh^>gD{@k`S1FucZF}yTu!(Yu%?z#^dIC!N5YQN8IR3<;~`uu zDX%@is%XeMCq$1VQWzh_u4ZC;E>v00d4pJQsHt>8tCGHhT^&QOm5fb0nl%UJHBwEt zowT)69D{pq$2Jf4><~3B()kd<^c*euWC0BFtj}Sa6)v)3vZH-AW={i5Zaj>S|2PyF z=KvV8+7XHyDd>2GM1*}^TuZ>YPceW0l~B=5h&o)>j2c#Gf09}VT+(|<$;A?A4$?KhY6^};_EGnncvJJ&SjAxJB+d{k_REix?)SKV*vQ;F?&Y&9;m(v$79}+Y**1f6 z&ZS3H8Hpki(zQ$(KOmL%&5YK63*T0Kb}6k@hh~FQ&^53hb#KmynhhVj7 z3GfyuUiwTIFH?Vjd{$Dy^GxON#Jl14C$wY&d|Sq{I+T{Vxyg0`V+f5shZp_nzUu&Z zv4q9$nfYtxgx5Gj7V!K4_%Sq!3q94j%n;2C; z(r}~gEFePkBOZCmTaE3R0=lMWk#_O`ew`*=8-fg?Jkv5I!+t+~{@N`R9ad?{f@RhC zdN^r<+9_CAw-?aChfYGk{RH$TkPSUQqdvR3lOZhCbID;Rq8NuzYhuql zfsPfDnD|E!Yrio1$py@GWfr@zlG@aXa`FfD zKu|_*lhmNRqoN24UQbi&yJzUD)U{mcr)5C(81gugHoN5@M{6wsi}o0@7UdURY`OHv zr5U?>TdG8t@+i34WYyvmuq4{N-+Q>Tx6-m^>726D%=Nx$)`=X(I2##8;DbfWpUd$W zR(!g=!BCfo9t&X}*AMPwzARnZpK-ixu>;B7Ehp*%^s0RESEoLcx-iFkPozmr+Sju> zh2hm4IRUp2v`J+n8ALlXB!N0EC@4k|s(2=Xv;~%q8@j1DCtsj5=k97_Xx{#Snd{J6 zb@QXa$aE812aX2)lm(pHB*ql);pr33N6=~|?vl>tO8M23O}@x71fyl_o8T3UXoK9) z@>tY~X*g_QljD{m=~f8djIqs^*V2z>_MhuEcW!_ecj4t?B|;LOhywfU4-!Mc@W@jGcekEs-_as3T#w4iH2|1av%4%d!i$Nqm&#e!?RURMu)SO*?7RJLL0m*6Dp$di`?JkXR zU^7R!i2_uZ4ZqlUN1h=$!7Z`0NDZF37E7w2yJdvLwDeD=y{@Q~>o{?-UJ>Am-1r6` zz~eH=QE)vKpJ2f?zd7=3xQ>FOj}6)MEriauvS-Ss7Wq)A4gbTtB|*J5I|2|*iX!!# zsu%eCn$2)4onofHDRxN`NAI}Xn-IMUUpi+TeW5FOwO@5nr;$4;vP$jle(524lg8Zx z5RHA?K#f+8Em~HXeOl9ENRu**xci9dI5!*M9gev_hyKQ*h#<;iF7_1+-r zKH+eIiWU@?5=12bShcwMA`OsvvmCgoETms_3PMtq_23A+%u6K>XDT;gmtY<*I?u zOrVk)P0}PZW^y@0#)q{<;}W$z=f!>dJiOR_#{=8NLx5FXz! z?{42Bj;b|TLluIa6)?zmgzpUZyAT(J)~TSlf+(Sypq8-^+5611cQ8M$Lt;1}N{uP0 zoNzU*JsVD!BZZB;>)OmidM7#nGp$pv0GStdiwhF6MC&S%qp*Qp*O`3Is9H$o7!=_`tgYpNjG+X(zb zo j+eJM@)>qijT{#1_T_{u&D9KPa1)Im8cnn95fR^&}Lw_TrUMccRDH~)0KPTpg%vl z+jo%jwQJIf2sWq$I!H8F&?o+0dY2EQ_|BZp8XqhFP*eQCqpTk zTG}RqM&kaqY8-Nv2%s=K!;t(aKWUe)b!jifOL+ax#TC7&x6xGpy82{2NIK*mWRrJ2LY@MqzH#20RT)^>o;m zR%PmJ%j~&QJadHxo{Da?6sIVj0@JWedZbg3sDjw#=%loLRIiNY&$<`7AT`-+KXEm9_b8STO+-^piJZ}a1anG`2c~qA~3X&+|rwE%) z_?#AUNRxqH-`6b+?Ry9zrf}v{<7lU|O@;AsSXHE`U4HOov|-hF z;(5nnKL1-<{??1@`%e?=W`5K*`648|JH91v)fawfP%l;%5hh;CM%7{OFcuMHUk_UA zOeiRUgq({LoV1T)5381`*w6NI>qW4<%7SVXg-VTiTkv)O$<}FjfCb&vB~~BU*8@K7 zb0Vw8N9qGR`-#~+=ycvE@LE^~(sDu-^rjOEu84QphH{>uzX=iD5ISMD&G}ziGW*jj{TEcsG~2l5U{G0AXT@| z5-?f4akSgmi;-=R_I;V~&4o-tmxn&RtHoy1m$UMw6Rsuh)DPucL~ibQwfiMjdPs5x z1ZP?k1$CmlPbqT^gdH#b1fgx4hO9_V8W^L|x*h(E(neJc;)$^Mk)i%(A-pKl?{-oN%ebi0aqJ#>wF+CdtSHi#9>L42q)`U>)4Le3%}HORTYcB7i0h^J zEvuKF@`5^Mgp8t*t5CqpuO9lijHJVdATehL+;?h_DHWhb4q<1XqCR+{}ufy9|PH@mr^U^IonXho)mI!wS+~VbEyN(_E09mJS z=qx+GN^`2E6!q{OaB;^lZ1}++t3rO(e04M_*kl!lTL9NzT`VjDkYU1$eG9r6LF%6H zqkdMTG-A+n(GA7dww)ZCG&>You0sqkU9{q230k;Z`PCfOytcs*F43$+ngv7k{&5hw zzTf!I>+ghJ22nJ@kcMmV+oRzt>yE~}IjChcij`KxNqwcQdUF4nsLqAeNLA!q(?)3p z66c{preGcpvy@rIo%8mnENAa15VBvO8-0?uR@X^C_M%vHeuJ~cbt;s|)_aTVz>g&v zTij%Og}lOwgjbsOrnz*^>{JNbTo%2#VeEd>b^Ft2vJ5bXl*lj4C9WN8T*BAA4!UcUbHuwSdTo8Zf2dk##7lKz z_V@Ya_Z!V>acC&0)Q9sKmWQJo6*+Aww&$wy93HOjcFs0zzvGWy?m$mF7iTsnD^H*$ z&=Uw^xA$;y?o6pugq6aKxD_3A_j0D_(Itt+H5Y#FcBBHauW!iQ(2_x{keh)}zCcC+ zM8{JSR#OiRkM5kats7$kq+)57P(>sfB+j@dJeA^JqV+u^afv@{iK}zQ&#ei;7yRJR zRDCgKR&}_ij2EMXO9*qSiVHttL@2M~TC@X-r6>UqRD7-PWnnj&&ilj_#VJ#ApzVpQ0?jPFCZs0W1a4x>r ztSB9cJrU2F$e*_6m`|M5Ii-{@=B}kZ<&!cY|B^RqmD7QqE;%Zf(}mYX{Tg~KEQfag zYl zvL)26aV;624>-&qD7;c&Nrw@t)ar>i&MG{tfJkUc<{fC~elS!}(CeJLxlToE09_D%ljp@ z-gXMmuiI&fk3TODB)U7$irT)%vkukBleHEt_6j=Ee$ z=4qJMSnkp<@{2~LLu>dWtli{%&a?frE>#h3JA^{%c*vJc62_9|CGnuoJ!dQQ8Q6{mUVl)B89-n^l4v8oZP)BL{im$52li;lm}&OjZX(1+EVA%D&Z6q6OqMiu+$n?00TM8i*AAdfrsNp3A_s@N z?bHH?vipzzE+-mHJjZ-r22(f`fX&RsJ#m`jL*gA4)){VOa!v|dOT-#ufS=vxH?Le3 zsCiU8bf3pC*KZbU+>Xug5_$$`2b3?|+yNP;lHpQqYHiJhS^N0-^( z`r}+@H)ne;oo^0~9ZqiMJ^)Ab1x|TKPTdd1B$EnPWHA?29WzvfU1ZG?y~5ev&@ZsQP-cOxuJzWXO+0cbvOVZXQ2nlX6yL4ZbJ?~R2SL3kn)O5- zjcSF5UJhUnXWceL${rS{B~8M3-L7GXLFb*9{Ka^a_w+aW76-q16-$sr;9@KOX8m7f-E6tbcZGNu9 zPTIW-=J9UMf9XD21y{x_T6l9D3GLWD;W|9&`7RwK#*+-b|C8$SJ6vVj%e)o{#v{=K z^& zRLaH9jvvbkYu^kx^R}8e2soEeSAvE?!G-;kZUnv};r%<`2rNj-_mqO;N=kxH|FAt- zI6ow{K*Ri_^q8$vNJ;{&0PZ9uegdwNlEAn^gQ0P7z{q5%Pa+~R5}5o)5iwZ(LG+LT z12%gQeRvd+gR}l6s(cV(z&wez$*`#ZM}E(rWFJhZLn-wqsK9?j`Tpy@{z~Pc{Yy9X zNtgGZv$OwHd`!>zgMD~-+=_o+kCiSxDT@4~_{6lnA>MwKJ_z&h}z%AscPxby4Uiu3tM)+8-(w}z!?{L$9 zSNzvu=U?_P$RF+fJACy&4?q9g++A2R*F@~tPj^^alTV}R|E5U@pHGC>~9 zF+6zbffM|>N`gHf#t+cd)zQx4iMO%8baMPh`w{iuqvhYqm{9lkp{(E}3bLp9QcFPs zQ_Bh_C!qo#QT(1lKOaPgk0NofJ|!yU|A(0Td5gypqQLe5lm-t`Vm$TK)9Uj8h<^Ag g{srvgdH^cpt1AH>;^, Object> services = new HashMap<>(); - - /** - * 注册服务 - * - * @param serviceClass 服务类 - * @param serviceImpl 服务实现 - * @param 服务类 - */ - public static void registerService(Class serviceClass, T serviceImpl) { - services.put(serviceClass, serviceImpl); - } - - /** - * 获得服务 - * - * @param serviceClass 服务类 - * @param 服务类 - * @return 服务实现 - */ - @SuppressWarnings("unchecked") - public static T getService(Class serviceClass) { - return (T) services.get(serviceClass); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java deleted file mode 100644 index b2a9f0360..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.common; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -// TODO @芋艿:要不要加个 mqtt 值了的前缀 -/** - * MQTT RPC 请求 - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class RpcRequest { - - /** - * 方法名 - */ - private String method; - - /** - * 参数 - */ - // TODO @haohao:object 对象会不会不好序列化? - private Object[] params; - - /** - * 关联 ID - */ - private String correlationId; - - /** - * 回复地址 - */ - private String replyTo; - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java deleted file mode 100644 index f3225d08e..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.common; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * MQTT RPC 响应 - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class RpcResponse { - - /** - * 关联 ID - */ - private String correlationId; - - /** - * 结果 - */ - // TODO @haohao:object 对象会不会不好反序列化? - private Object result; - - /** - * 错误 - */ - private String error; - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java deleted file mode 100644 index 620b00763..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.common; - -import cn.hutool.json.JSONUtil; - -/** - * 序列化工具类 - * - */ -public class SerializationUtils { - - public static String serialize(Object obj) { - return JSONUtil.toJsonStr(obj); - } - - public static T deserialize(String json, Class clazz) { - return JSONUtil.toBean(json, clazz); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java index 2cb688cfa..96ca83369 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java @@ -1,22 +1,20 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import java.util.List; - -import javax.annotation.Resource; - +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import cn.iocoder.yudao.module.iot.service.plugin.PluginInfoService; +import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; -import lombok.extern.slf4j.Slf4j; - -import cn.iocoder.yudao.module.iot.service.plugin.PluginInfoService; -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; -import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import javax.annotation.Resource; +import java.util.List; +// TODO @芋艿:需要 review 下 @Component @Slf4j public class PluginStart implements ApplicationRunner { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index e02ec9be0..150051ce5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -1,46 +1,35 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.api.ServiceRegistry; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.framework.plugin.listener.CustomPluginStateListener; import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; -import javax.annotation.Resource; import java.nio.file.Paths; +// TODO @芋艿:需要 review 下 @Slf4j @Configuration public class UnifiedConfiguration { - private static final String SERVICE_REGISTRY_INITIALIZED_MARKER = "serviceRegistryInitializedMarker"; - - @Resource - private DeviceDataApi deviceDataApi; @Value("${pf4j.pluginsDir:pluginsDir}") private String pluginsDir; - @Bean(SERVICE_REGISTRY_INITIALIZED_MARKER) - public Object serviceRegistryInitializedMarker() { - ServiceRegistry.registerService(DeviceDataApi.class, deviceDataApi); - log.info("[init][将 DeviceDataApi 实例注册到 ServiceRegistry 中]"); - return new Object(); - } - @Bean - @DependsOn(SERVICE_REGISTRY_INITIALIZED_MARKER) +// @DependsOn("deviceDataApiImpl") public SpringPluginManager pluginManager() { log.info("[init][实例化 SpringPluginManager]"); SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { +// SpringPluginManager springPluginManager = new SpringPluginManager() { + @Override public void startPlugins() { // 禁用插件启动,避免插件启动时,启动所有插件 log.info("[init][禁用默认启动所有插件]"); } + }; springPluginManager.addPluginStateListener(new CustomPluginStateListener()); return springPluginManager; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java index c0802d7f5..4542868b0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java @@ -5,6 +5,7 @@ import org.pf4j.PluginStateEvent; import org.pf4j.PluginStateListener; import org.springframework.stereotype.Component; +// TODO @芋艿:需要 review 下 @Component @Slf4j public class CustomPluginStateListener implements PluginStateListener { diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java index 1d6fcad92..54d9c7c2b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java @@ -1,22 +1,22 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import io.vertx.core.Vertx; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; +import lombok.extern.slf4j.Slf4j; import org.pf4j.PluginWrapper; import org.pf4j.spring.SpringPlugin; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import lombok.extern.slf4j.Slf4j; - @Slf4j public class HttpVertxPlugin extends SpringPlugin { private static final int PORT = 8092; private Vertx vertx; + private DeviceDataApi deviceDataApi; public HttpVertxPlugin(PluginWrapper wrapper) { @@ -28,7 +28,7 @@ public class HttpVertxPlugin extends SpringPlugin { log.info("HttpVertxPlugin.start()"); // 获取 DeviceDataApi 实例 - deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); + deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); if (deviceDataApi == null) { log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); return; From d608c4b9844af070a2e45be6b6f20f5c5e4e3660 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 20 Jan 2025 20:02:46 +0800 Subject: [PATCH 089/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20HttpPlugin?= =?UTF-8?q?=20=E7=8B=AC=E7=AB=8B=E5=90=AF=E5=8A=A8=E7=9A=84=20demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 2 +- .../yudao-module-iot-http-plugin/pom.xml | 2 +- .../iot/HttpPluginSpringbootApplication.java | 2 ++ .../module/iot/config/TestConfiguration.java | 34 +++++++++++++++++++ .../src/main/resources/application.yml | 5 +-- 5 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 0a9d0bf45..01e2f1454 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -67,7 +67,7 @@ 3.0.6 1.2.5 0.9.0 - 4.4.0 + 4.5.11 3.5.0 4.11.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index 22cb43968..4658a1f6b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -127,7 +127,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java index 6b553f92b..2b871cade 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java @@ -5,7 +5,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class HttpPluginSpringbootApplication { + public static void main(String[] args) { SpringApplication.run(HttpPluginSpringbootApplication.class, args); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java new file mode 100644 index 000000000..b32a1f59f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.config; + +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin; +import org.pf4j.DefaultPluginManager; +import org.pf4j.PluginWrapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +// TODO 芋艿:临时实现; +@Configuration +public class TestConfiguration { + + @Bean + public DeviceDataApi deviceDataApi() { + return new DeviceDataApi() { + + @Override + public void saveDeviceData(DeviceDataCreateReqDTO createDTO) { + System.out.println("saveDeviceData"); + } + + }; + } + + // TODO @haohao:可能要看下,有没更好的方式 + @Bean(initMethod = "start") + public HttpVertxPlugin HttpVertxPlugin() { + PluginWrapper pluginWrapper = new PluginWrapper(new DefaultPluginManager(), null, null, null); + return new HttpVertxPlugin(pluginWrapper); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml index ea2234f83..9056af48a 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml @@ -1,10 +1,7 @@ -server: - port: 8092 - spring: application: name: yudao-module-iot-http-plugin - + # MQTT-RPC 配置 mqtt: broker: tcp://chaojiniu.top:1883 From a152f6d98fe7295f8abd6b7096b388f0ca3dee42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Tue, 21 Jan 2025 18:18:28 +0800 Subject: [PATCH 090/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E5=88=A0=E9=99=A4=E6=97=A7=E7=89=88?= =?UTF-8?q?=20HTTP=20=E6=8F=92=E4=BB=B6=EF=BC=8C=E6=96=B0=E5=A2=9E=20HTTP?= =?UTF-8?q?=20=E5=92=8C=20MQTT=20=E6=8F=92=E4=BB=B6=EF=BC=8C=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E6=8F=92=E4=BB=B6=E7=AE=A1=E7=90=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=20EMQX=20=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=EF=BC=8C=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 8535 -> 0 bytes .../yudao-module-iot-plugin-http-1.0.0.jar | Bin 0 -> 10643 bytes .../yudao-module-iot-plugin/pom.xml | 6 +- .../plugin.properties | 6 - .../yudao/module/iot/plugin/DemoPlugin.java | 77 --------- .../dependency-reduced-pom.xml | 81 --------- .../plugin.properties | 6 - .../yudao-module-iot-http-plugin/pom.xml | 157 ------------------ .../src/main/resources/application.yml | 12 -- .../src/main/assembly/assembly.xml | 31 ---- .../plugin.properties | 6 +- .../pom.xml | 2 +- .../src/main/assembly/assembly.xml | 0 .../yudao/module/iot/plugin/EmqxPlugin.java | 7 +- .../dependency-reduced-pom.xml | 43 +++++ .../plugin.properties | 6 + .../pom.xml | 70 ++++---- .../src/main/assembly/assembly.xml | 9 +- .../iot/HttpPluginSpringbootApplication.java | 0 .../module/iot/config}/HttpVertxPlugin.java | 7 +- .../module/iot/config/TestConfiguration.java | 1 - .../module/iot/service}/HttpVertxHandler.java | 2 +- .../src/main/resources/application.yml | 3 + .../plugin.properties | 0 .../pom.xml | 2 +- .../src/main/assembly/assembly.xml | 0 .../yudao/module/iot/plugin/MqttPlugin.java | 0 .../iot/plugin/MqttServerExtension.java | 0 28 files changed, 103 insertions(+), 431 deletions(-) delete mode 100644 plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar create mode 100644 plugins/yudao-module-iot-plugin-http-1.0.0.jar delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/dependency-reduced-pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/assembly/assembly.xml rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-emqx-plugin => yudao-module-iot-plugin-emqx}/plugin.properties (55%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-emqx-plugin => yudao-module-iot-plugin-emqx}/pom.xml (99%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-demo-plugin => yudao-module-iot-plugin-emqx}/src/main/assembly/assembly.xml (100%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-emqx-plugin => yudao-module-iot-plugin-emqx}/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java (82%) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-demo-plugin => yudao-module-iot-plugin-http}/pom.xml (73%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-http-plugin => yudao-module-iot-plugin-http}/src/main/assembly/assembly.xml (74%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-http-plugin => yudao-module-iot-plugin-http}/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java (100%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin => yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config}/HttpVertxPlugin.java (93%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-http-plugin => yudao-module-iot-plugin-http}/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java (94%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin => yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service}/HttpVertxHandler.java (98%) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-mqtt-plugin => yudao-module-iot-plugin-mqtt}/plugin.properties (100%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-mqtt-plugin => yudao-module-iot-plugin-mqtt}/pom.xml (99%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-emqx-plugin => yudao-module-iot-plugin-mqtt}/src/main/assembly/assembly.xml (100%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-mqtt-plugin => yudao-module-iot-plugin-mqtt}/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java (100%) rename yudao-module-iot/yudao-module-iot-plugin/{yudao-module-iot-mqtt-plugin => yudao-module-iot-plugin-mqtt}/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java (100%) diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar deleted file mode 100644 index 8b5e72b4a4a93219518d66cbf05cc05a5e486a5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8535 zcmb_>1yqz<+xE~%$j~9(f`BvT#bS>K7-$W{Qhy{@>@klOM*i| zRhCQr_b^OA{$-eP#bIvm<=-+$007aS!&D?x6=Y>VTAV7f+A)3h9e07y?byAWen`&( zg|t@C4*-eutCP*a;>SBt%qD$% z`S{#N$_BJ7nH>NZosRaQQd{_IR6nPV+e{`pipTu=x9*SSYg;mbZ+o|Epzm2Vi6`GN z@$uCC=uoy*u{hb^^PZV)^FZ0s$m&U7U4fk+($AUyS|F6mnVZ@FQJP-^uzv(tIhZ*> z%$@%s5dVJ%dbvTs4*w8N_E+I{4iGn6^M625{sYR&!Sx@I4F7_3v~_!IbzKO|-)<#e z!9JT!3;^Ka<>c=DcLegTu8un9&aR&FV0(zIxihDkE!f4SMOWXEsE7Q!x7(m4c~HHf zu}h^bPV>t*DGYiY%)&rS9RgX&&h~Jz=DAraD|d_34Sd#QGYpnafv1#=!G^;MszFgL z^6wQ_=@Olps;d+W_bAxCR1&i_OJmv|>#iF>5(gBfhFu+w{SPj_$zAOCT+E+x1oSwG zgaO!yw5&@c`K7kP?icl_EcADt#WRR9k(C{jC(&g+Dhca`TIb}+N~j~SEOA6YI`eRl zdz#3u6IbQjZbs&jvT7uKmS9U1xC`$_EX^`Z$VLA7II{=Y7o~k}hOTDU+~;e!P_gjB z&UG&aV@R0C(5elnCXOz}BaDv;wzErIB9j>y1D(=Cz`Nid%rqS`vhjB(M9Cjm_;kQ| zG8>sJ!*iLdBR^{_jJe><<%R1{U<6CK+SPO^vAu~MUUoV?piCCto(6WK;3O)Dhz$e7 zy9pw-_d(PiG8h{5m9J%OHR1XQ5@|94PMN`+jW6KoMvGS(4|Kiz-93GS-9OYZ+DV9p zg%a6L?c8nTu3)jP%Yxh0N#7fN=V3_39F#Uql}tz~gbgxF5e0V%7kQMPsKMCcr zrYINAoaX3jU@MCmkXsA2hH8ky0La41Yk1&1J;j>=R;kBXri+-MqM%OXG|HZkyVt~3 z7)c229Umlq$z({}EMMMB@C2LYLy~1~NiU)F2M(_}VzwjogD;j|jPhg6x(G8%bId}@ zDr~=~W-kH+QvlA0oKF(mdw1#nOuuGtf52?9hJ|KFsp^I!PK}KHh^E2UCjQq{23a*h zsJ=v7Si*d+d67#?=1v-_FAZ@pjXdpH3hAVz>K`{zXuE<^PW8>hKeq3R>NY9)OtM!%6lKB6oU1acT}P z?cj7)no_eCf+9s=+ZPr#ZCB^b5oR$AT`t4jam~FOxHJfm76UJVnDF@`Pk4Pr2SKNT zXytoCiu>V@$!3%F@h3X6K*Stu&dB+*LvBxVqoa$vE_w*zg4H|a?J;lInoM!yZSpCUN24`Y5hIT85rFLRSy|)u z+qgFkp++<--4MNvPiDUE(YYe0bQv511sx1PL#{-6O05iw8PSy0Snyom2E8esTuGc) zQ5czhun25xvOK4}QqvlDdEz80aK!qAGRv$a{m=@JI3enwo~J0CdYi^VkEMK^9_vA0 z_Vf;NtN2%CH0a*r4f@(BcGa#(*ABk7WgY5HusG2knK!ECo(k0ABAmnmUiq)`mPA`6 z&-B~c!7~&b6M(@@G0a+8&gF8f)}p1&6LcfH#`y5&k2_Vdo*lz68VlZvGdFX!q#6oe zNKg4z>1P&wc?m&C4hy_3cmhH^cT9bMcMHeJJu;lg5UeNC*0HcPDnPk^2fX6>jNjsg z?D)!7k~wx;LbGO?)mq$<HS6>jUAZ5$@a2PGrz@qkws(YgO`fU*c8NFF@tWuzk$C%Z6TRQNyTm`AhyO; ze}QpYM_Z9q$OZo~J2YA38saszfmB53CI-SE>lW#vLM z1`FyvoQtxbOVceOOP`R_?3eI`mxo8cAm1M^1JZ;rjwyrv0l6r-L7??galP9)9$0cH zLfrUOSh%&wP=j)o-Q6POEIZDC(DJaH0A(bGN=3vi^^Sg`3IN5Y9d`wz7s8Ad2PI5m zo<2{h5391uXVl_8&G^)PHp71V*5??Ky^~oJ&Gy|rqg&*JHyVj%K6xF1p{Lfnptdv4 zLN0)B#GqkcbWCD>M$>^rfj999;3O8!s#$LnH{fi^Y$dYJ=}j~OW*Igm?VF3no(W>_ z{3`4g^?VHWE+54|Z}^mol4;231Y6;ph2VtLTOaLI5BSZNKdTdOgK?|mmDF-MQ3;kc z@p`y*ewAff{eA_+pr^rb2K*e3#^<=m=>$OFpa zo}9IeZSZ6xDC@jFSnA2`DQgM}|Ik@vYhC$nkM(dqeU5DB_&R<1Sl;dfAUm{dK8D8ByN;|Y#MDf z0X~LD;qa!X>N}>-2&lvtSx+v;&88K+DacirV(nKk8-F-nWOXL`?Ur8sgVhJ?6WfEI zIg^b%HT@rrq`I^YoEeSu6klY%#C@-EJ`j2bqSPB(gVThwsmxv>ed0CSvnViZPQIjrPny23cl1jcM~{r-kFM&t)AFm zsRx_hVB*m+C6*eKw1-j-t@D!WoT11~(P@uqgYy`a8Q&8qlDl)F=|)>BhT&OBRDE_! zZYj$bkmaL!^Qbb|nfw?`B}Lq~{!F;2l>I!#taLxqYjn&N{q|rcb5&d=-XPjUMS0_b zI`7(w__hYMD@CyGcCyA(Md)g7Q$IQN&3SCgy;XE*vBhwk&v6J|kwaG1=jEgqUsk|F z?iG5g3lkr9d8>7X&B~%o{LD^|`bHcwU;3Dz4~Gm)(6rtcbJ`#7?K_!FJvnJeRU+MR zv~XqoK3+QFAjXBP$?*XRKiYi0R=FH-YbjZsA)mwzhn*ipPViJKu&9ezut-{XrPBO+ znm9W0G--NBFb7e86cO4?gdIWSz|7N3MphZAU3I8e^|+NRRV=Vc$Fy!LTVs?Gu&-}K zj5jb7B8LfQ56PWxBNL0A&X?$*PA!9Bl?X>ynD9#qcUAY{bQ!dWwPPC?632Z@WqkaI zPRv9$KbV<(Xl6h?jr``SiN9t~V@MK<42QK6wE^n}k%$HRA$}we$NJ|F+=Yt+wckF` z>Sp-G?)Zk?(ppJU$ZQY4jX&WYJZE5Dzf`Ujy&M1r6C*3jDx#inxjYo zj{xxVi$%7gBDt0AX~?C5IgKQx%#}}o?U-vDbRSJr@+e8}-oyOF7YgyE3MGHTr7#5V zSRRpX+A82#j^zSYMnx!`I3cskaLov}U@Z6!^Z&h`e$k8MXDYF9Uve_i|QPQp)DWbs1`BNd|_u3sHfpEjk@FUQ+13ac^Uw1)#Z;fc)pP5hX(aAdU zW_%HhPXQY^f!$TC^~~rw7XGMSKCmU}~x z49am?=Cn7$`OtjaJpnWMI)3MQTZtLd{_&x9V;6C+z+3ZqP!js23>Zr00!~GA5pEei z1stbX?u6-92`$Jut<;T&2%Rrz``OJS=kkZr!D*%<9;ZX zwRIz&KGJb8@0}x@BxIR@dOW0S-0nT} z=Zl8nzg#RFLop71aEI(QNJet;G=BY+f07ebz6@DmkXmQEiMb(yHE7;K zJ>q5Ru-y&+VuBM%SnLj7#P{)ngF&y(68dQU1A~t_hUeH))e|zO{e_1d1_QeSeoAK^ zmf0crr}_6L7ba{~%cVUI+K8T9z*+@H*&wTL-b4o(6;dIZ4>n!Y2Ev?i7xNc*pzoTK zlkdv61s=Xb6$etap_f9wGGZx!`aa!AcoIA%2yZ#ZLscz+bV?# zvldLetZ^rJXD$>L;L*KugkNpAyh^*!lq5Jf7>TDr zY%oSGTh%gFV$BgvTIQX2g>!n5(sf-W)>(xJ>b#xL9n7Cq*$i~$-52D&UiE9EtR%0f zyg$^Cult&^XjLnzhx0>M zNWkq75tp5-Xk-9D;$L*dRZHTBmH;_ATiHK0b#QQ%aCEe_G6TC>IoSUY7$F)1s&nE* zVh9Fi<^;LhA!yi)By^F(7%B7;jGgpolR5B5{O;%;C1Qlpj}_1KE5z@dBKZ<6!-Aw^ z=$E=$KKP8>J3c%(KcRW;VcV6`ZX4W0@^S2uUK74QDp&CESAA~=-k#AJU4teR=-Z=3 z+74u?IIAjU3+VWszaJ|O*U%_wTp%o4NKlx|x60KYk~j=9n_sfjDp3|Pca0*8#5dr$ zvqUJ>Gn1jqzcU-5xkz!Aj)6r}$C5G`a0r=j->&Slrz>M?N((zMde7w3V%48IruyCO zmCZpze+#h{9gCuC&qgq~N@;@o&T&FgajSA+3#Oi8f}{rFtt~5ljQZC!G6?g-E+#+<+OEY?P;xOPSDD1V-fBCr)64}+BP3PiEdCSXTldVcVNT3)Ece! zd+Sf0qKbsAA1$RLVNbI(EBnu_kbnI;EH*wYjU#)OK~GTs7VLq9TN+cs8biWIikS*GO9^j*A)W!5m~@xWGccU6vwYeXkc<&wjwz!FP}P&U%HA{ONwV;SO!1^0KVP?0Hpqp%#IFroSt^J zl{)RPIRRkHwl1b*75&ywBP)pkn#_0}8iDImfk=iW#| zZGcjM-j)qw=F8%@3*!Lrb>&{*sv)0HY`MIidT1+ftKMsVJxi4tbp9c7?VVr@Lw6#x zXdxK6$cc_8%_Oy)CAx>qr`Dj9G0r)YPp%95cG=$C9ffG{*+ zwSwLk^@oMMwn>}_yFr!c)$mBP8wTUHc8STz1M!6uu@oA-shYk?W;;eHT5z*7D;_2s z8Xw5~%(y{8?hV2&D!s+vc0OBTMa8`s-_x%n{w8f_2jA^>c89oVzJK5RK+|@yKUXa= z329C2nrW~!WtUNC7u2@H!GUzvb~ZmH_OT}CxIGe3*$`wr5P$PvYZrD=!n`bFrS=HUU#XCYK-C&Gb$i$yG1|61Nj}Dc47gCs!ZA2s5 ztP_S4u&^(#T?mXWh*l>tt82wbLrnR}-HwZk&f9c8Ur#Ks(YaXk=J%|QN%bC*;U+8( zx+{_x^g2qjr(VNQ%A@>3j@Vvpc)eUC1la=kCdq*G@CoAw*| zJk_L220FeDF2_LCu{Dw0V7r%vR@xp^<{?!xiGh@9;4Xhtb4L}(-N*N$xd+gNSL0ZF z@f36+NM{xs<#$l~61i*&Zx~|kXCr2%+@w*!BlT zCAjP1k7K;(@lx)8neY4dG$3PW$sP!&YI3O_W1kNa9z}tf54|O`ISP&Ib?tkD2qq1# zyQej)J9>1w)bUm@NDUR3qu9KJOATayXSQ2U9_yW7+ZY~G$H&DDZ6$?{LnA`ywc#jocib&V zE_W)@Kt5p`RDlODH>r5NLAE%R#ZPhaRC-69eBPUtydn~d(~TFGHWm^x5z5~?eV0?c z96-R)RtG2P`c{hOcm_g8x5 zs9ggje*muiwZ8{mIc(QJoBs{`>9_qo{K|2=hNt}%{15-_?^&)KxNDZte_;9H$NfFi zl_Ph}gmo!oFAMjx4nL;z`}JHg{c)21B>ZcK?k8ozQ>Fio@UQ*4>jnSoHr{ob=*!#j zzqsx{()_up_n%q*Q`BE)Sta=AEdQ0n|8u&(l9t!$hA$2A{}7tj;9nnsDl z3&ekVh+TH1sQO{L7a<8UV0<$qoSg4@-g#`2YX_ diff --git a/plugins/yudao-module-iot-plugin-http-1.0.0.jar b/plugins/yudao-module-iot-plugin-http-1.0.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..a1d4db6c8a0d94ffe5ca6535b2008102c4d07152 GIT binary patch literal 10643 zcmb_?1ymH+7dPDvLrQnYfJli*gLJ11Fmw#vASu$_At@mUNVlZ4G)T8}Neg_quIsM5 z>;BL8eUCG74maMrbLY-K(6qstBvJyac=A?_x+$ zz&o*YF_-1ZyMJ3lLqXyFSxinuURpw2MU_oX!YfM728I(Y@GRQ?xh@5MWoXDWv>qN! zu9g!yZBTg%oszc%ysGgDIboK)&qmpNxmh%Si+XRg63v76w z=TnvW!LW*z!=NA?2f8*F#{ue4fEAi)eXC^2i=m=PH+#xPqqap3&Bq8rJ)I^pPBNUF zC;emnW9IkK`^VD0WL$H)KyGIUj51fGJP+ENKMj#LIpm!~e-8u{6v|KWg1rlbk^*UTIRNnztE)q4^1Om z8xwQWUl^eI4+9QhduMZ_ADc(|E!L6VRQAtcprB;op`iHx!@}=dPz5_UivG46Cwq{i zxvdSGkrl|nAzjs40apae8y}?#5lOwotR&MTD-O`zgsXe{Z zQ>@!~Zwo_QpJ&3o4;q?Om6u6UX9xFo`hmy&d$VWcPg|f}F@!_0gQ^}~aG|vYeYkm* z`%bh4_kK(@Mc$#mA`iH40k?eGu}{o_S~Olf2(%tWZr3uP*5}jU!vNFHar1=9T%RK> zfxr?iSS?%H}|SHj4z6_ePv6_UdJ@a zBAA*e7=_o9ItERlH`FI!Ir{SzoA+8Sy@;MyA_KKRHl2}loizi1m>}p#r!c5~tvfoQ zXnd@Z`eD$e|3F``5e#Y4B|E&vww5l9j47z{pjDJC(Hb2UO`*?}IkYKibFxc}Cu`tP zUcg*h9Qitrn{hUZ9MJWaw~4l2WXgar6n&B|bQ=v`C$^x@`O}%)f+d;wV^cf-Eba%z z!E_2A^KC0S0k+7ySpjL!sn%IWXV4mTNnvDJC!e1Huo1N-=yIvgnBvi{^Jy>yX7A4D} z@Tm}ku}IERz79S6dz4x`S(^Jv*V`}Afn0PPO>v|HIEZ1P$ADP27( z9bEXxLjJTHZv`nJnX4h9FMR-)M)A#IbGLBcYsj~}t}iFVV7|-iayTd`!T-y=rs4dS z*(EC0mR~cwTF#-zt=jZs$Jv=`tf~hqUZHAWj3!e@b<&6Z)CQh8`?_$K)JH8BiFm39 z{=%)~w1d{La*D-pn5QPr&g;{r`lnZsZx)~gyXymqg6O?hrPqodbr9_~q#Ab0!7wb%3+cs61wkS&qC6-g>*u{UG|xXiP5`Y4ip?kLQv{6==(h(W zOnNr36IEPF(XH_qj->^S;8P05Mvt)*W~k@;7m#roZ{fuuwu>X;+ut`SU!=fH1XaiI zvv7lHP7#_Sf@d0WQGy<;TnGxTmOnY8HlmYz4su|kTXT}>_G0}Uje_CY@9{V^>BBni zLp)O_qbWY&(Q*q!?Qpe5GSt#elEc#B`B#<4wISR1rE-;(PBCV~4iH#gMi-tBXr1|d z3B3Zr;9Q*)19u(1IIG!rLZ~i8_&zI3iw}Fz)P;Ehv6oa+jLyusT;vXqo0r6M3Ab)3 zfd~zG2<7a~#vfxx*aP+D%oP=$N_ZFGWZP*wpfdX;uLwI0zB76~asU_G-lSD{W66&@ zkY{TPp}NL*~0CyezXcVLJP;y<*@U4krU~ z<4ABfqka+V3bb!{RHC%;!G{11MVGg&^ge0k+_ zx;^P&N;hr%cADv;d37+&V^FB&xY6`z-bb<&rWWxwE~>rkz9B;j5ogY<^5u%sxN7}? zneK*|V_dL#r6s9M(@KYS-P-5f;T6&pO3Fx3mbnu{`Kc2kK)}RY;`zuj8yTW#sf{y7 zTmXDx32JrO^zge9;vo0|yY}IFH~-j3a=xOa$|Co)4VX25vyHJ?Gw z8quwz5P5M04O5@o^JKj>by6Zytr8*&WwuV5va5Lw;EhD5jTF}7L{=9++CiNxCA(Pc z9ZuZ{vPl#4*e%(3gC05mz>9{@UXagm=`vYGtkL_>@#sYkxvtw2SKFL0xi*E1*@`E{ zSgGaWZ9-^ofw?tdGZ1!oYSm=U3vs#$l#JxSf_5*QYTW$?)O?bgYt}MviCn}Soek*0 z*=x<5uQ9-a_I}wtM?8c3*xea}yda?efT&cLXMyu{IY|N~0ffTD^l#Lgs9l zQw{OgEIOt;uj1wOGxqW?l?wD3qg^q1?*(cWbfkIHntY6a%)9~%1`jEkBf+$XJjvrs zw?Rg{QRtk~PszW0W~+dODFV384F?%9Skfn#ekw2&_mcoaDph(shOtA$tdUIFGGbEF zD~oeA86KrSU=T5?rDo0vWBY^#WW9l;&B$MC*53CFhJaOdAM<8Wwu^-w^@cv=*<*B7 zc`=3z1M;U*eW}vvAbMW1gkLpkji3HWM&_jsDl{mgnoe3eG)JPIcs$8xbags{2z3#g z>3JdPY*-+ZY=J2uRl(D!LxyIls(Zt7GbL-AEO`P>83Y#}HJ?mU?K#P7REe6Iy+^um z$(`|@>9iiP)Ye;e#zE^O63U7c|f~t_XC%=kHr-C$)+j?O;>he#7o!zD=WOyLp5Sh3?7vI7moVk@x<* z5MUB9Q-G2jom^rH{Fg0vW) z^I#dfEI$Y*kBW8gsGSl+FXA5K;3R&i6JG256nCWulPJN|tXW0Uw|4?+P&tlk=}EKW z&3ay9AgX?%9T|Zba-p5lV+Z=Rwt4x!9e~>ARtrt(HShb+JC`bt_ZXP#QRKq4{6r)a zG9FwR8L4cnZ+4EFt?Ob5GJ6!+6c?ioAfBbN{NM;*=XsTj?Fu|PZoHZm`f2GJH$^W=2z zEXzz)JtG`HEzi2$IENPnxrB5a+;l{p$ILJ3qgEyc$-QMJEAAn#llG%Rsj1#9>}S*A zbE=UaKfw=Q56p)7!fky?HneH@McMKF)4p?z4C=0@fEB*XQ$!+aw%s!^qbL%z%f}8^ zI5o6i;w3&|u2CWTyjqV=k1y4TBnp-0^jaIXO+HV{=6x~WLHx1`4M_14Fyeq=e3>Vb zm_hrI^)csee|AlLWk@Cwtra0H0q1^WpT2~Tf2E%$EW>a<4=7^fu+7pgFrs|I+OyYvB> zCk1|dzDVKG$c|BzYyQ-q5O7={5L^vj&BO7KEEU5W_fuWsvC*r*ed!EvCUVLV*t9Id z(J7>zh(**XCq@izD^FO@3@;r9WS}<>zs;hGAgh3&54;ulAj`H%?GCjgtVsm|?0$~) zScKXQDNsdH5#Dfr^wJygZ3ma%5Nhr7_cwNxw5z~FpHK>TF#aBGqktY>g-b+a_RyN? zTE`c{=2hmIeM!3;282`0r9+6*IM{QID?+zxvWR^}XZ%eh;>2i0sN(aUY>6Z3(EzBS zvnsexQ?@Hw9K`em@}4}fkKewpDS|^FvQ9)Fb z?{`oOwSw8pj?wj~`EJ_- zowH4sbLyJ_;fA%21A;H;x2<1p|G3kC!{hzs+Q-#*jScF%3%$sHK%uV~=o|b|f!Led zm>SyJI*LFbR^~>3x^Cvh4A|guVs+ozj9S&hX)AwJeuyD;Z{*%Vxa>z6ZsqZId?vp( z-&mIw8$IXU_m;3;Eb^*C2T+2lF4Cej8oqW230i(8=9d7lNkZFtzT#LltnYJE?jZNpT# zXa^mU)1D%$pyUxb*FTMMD-xj|c zwY&bS`S87c@drSb0@)Z_f$hIt(V8@@A*vcg-h=Ba^DK#P){0RB5#Z{jrK<5{D1GxO zv5>5g=qNRdt9cuEQ)Qjc*v{tBb0?TItJE2TvxBuQs|?3s7_BMrn7!3r-`Ml7d!BpHqe+?&?L*pBRebzZCrZ}UNvtBy}8}!ErzOIbU}fE*eM|^fmFik?$j|5y-WZuUhmJ z164TVoZS`^U62j})A-9rfFx2Nuq#8izOPKcv1@k;cTy$2-nw_;qH|=x4U<=VUMC5V zE`kRt4C+jx-Cf86A#itXohA*cF3vF_BF(4ax9^tYcsS`Okd%T{G|VGwn9I0uNP6H_ z%1DHa9mQu}r&*fBgsXS0;mj$QYf~gunX~Tg-M=)Y@RNZDING6r(A6|Wzr3xVS(zr# z6vDrCo}>d}8nnfP5P$q^_ffPZZ=iwub>|#hZlBC&)Hq2dln1u=`iUYM;_o>D%g9LZ zW~m`p#-7A`of6P;F3x=FUFd+=!xX->!Xv4k%ZFPknA8@2gT+Qi^4EKXhsC3 z$8ggtWGZ7WnlV6{}&MKEmjPWwj4P=bN zHCrghy*8W1+750&N23DEg`;yNIlx@O=iR#am_WXZ@Qh(*1*@F-y#7)U7y$bNy3p`lBbT85l5n|qL5AB zQulXrk1Z-md&#t8Z-&O4dL-#yRR(n*68Yj_di(C~Bc8Kt4=o*|WF#4`*N?N7E=hZe z7$oGJ5#^A;$c>Vr&>hO@cXlKB#fEmj@DEvm>Em|~JF@AM-?ph6*Bg{ikgZ$GSFxF@ z2D6*abUvx^Oz2Zog|Z380#m^Bg&- zWH~ql+PSZi_oA?tL2r50w6{Tn8~5U|gVd|WYIgH;D0Q4-XJ*sxa5|NU7pPs4@jS{Y zl4CY>!1|pDm~t5Oxx>Wq_a4fvdj%&AfxXN#K+9ir69CeVjM~Tj*0n)bt5BK)5^8xJ|vp+>Y`W zu}*e3>SnK-k%QLZB^838$aIh6qw=NEjRpS0j)P7WAE9H{I>Gs)CDYPorxRD}y2agv zw58)-kLvdwdi>^?YLN8yp2{|j1O8ACd-e6$p|G|7SgIR#k!O*BhcQx#cAhM2yzgzL z9_pU6E)72EU*591DO%LHVMcw?m*jwrig-@_Z05-CrPP!Tv=3_+jt-BqedfCK{%DKilN*Dw>24DB94B?%PBi=l|-E2sD3ee^W z5P&r+L{anT$S9%|gSQB6?-bRfhY+P&$POAxTAQ!w+ARadgdxc2RJ#1ZB^qV1O8Xd9 zXxUZjS-JwL{tq|Y(Y8#FCW&ffQ1|Pd_2FWW)SGK1nY^X_~Ea-zI@(sdcZ}w;# ziivQ|z}?vy@zSQ+SR)V||4F{$3+|#qFIKX5bFOIHkhuEH4xtBKRV!om2&o6?%~cr^ zq#5ld&Qq+eWM}1W6D#n0O~F@g_t9&EO3u+)n|!U$sY|Y36ds%Iw5AHCfw)(!wQotB zSN3PG5Dm}iwITlO_<#~avIQnCw+urWP68V`%tGArn0^~h|BOr;GD_@4Mf;csEL|-J zV9&swnv@p#rQ-fG?xy2HCii2WG!u(`DukySDQyfb;t{dB0`la8987`pZ(4clibpoI z6&`1~Fu!M<%*e+@XJ{5FkikQO$A(`xy_x8H8h$I0<9A8Ikrg(x&V?LVxM#ALd4Tf# z4VUm)C;w%seF-p=tV%``*~_#C?CF9vv`>HCmNNPBHD9Pf24zcH(IDme(K;` z#y%*heBPWJ5yf;`0If_*<}}=16K1+?#D+Z^-iltNiX44lM|7+a`K-m+-@e9>vA#}y zA4J5KXZlj%CGSh}XI3%q2)p{NddL^X>uq6TWt{wqj;u z=;ycPbwst783i6Y z0%c@SYN5V^yuVLBzk2#(`e_Yv2LE}o_w%Tf{O`g>Hf+BS`q;i+3jQ<=`&s#G&;KV+ zKP&$>0c8C)(qp|F&apy%Yq_$T-CaNau#EKE1Q)r@VCw4b=5p`u0HXhomLay*Y_8T; zCF%natK3-4Ln>m}lT&kVVISu_Q8y##kZCZaG3XdiuWb-YpNigfJbSiYCMk~;(D4G6 z*A<#AxW-qH%wHz0!+3Xv?8)`PCH_X0<94-MQKW$+sLY1p!1W#l;8P zZyts|#K@#GwPWmLm2)c7*ip{2)Q(D|qOIrDw$#%%)Qw_Y3yy<}h>l|RyzXT7^ffWV zA0xJS0)E3q9Y!n;w*Z0)uH}Dc?TX*}X1Eznx2e;nMzn!GeDA{Qe)mG7`vn-5&rsLA zO@)}wfS7D zyvPlEe2ivC?_8|kMDsL8+Bv8*gH`il;+?i*YZh(~7q&AOZmx|E)}LqITx<{Vw%nfX zziEL}8a+_QH=4|5EX1RQUr?Vydd4#7lkLGUmL$uW=n7rab?q}dz{k$k-5|~_&^XZyqU4r`Ka3{?U>SxN7A##Si<2k)J@lJamn8Nv* zi@k?ls_VYgx_u$!>9=HUe3zeI#zCH(ahGgC=f3^`Xi$!7uYG-9^BT?O1zG~jD^8Q? zN3V2o;jbw-gI+JrdR{Uyi`cLAX`90!iwJM|G$WIhzZk%KO~V&}@`?kXu8P?SF;G_I zYC;LecW*HMCP{2bAYf z#^vw#<&B2<+>aixFue~tEhkSG6WeyL>614e={ZTy)@|uT;>#@*l78k`=FJt+FncA8 zR4v~yg|rDPxGYEq7E*d>?)7LWA&LZV=h5COPfDAIBBDua;p;j=qk%(ZoaEAJ=cxlf zNOeH!DPvfZcR6Hm00Xbd%(>a7$se(!H&Rp3vN~_RpssFWFL^ExL(X&qfNpRGCUco>-Wzb&Z6WHJzWrVwztxu8#=u0kyPERs z?jiI4p|(KmZ6S99By+F>dXFqh8wVED2QPWf4^EG9gw3*;39=V^^(o}Khzo#}@+eJB z&AZ#BQkwn-e&+s?n$fDf_X9jA4lriR7c#HrklBW?8&42GPlp-pOPbZ0dXG@?&lug4|hbkzjpWiga6}Hf9d%B?B{1d`@>J%-B;l!c>6>7 zpE2q;Wh|)M+nYP(KPt_4#QGz(e}dx3^~hZR|e~ z?e}f}Gp7CSEZ4W~|IyR$2=~X){`rUQheI-||BTZwkM`B!kDon7S$Kr6w(;)%yzk!K J-dTr&`afenk2e4S literal 0 HcmV?d00001 diff --git a/yudao-module-iot/yudao-module-iot-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/pom.xml index 4a46b6167..949ff13e6 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/pom.xml @@ -8,9 +8,9 @@ ${revision} - yudao-module-iot-demo-plugin - yudao-module-iot-http-plugin - yudao-module-iot-mqtt-plugin + yudao-module-iot-plugin-http + yudao-module-iot-plugin-mqtt + yudao-module-iot-plugin-emqx 4.0.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties deleted file mode 100644 index 5a67270bb..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/plugin.properties +++ /dev/null @@ -1,6 +0,0 @@ -plugin.id=demo-plugin -plugin.class=cn.iocoder.yudao.module.iot.plugin.DemoPlugin -plugin.version=0.0.1 -plugin.provider=ahh -plugin.dependencies= -plugin.description=demo-plugin diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java deleted file mode 100644 index c97a5b9b5..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/DemoPlugin.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - -import com.sun.net.httpserver.HttpServer; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.Plugin; -import org.pf4j.PluginWrapper; -import org.pf4j.RuntimeMode; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetSocketAddress; - -/** - * 一个启动 HTTP 服务器的简单插件。 - */ -@Slf4j -public class DemoPlugin extends Plugin { - - private HttpServer server; - - public DemoPlugin(PluginWrapper wrapper) { - super(wrapper); - } - - @Override - public void start() { - log.info("Demo 插件启动"); - // for testing the development mode - if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { - log.info("DemoPlugin in DEVELOPMENT mode"); - } - startDemoServer(); - } - - @Override - public void stop() { - log.info("Demo 插件停止"); - stopDemoServer(); - } - - private void startDemoServer() { - try { - server = HttpServer.create(new InetSocketAddress(9081), 0); - server.createContext("/", exchange -> { - String response = "Hello from DemoPlugin"; - exchange.sendResponseHeaders(200, response.getBytes().length); - OutputStream os = exchange.getResponseBody(); - os.write(response.getBytes()); - os.close(); - }); - server.setExecutor(null); - server.start(); - log.info("HTTP 服务器启动成功,端口为 9081"); - log.info("访问地址为 http://127.0.0.1:9081/"); - } catch (IOException e) { - log.error("HTTP 服务器启动失败", e); - } - } - - private void stopDemoServer() { - if (server != null) { - server.stop(0); - log.info("HTTP 服务器停止成功"); - } - } - -// @Extension -// public static class WelcomeGreeting implements Greeting { -// -// @Override -// public String getGreeting() { -// return "Welcome to DemoPlugin"; -// } -// -// } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/dependency-reduced-pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/dependency-reduced-pom.xml deleted file mode 100644 index f4ec60d96..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/dependency-reduced-pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - yudao-module-iot-plugin - cn.iocoder.boot - 2.2.0-snapshot - - 4.0.0 - yudao-module-iot-http-plugin - ${project.artifactId} - 2.2.0-snapshot - 物联网 插件模块 - http 插件 - - - - maven-jar-plugin - 2.4 - - - - ${plugin.id} - ${plugin.class} - ${plugin.version} - ${plugin.provider} - ${plugin.description} - ${plugin.dependencies} - - - - - - maven-deploy-plugin - - true - - - - maven-shade-plugin - 3.4.1 - - - package - - shade - - - true - shaded - - - cn.iocoder.yudao.module.iot.HttpPluginSpringbootApplication - - - - - - - - - - - org.pf4j - pf4j-spring - 0.9.0 - provided - - - org.projectlombok - lombok - 1.18.34 - provided - - - - cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin - 0.0.1 - http-plugin - http-plugin-0.0.1 - ahh - - diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties deleted file mode 100644 index 44f221cb1..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties +++ /dev/null @@ -1,6 +0,0 @@ -plugin.id=http-plugin -plugin.class=cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin -plugin.version=0.0.1 -plugin.provider=ahh -plugin.dependencies= -plugin.description=http-plugin-0.0.1 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml deleted file mode 100644 index 4658a1f6b..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ /dev/null @@ -1,157 +0,0 @@ - - - - yudao-module-iot-plugin - cn.iocoder.boot - ${revision} - - 4.0.0 - jar - - yudao-module-iot-http-plugin - - ${project.artifactId} - - 物联网 插件模块 - http 插件 - - - - - http-plugin - cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin - 0.0.1 - ahh - http-plugin-0.0.1 - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - 1.6 - - - unzip jar file - package - - - - - - - run - - - - - - - maven-assembly-plugin - 2.3 - - - - src/main/assembly/assembly.xml - - - false - - - - make-assembly - package - - attached - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - ${plugin.id} - ${plugin.class} - ${plugin.version} - ${plugin.provider} - ${plugin.description} - ${plugin.dependencies} - - - - - - - maven-deploy-plugin - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.springframework.boot - spring-boot-starter - - - - org.pf4j - pf4j-spring - provided - - - - cn.iocoder.boot - yudao-module-iot-api - ${revision} - - - org.projectlombok - lombok - ${lombok.version} - provided - - - - io.vertx - vertx-web - 4.5.11 - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml deleted file mode 100644 index 9056af48a..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml +++ /dev/null @@ -1,12 +0,0 @@ -spring: - application: - name: yudao-module-iot-http-plugin - -# MQTT-RPC 配置 -mqtt: - broker: tcp://chaojiniu.top:1883 - username: haohao - password: ahh@123456 - clientId: mqtt-rpc-client-${random.int} - requestTopic: rpc/request - responseTopicPrefix: rpc/response/ diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/assembly/assembly.xml deleted file mode 100644 index daec9e431..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/assembly/assembly.xml +++ /dev/null @@ -1,31 +0,0 @@ - - plugin - - zip - - false - - - false - runtime - lib - - *:jar:* - - - - - - - target/plugin-classes - classes - - - diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties similarity index 55% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties index a23bafcf7..7f565b75e 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties @@ -1,6 +1,6 @@ -plugin.id=emqx-plugin +plugin.id=plugin-emqx plugin.class=cn.iocoder.yudao.module.iot.plugin.EmqxPlugin -plugin.version=0.0.1 +plugin.version=1.0.0 plugin.provider=ahh plugin.dependencies= -plugin.description=emqx-plugin-0.0.1 +plugin.description=plugin-emqx-1.0.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml similarity index 99% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml index 43d67f520..266e45fd3 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml @@ -11,7 +11,7 @@ 4.0.0 jar - yudao-module-iot-emqx-plugin + yudao-module-iot-plugin-emqx ${project.artifactId} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/src/main/assembly/assembly.xml rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java similarity index 82% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java index e64695b06..27b90426b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java @@ -1,12 +1,11 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import lombok.extern.slf4j.Slf4j; import org.pf4j.Plugin; import org.pf4j.PluginWrapper; -import javax.annotation.Resource; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -14,8 +13,6 @@ import java.util.concurrent.Executors; public class EmqxPlugin extends Plugin { private ExecutorService executorService; - @Resource - private DeviceDataApi deviceDataApi; public EmqxPlugin(PluginWrapper wrapper) { super(wrapper); @@ -30,7 +27,7 @@ public class EmqxPlugin extends Plugin { executorService = Executors.newSingleThreadExecutor(); } - deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); + DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); if (deviceDataApi == null) { log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); return; diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml new file mode 100644 index 000000000..260ef9c8d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml @@ -0,0 +1,43 @@ + + + + yudao-module-iot-plugin + cn.iocoder.boot + 2.2.0-snapshot + + 4.0.0 + yudao-module-iot-plugin-http + ${project.artifactId} + 1.0.0 + 物联网 插件模块 - http 插件 + + + + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + com.example.HttpPluginSpringbootApplication + + + + + + + + + + ${project.artifactId} + ${project.artifactId}-${project.version} + cn.iocoder.yudao.module.iot.config.HttpVertxPlugin + ${project.version} + yudao + + diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties new file mode 100644 index 000000000..49aef5b18 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties @@ -0,0 +1,6 @@ +plugin.id=yudao-module-iot-plugin-http +plugin.class=cn.iocoder.yudao.module.iot.config.HttpVertxPlugin +plugin.version=1.0.0 +plugin.provider=yudao +plugin.dependencies= +plugin.description=yudao-module-iot-plugin-http-1.0.0 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml similarity index 73% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml index 3d58a1a75..40bb303bc 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-demo-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml @@ -11,45 +11,27 @@ 4.0.0 jar - yudao-module-iot-demo-plugin + yudao-module-iot-plugin-http + 1.0.0 ${project.artifactId} - 物联网 插件模块 - demo 插件 + 物联网 插件模块 - http 插件 - demo-plugin - cn.iocoder.yudao.module.iot.plugin.DemoPlugin - 0.0.1 - ahh + ${project.artifactId} + cn.iocoder.yudao.module.iot.config.HttpVertxPlugin + ${project.version} + yudao + ${project.artifactId}-${project.version} - - + org.apache.maven.plugins maven-antrun-plugin @@ -60,7 +42,8 @@ package - + @@ -92,6 +75,7 @@ + org.apache.maven.plugins maven-jar-plugin @@ -103,12 +87,30 @@ ${plugin.class} ${plugin.version} ${plugin.provider} + ${plugin.description} ${plugin.dependencies} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + -standalone + + + + + maven-deploy-plugin @@ -122,15 +124,12 @@ org.springframework.boot - spring-boot-starter-web - ${spring.boot.version} - provided + spring-boot-starter org.pf4j pf4j-spring - provided @@ -141,8 +140,11 @@ org.projectlombok lombok - ${lombok.version} - provided + + + + io.vertx + vertx-web \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml similarity index 74% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml index daec9e431..9b79e6152 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/assembly/assembly.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml @@ -14,14 +14,7 @@ - + target/plugin-classes diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java similarity index 93% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java index 54d9c7c2b..d77f990c2 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java @@ -1,7 +1,8 @@ -package cn.iocoder.yudao.module.iot.plugin; +package cn.iocoder.yudao.module.iot.config; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.service.HttpVertxHandler; import io.vertx.core.Vertx; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; @@ -17,8 +18,6 @@ public class HttpVertxPlugin extends SpringPlugin { private static final int PORT = 8092; private Vertx vertx; - private DeviceDataApi deviceDataApi; - public HttpVertxPlugin(PluginWrapper wrapper) { super(wrapper); } @@ -28,7 +27,7 @@ public class HttpVertxPlugin extends SpringPlugin { log.info("HttpVertxPlugin.start()"); // 获取 DeviceDataApi 实例 - deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); + DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); if (deviceDataApi == null) { log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); return; diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java similarity index 94% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java index b32a1f59f..1931268b6 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.config; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; -import cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin; import org.pf4j.DefaultPluginManager; import org.pf4j.PluginWrapper; import org.springframework.context.annotation.Bean; diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java similarity index 98% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxHandler.java rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java index 335d6c95d..8542cfefb 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.plugin; +package cn.iocoder.yudao.module.iot.service; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml new file mode 100644 index 000000000..c5a1ee84c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml @@ -0,0 +1,3 @@ +spring: + application: + name: yudao-module-iot-plugin-http diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/plugin.properties similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/plugin.properties diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml similarity index 99% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml index 462fbd090..7e4689b4a 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml @@ -11,7 +11,7 @@ 4.0.0 jar - yudao-module-iot-mqtt-plugin + yudao-module-iot-plugin-mqtt ${project.artifactId} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java rename to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java From 916024b8914482eb6b4e32f52e75b4193aa4e108 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 21 Jan 2025 19:38:41 +0800 Subject: [PATCH 091/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E9=AA=8C=E8=AF=81=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E7=8B=AC=E7=AB=8B=E3=80=81=E5=86=85=E5=B5=8C=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E7=9A=84=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 0 -> 10353 bytes .../framework/common/enums/RpcConstants.java | 17 +++++++ yudao-module-iot/yudao-module-iot-api/pom.xml | 8 ++++ .../module/iot/api/device/DeviceDataApi.java | 41 ++++++++++++++-- .../device/dto/DeviceDataCreateReqDTO.java | 31 ------------ .../dto/IotDeviceEventReportReqDTO.java | 45 ++++++++++++++++++ .../dto/IotDevicePropertyReportReqDTO.java | 39 +++++++++++++++ .../dto/IotDeviceStatusUpdateReqDTO.java | 40 ++++++++++++++++ .../yudao/module/iot/enums/ApiConstants.java | 16 +++++++ .../iot/api/device/DeviceDataApiImpl.java | 26 ++++++++-- .../iot/emq/service/EmqxServiceImpl.java | 6 +-- .../plugin/UnifiedConfiguration.java | 6 +-- .../device/IotDevicePropertyDataService.java | 4 +- .../IotDevicePropertyDataServiceImpl.java | 7 +-- .../yudao-module-iot-plugin-http/pom.xml | 2 +- .../iot/HttpPluginSpringbootApplication.java | 17 ++++++- .../module/iot/config/TestConfiguration.java | 44 +++++++++++++++-- .../module/iot/service/HttpVertxHandler.java | 8 ++-- 18 files changed, 294 insertions(+), 63 deletions(-) create mode 100644 plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar create mode 100644 yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/RpcConstants.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/DeviceDataCreateReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ApiConstants.java diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar new file mode 100644 index 0000000000000000000000000000000000000000..fef8d5362c38ea47e769e58933c715d492df719f GIT binary patch literal 10353 zcmb_?1zeQd(?6YyEF~o!5`uJtpmf91(jhHfvVhb|hvbqX-6co}NOz}nN=t`;@WS$fkzUr?_<<-}A(n55*z zA1eM%h62NRO{QCLl-6u;D&D zD$7WRFfo)XBef=&t|~@Pbt(6cIZ>S!&c1a&@GWs{j6dauNcJ6D!Rt(I`HpZHoVKSo zx`%Bkm?atsM=I_$PnXx>D^n4-_{CZqAlFv%8nc-zty&=#3hzBU0zCr@pX`Rv>UHj? zW3e8~YLVYhZh~=8YijJxwJQ0D;Az)HPot+MeZr|pEHs#|YDQx~|DsU|Y2UnBIPQU- zyQ}(Vo4oCU*^#dHd0K|eLs>H&bC1sQ3~Nu=A1nV^LGafrH+ueuYJMg_|4v|TV`O7& zV*d+5tp6l*b22ut`2{(_-;rC}7&}>+{DSM=FSyKY9Dl({^)H-8HqW1#oBkgJ*jhQ6 zn%`;?<-09XHyB94!N3F~z`*eRcQa5iad3R{+hm;V4IIsFo--R+88|p3gRB*BM1Y>L zcNrwyu&~5LSHzeIX3PQ}ipT*CIp`&$M-G>cYnXz!znIuy?&+;(({k-0pQeYD%lK*m zh?uKqsy{(ZQ{0@toQD_B!3Z=<`@t@wb>OoGP(T7b?8seZ)@Z#zQ*ot61TXU5+4mFL zXRb)Yt`d;8B{1S7*1Wp_so_K3%L!Ua+4GSS&nU{(GlJe@_4J@+hv?RjrM>JJCp2(X zW=KUe?qw%1iRY^9jB48unlm?%%ba@}Nj-FzrH{o0TuDz%X<3~f!IUNjnnW?`5Ti33 zVz2&4F1;dDqPwis;04MmRSjf!#5Er3+J#Vd@i%QBfkkRUV!rw)3jxJ4&h#0$ox=yf9!%SWT8wRCE= z1o_S^jRc$X;OgMqjpRF7UfyC9j<8W0fR|LT5eBTS*!xvdMX=L+MNWyw*mZ7Y=o)um zX3_c;e)xj#1}YjYvktvB&{0Gf7=iys1EpsDZlb*^Pp?fB_Yw(hDi$#|e;yC30?}B6 z*+&ff0g)5~P}+6ZdV-{D(K)-XZ*2E-uve2_8ZE6xG}K-sY+9{>E|yh<%KIeiXeMN$%yG_|HIWZHa;zngYIQqjvD5n6 zEi$T(jak@Q2l7rn*c!hEqTzdYWJZd12~Ua=%OY8(s#k9xyfH4`*+Q2XMh(`TU#Ee5 zmUZU$zvD<$BI}rTK61P$k|PFn?hHseL)#0wzm2hiSd$YozoLy@2Oyy+4#HD9x>wr7 zsgO<<2LQwqw3t9rkURn6nOq0(aDBM)Nx7ZcT_*2`tAZ?%iV~~5DIi5lOyQY_i1#JZ zyS_;l?64i0>Kdav@zdcnSDEOyv{+9Y#23k|7A>0WY30R5_u6YBIg5Rf;V0WnqznNE zO`%Y=V;OXmym-B)#O(0tj3^m1fjz;G!<$ zuF3`TDWs9RH9w~C2%R>PVny+xxd<==zfSq1QwCjv%N2Y>D-uSvXvVM@A-#mak%ik% zasIGqZ?N9quZbe z$y?Da^;H@QtLQ_0Y=BGSgZyK(q2>uuFXA$42`OS)&GHP1b|LRjPwzeNX8Um=r|6k`JY8|TQm0z2bdaj~n& zEQjMMpdTNQ&Kp=k#h9H9{t(u9w zqpPIBb7LzL`|tMNs{Yg#XPodd4E(8L;$>mWOE_3w3i7X&Y1-0O*c<3bzBY|*95mMD zufsAc)N8xGL^euIanMVdVG|`p$7a1hlrDyi6P@sL=JQy~@aU1v#`LhBu0Nu|^jM3& zG^JTeWJv+A_ekyuKVST<9Ymj|-c}k~% z0_m#DvJR3U?0Q?ez>t%p3>+yzBWe!wD@>GclCoD%?V!Ps=;!H7YF$@c(`1Zev;Ou5 z_{rc)P!uu-zqwu9LJ>6?H_nG)p!m}<rMUZNZ8BWu z!HTw6(p(K0KJ?FrgoMmaMdQG>I>3tEecnc3VB3q>yw3_NRrer_v3E*$*wrys%d3=ak ziHL!%P*3m4@B_`fwF8vWjHhJ1+jp>xsC5+BL`FTuoy2`-xh8zS*_UzgZPH;C0WPG& zjU*ZZI2!yCW1%uAX0Txz!;}D_Ez@ol>3T$!SRq@(fQCNTJ0?lVL?tg^@0gQs9?o$X z0cl=~gvR3_S4T#Vro9)Xjcu|uY3mHw93FV+D~BiV{WQ;0wiyectZmCrKT}r`RFu?F zJv5UJfMutrAsgN`7m(*Ln#C2w(XX+eXiOV1uA z`x=WjYf-N-7dEz-rDaNSMY#jAgFh>;mL2L+xl34Aa2N}llr>@Ahj>rjlU4ap<|^%- z-w4lHn@ncPtgo?i#um3>=t}Xz9fNt{3Z)n4!fz=|X|%&Q=h!4!Nn&UBL?zZf_6;_h zJn#AnHmZdOgFKrRk@P`Fz|u1SmYq0dkpezz9g2%idm(6#qZeOU2B`ND9}g_mTz<;- zq*wca3+S6%CyII-24nlV1i@GrWxZchabUmYDVn^}*Yp=X1C`)jokr0&i(+LgQl~jQ za$Lq}ayqTuDkSXM8Oa$z>X~-aM>$j-Y8RXs#S0Gv70#n5nq$oZJIxyh#)ydTEINHi zngDn5z9$)tsE@CF zpWH4p=!J6a>9;h^4a%u05((EP&N4*xI?k9Xf)*NChSS0%{D&ZcUZ~0BQXj#?8chNU z8-%W}UuW;4qCZAwsACcgV~_1-el*Rb9}QAO-CxRlZ4nr7r@0JCjzS{T#hl~ocq=1& zRDXX`Er-MBZ7pok;Z$u$Q9(OEz-f5 zSQo_MXllmCB8~1U#j*D@lbC_&Vag0Jkez{@I<|7ND?y@lM)Pk%g%n>Yr7RJ@6@SDG z*kC$SSFn6JrvDAEHx5j|*w(G~bUNcYH-x|%RB5z|ag9|Y zhr)53V+>(n3Yd4q?SV0@(LSI|%ADGU1fd_PP|^PA9ouzA*u#M{Yl>IGb!u7w@hASZBz_H0J>p**Jkqrz8f zjuBNU!nmj}EC&5e21JJ{mk6cnOiSUjOK=_<;On+NPrBbH!{MNij^QQBe<`~|OQ!#l z!)4KidT(y6(Q80vZ>nA8u$)K$LKa11P1hj5$cUSRmWOxIa%F`8D%oyWQv}wA;YN#v zug7xh)|1lBn`=UYFHoBWq}niscdyV zqg6Md9rvHN0O^u+vfot`N`2bW{CL8v9hhzI7FjQ`?mpR|GhqFuCbVq%G1jXZ!?&uV z+!wH;Zb{H?c4*q0=_IidqUG-XZ%c65VA&)JCp5i=5F4hI2kj5Rb4hhvILC%im9e>gP{! z#|b?#$>F={@bRL}U}P5IHe6*w^k2ip3hP9}8HSn<8=RDc0N4|unzo4(Tyjxa79+E- zClfNpGSZ|*>AK{MhMo>(nV$=MBi4BLXywt`@J`PbbDWN=vX_28)S#M?t= zOic^wrb0+U3V4}9&qqNV))=xa@?@~*4dG%eb}&Q*M9A?(DS0?8T~u2)bJUJfaN0hM z2G3;kS$tZHs^R8inU8>1QeaXwmT0CobB6qRE2oxdihhQuG;C^ycuxi&KZo4wU1KLy zJBODTrBEGIHF!%UOFfS*P3X*ws2*x29e`;rQnck1SC^O0CC))MreEl1Pk3TL@&vDQ zEu1eam+>OrDEA=QZD7z5iM}V9w&-;sW)I?UL4M_oBKzvH@QxCxBaxr_PMngrG-M^M zx{HwX&NRB&{t6N#`&nOu`-wkhmQ700)?#ecmt})q=K_tDnc<~9_F}a@qr4D3PouNr z&VHNZ8h4Y6KL74vvU(vwyMw-t&eIX->1hR227lf5nIrY(P;S4C;6pfNrX^UcP?PC0 z*?bt{g*Zj3^t(;~MothRwzrB;Rx2KNmMGtHp~+=}FcRE2exko06K+=sF5*OxHFjn9 zgm*GEo!FB-MTlGRkhwTXB(Pe|uzWOCY2Y5rfu;@~X7_}@1WE~`f7)~dfnel#x=0f# zG%pM-hcC21kMl8KYjG!_RjW?05nW3g@AWq*wW&UZpq_ZTA1z_;M7LrB;hhydFXi@1 z|JeItOcpYvT6F8U{LdJVu!7l`*0z>dGiSTYzHN}JCwWHhf&++EmSd%o8w2UFhMoPU zv`pSD(eYL+1@OJaFv+}QDL@L4ea zy)?<_uw4^Xt+wOgLN=Mld%P$c9IuSQB(Dg^9!m9=G%favR&QspEk-^B7KQ}LU4U z>99VA1z`jlVFe-XymT2Q|JZ5_Chk`jnwW;RtEC*jpsw=6A`0t14P%imb4_jCzJvo~ z_RE~shv4tREA!1YggW=2INS5*fiyo)4eCc605PkD+}JQ5DmC9-n6fWmyIfrJ(yiq< z*#C4I$bGQ8-xPfMRDDO+>nR;S#S*oAV0@ku)^M5IGv|}1pGzk5gD*Awh8J^rniUh% zD2$Es);pWS1M4elYt!vNUoh_B;4iL(yPaxOcPs^t!8F&PBxC4P$1q7+@_V5c4m)&)aL9bZc*&t)W8&S^hw zB{E^yHPqXv>mcmrLp=Q!a+fkTDGWY&22c>1g^`CvR07DBIHe)ZAqUwfJVEBtbWY zLyUIgd8viMDg{;S=7zqFWZ~VR{P(QW4JD~Poi0IGs_H@B`f4^N9aA_XI8?>O-62{c zvu{y9=HGQ@!$M}O@8lp!NFE7TMXY7P2MJBLFrkulRE1&^a`ixD*&#i!MF`rNEosLz z>DnwjC!6KfcJeH4XdfVE>d3MVN(9)=9qTNjAJN-;Cs0P|+jp~(+efl^oau+k`awy}l z$E_uYGF0+>7!3-l+&!(wM$nMX`o-FsY~GUqO4ss31J>AWK|!&dV7qArIGxE@zw z^;`oC#w%lEp}snqB+a#ln+^)y0rnWP=`(DQx!Slm7Rd&mqd5d&AV~vKuJKoDG$~N$ z25Pj2-zaxU{W0H|mk-`znFY39SJUVus(>qe;+o+wLbUJDgIBKX!M{h zIGWKR=XcO&?cTZL`*>oL09po;{TG7{K(5&FE!^dHYk8JXVeN3d!`iS2^*7NEbQC-% zC6B-Ek>gHoQ$Bj9&weM0JEe{5g?r`jlPdUrtW}f69;AaP6Lsa|iYR??%S@KE@$&FD z;1I)7Sqf?v+cHMPG(Q120dXLy1Z!_Ko|#-w(VP5}z!98pW=)%xHjnuQ!n}obwh2O5 zHH>)FxFM?>vkHh!QG{olIozr+0(VtSy{z~2QODwp8p9h8M!WTH3eGsvOhY&Ac_K=Ivw7g|8p9#9HQ`_w`iOEB5?`9q#}oLcn$*aR^t9k_+mNEv=CO77`Q zKP|t1PTsQNgCPg+xGksq^rqtcZmX{CYcetJj6;vZV%9>2P@836Wf^IFVPNV9L#5C8 z_34$+#N@0hX-Bt);S@4!*?b+aEcnbB-=ZW&1-rLR$&%)im!GF{ZX?@43iWjPRlDl* zRLoQ@mo@~}No12sW|Mcr`q+t-JgxTE=HO7BfrH!4+=zFJ6r7=#m7VPS<=YY^$S(#I zjftIDngr_gW9VROo`SrqM{~aUeSMU=RuvnD+VHZ1ysbo6eKKd8w%$|H6MptjiL0B6 zm5uq9-q7_8#=O4SnAe{Mf4XsQ)>fRMBJ%L80GJ&&f10YSd}U!(dC8;~IVuC5bb2G%$>F@{$CT8#+qD?Gd6Y*> z)6PMbTUj5}vU<^y>o9+QY2jAM*HBf!10ay%##5M^qHgT#NU5h)APGmO_Q*F0dWBtH z`GDZwNXb_!i8z1y_VnpY*YN(U&Id#X=s)cI=c?4r^8cvoSsOT;+!kJbCMNrt*yuU) z?-ecPn@8XmWuKd*_+OCz%KTfYi|Kpqis`xv#bkEV+SQ&C<%95s(DFmh37U(WL*k zNDZJ<5NkVKqy&F$9v{SCh+3v*&Zx@Dz2h8|obM<#zFaLCSQHwog}+Kr+zGK4MT47? z>_Du)_<|_(1cw8a0fRH63WS5ijs~~*k=+^g|ukBk9r~{=r za2~f;&9GRAT5#RZMQW6TVqtlYvt?u9@GNGW7cm%o(EY06 z>g=?A=j!6v5;z)TW6bKzv@tEMq_``m8U+teSo&a3UcWU(OB}t6UEgx$&G3GPpa=2n z9+_%OBHuBoq-DxyQTq3XPLq*R{3zFH(+1c%VT!ui!#!f;lzy&tA%tvPHN4jq20$)~ zZj_|$P_>H5l6S`n6mOLkF zZE+9EHwUX?9vl1Yw8N{$Jf?k3%dZ*Idq!&3W^+a|9)W8G)Ok85QA|BkvT-t2>vbXx zt!P;@VfXK|*sfG*-hTa@~1Lbc~LzMYziYC^DBgj6Rl>zP#P$ zA(~^u^s%BM9+EYb=o8#BdL|T-MPN-Txp`s5@Qr@%MtCkehSMY_X{qD1CT2%}#8D4c zt9U9psIH$lGG;wbWK5-%sG9K|6zh2|z#E6nKK0?L%@i3`f_XuGR}{?<%oN%-_#<1t zSoVqgy{z}(A~rQW9qt9o4=%kj7)&TI!#{775`9+$soavJB}txR?Q#MIMtCGlCL>59 zJJ2ju3A&&7>LkG>`N|5%CTH= zjZ1gxn}V;ZSJU;r-Ogbf0`H%TE~gZk_cl+ut{Q+z{W44Db8b*FSvxpV~ieCH%ap+%!&nA2+}h z*IV*$Z501J)0;+$TZYHq8E)Gu{+aQnvEr7|@;@1Wv|0Q!`%R<8EqlV>vH#I_@y}B3 z{Sfk-o(Fy*<$D{(KTEo4#P~jL6o+;lv|cOjhaSE!=lA*CNcy8Kzt8X=+BR-Y=V7K75M)`6F=ensJ{Od>91wZTO{)9B;>D< zepk`o7d`(9^Vh8AElm7%p7VbL^Zi`%J;(W1l)s*FZc%ox?fX|K|J8}-&v1ViY2U(q zBKj%rzGeQ|OWee%-vS}`cPk!b{)cV5?e`dakTW^^WuOGoboYZ&bzXqben#oNZ zdn@emzYF`9sP@OSzx&p|#cn.iocoder.boot yudao-common + + + + org.springframework + spring-web + provided + + diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java index 6eed3592b..c2d36e18c 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java @@ -1,8 +1,17 @@ package cn.iocoder.yudao.module.iot.api.device; -import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; +import cn.iocoder.yudao.module.iot.enums.ApiConstants; +import jakarta.annotation.security.PermitAll; import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +// TODO 芋艿:名字可能看情况改下 /** * 设备数据 API * @@ -10,11 +19,35 @@ import jakarta.validation.Valid; */ public interface DeviceDataApi { + // TODO @芋艿:可能会调整 + String PREFIX = ApiConstants.PREFIX + "/device-data"; + /** - * 保存设备数据 + * 更新设备状态 * - * @param createDTO 设备数据 + * @param updateReqDTO 更新请求 */ - void saveDeviceData(@Valid DeviceDataCreateReqDTO createDTO); + @PutMapping(PREFIX + "/update-status") + @PermitAll // TODO 芋艿:后续看看怎么优化下 + CommonResult updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqDTO updateReqDTO); + + /** + * 上报设备事件数据 + * + * @param reportReqDTO 设备事件 + */ + @PostMapping(PREFIX + "/report-event") + @PermitAll // TODO 芋艿:后续看看怎么优化下 + CommonResult reportDeviceEventData(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO); + + /** + * 上报设备属性数据 + * + * @param reportReqDTO 设备数据 + */ + @PostMapping(PREFIX + "/report-property") + @PermitAll // TODO 芋艿:后续看看怎么优化下 + CommonResult reportDevicePropertyData(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/DeviceDataCreateReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/DeviceDataCreateReqDTO.java deleted file mode 100644 index 94bc84b80..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/DeviceDataCreateReqDTO.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.iot.api.device.dto; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import jakarta.validation.constraints.NotNull; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class DeviceDataCreateReqDTO { - - /** - * 产品标识 - */ - @NotNull(message = "产品标识不能为空") - private String productKey; - /** - * 设备名称 - */ - @NotNull(message = "设备名称不能为空") - private String deviceName; - /** - * 消息 - */ - @NotNull(message = "消息不能为空") - private String message; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java new file mode 100644 index 000000000..373905c94 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.iot.api.device.dto; + +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * IoT 设备【事件】数据上报 Request DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class IotDeviceEventReportReqDTO { + + // TODO 芋艿:要不要 id + // TODO 芋艿:要不要 time + + /** + * 产品标识 + */ + @NotEmpty(message = "产品标识不能为空") + private String productKey; + /** + * 设备名称 + */ + @NotEmpty(message = "设备名称不能为空") + private String deviceName; + + /** + * 事件标识 + */ + @NotEmpty(message = "事件标识不能为空") + private String identifier; + /** + * 事件参数 + */ + @NotEmpty(message = "事件参数不能为空") + private Map params; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java new file mode 100644 index 000000000..37a4c6c98 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.iot.api.device.dto; + +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * IoT 设备【属性】数据上报 Request DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class IotDevicePropertyReportReqDTO { + + // TODO 芋艿:要不要 id + // TODO 芋艿:要不要 time + + /** + * 产品标识 + */ + @NotEmpty(message = "产品标识不能为空") + private String productKey; + /** + * 设备名称 + */ + @NotEmpty(message = "设备名称不能为空") + private String deviceName; + /** + * 属性参数 + */ + @NotEmpty(message = "属性参数不能为空") + private Map params; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java new file mode 100644 index 000000000..0b08f2bd1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.iot.api.device.dto; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * IoT 设备状态更新 Request DTO + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class IotDeviceStatusUpdateReqDTO { + + // TODO 芋艿:要不要 id + // TODO 芋艿:要不要 time + + /** + * 产品标识 + */ + @NotEmpty(message = "产品标识不能为空") + private String productKey; + /** + * 设备名称 + */ + @NotEmpty(message = "设备名称不能为空") + private String deviceName; + /** + * 设备状态 + */ + @NotEmpty(message = "设备状态不能为空") + @InEnum(IotDeviceStatusEnum.class) // 只使用:在线、离线 + private Integer status; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ApiConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ApiConstants.java new file mode 100644 index 000000000..2c4147be1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ApiConstants.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.enums; + +import cn.iocoder.yudao.framework.common.enums.RpcConstants; + +/** + * API 相关的枚举 + * + * @author 芋道源码 + */ +public class ApiConstants { + + public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/iot"; + + public static final String VERSION = "1.0.0"; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java index eea7b2a96..cdcfdfdfd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java @@ -1,16 +1,21 @@ package cn.iocoder.yudao.module.iot.api.device; -import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; -import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + /** * 设备数据 API 实现类 */ -@Service +@RestController @Validated public class DeviceDataApiImpl implements DeviceDataApi { @@ -18,8 +23,19 @@ public class DeviceDataApiImpl implements DeviceDataApi { private IotDevicePropertyDataService deviceDataService; @Override - public void saveDeviceData(DeviceDataCreateReqDTO createDTO) { - deviceDataService.saveDeviceData(createDTO); + public CommonResult updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { + return success(true); + } + + @Override + public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { + return success(true); + } + + @Override + public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { + deviceDataService.saveDeviceData(reportReqDTO); + return success(true); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index 3c21a55ca..222d1d50a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.emq.service; -import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -34,10 +34,10 @@ public class EmqxServiceImpl implements EmqxService { String productKey = topic.split("/")[2]; String deviceName = topic.split("/")[3]; String message = new String(mqttMessage.getPayload()); - DeviceDataCreateReqDTO createDTO = DeviceDataCreateReqDTO.builder() + IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder() .productKey(productKey) .deviceName(deviceName) - .message(message) +// .properties(message) // TODO 芋艿:临时去掉,看看 .build(); iotDeviceDataService.saveDeviceData(createDTO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index 150051ce5..e27d9b5fb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -7,8 +7,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.nio.file.Paths; - // TODO @芋艿:需要 review 下 @Slf4j @Configuration @@ -21,8 +19,8 @@ public class UnifiedConfiguration { // @DependsOn("deviceDataApiImpl") public SpringPluginManager pluginManager() { log.info("[init][实例化 SpringPluginManager]"); - SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { -// SpringPluginManager springPluginManager = new SpringPluginManager() { +// SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { + SpringPluginManager springPluginManager = new SpringPluginManager() { @Override public void startPlugins() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java index a882b5d6c..396cbf79f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import jakarta.validation.Valid; @@ -28,7 +28,7 @@ public interface IotDevicePropertyDataService { * * @param createDTO 设备数据 */ - void saveDeviceData(DeviceDataCreateReqDTO createDTO); + void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); /** * 获得设备属性最新数据 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index 0f9523414..aefaac696 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -6,7 +6,7 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -130,11 +130,12 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe } @Override - public void saveDeviceData(DeviceDataCreateReqDTO createDTO) { + public void saveDeviceData(IotDevicePropertyReportReqDTO createDTO) { + // TODO 芋艿:这块需要实现 // 1. 根据产品 key 和设备名称,获得设备信息 IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName()); // 2. 解析消息,保存数据 - JSONObject jsonObject = new JSONObject(createDTO.getMessage()); + JSONObject jsonObject = new JSONObject(createDTO.getParams()); log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject); ThingModelMessage thingModelMessage = ThingModelMessage.builder() .id(jsonObject.getStr("id")) diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml index 40bb303bc..cfea78964 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml @@ -124,7 +124,7 @@ org.springframework.boot - spring-boot-starter + spring-boot-starter-web diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java index 2b871cade..7b29367d2 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java @@ -1,13 +1,26 @@ package cn.iocoder.yudao.module.iot; import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; +// TODO @haohao:建议包名:cn.iocoder.yudao.module.iot.plugin.${pluginName},例如说 http。然后子包如下: +// config:方配置类,以及 HttpVertxPlugin 初始化 +// service:放 HttpVertxHandler 逻辑; @SpringBootApplication public class HttpPluginSpringbootApplication { public static void main(String[] args) { - SpringApplication.run(HttpPluginSpringbootApplication.class, args); +// SpringApplication.run(HttpPluginSpringbootApplication.class, args); + SpringApplication application = new SpringApplication(HttpPluginSpringbootApplication.class); + application.setWebApplicationType(WebApplicationType.NONE); + application.run(args); } -} \ No newline at end of file +} + +// TODO @haohao:如下是 sdk 的包:cn.iocoder.yudao.module.iot.plugin.sdk +// 1. api 包:实现 DeviceDataApi 接口,通过 resttemplate 调用 +// 2. config 包:初始化 DeviceDataApi 等等 + +// 3. 其中 resttemplate 调用的后端地址,通过每个服务的 application.yaml 进行注入。 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java index 1931268b6..18f6b285e 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java @@ -1,23 +1,59 @@ package cn.iocoder.yudao.module.iot.config; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; import org.pf4j.DefaultPluginManager; import org.pf4j.PluginWrapper; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; // TODO 芋艿:临时实现; @Configuration public class TestConfiguration { +// @Resource +// private RestTemplate restTemplate; + + // TODO 芋艿:这里,后续看看怎么创建好点 @Bean - public DeviceDataApi deviceDataApi() { + public RestTemplate restTemplate() { + return new RestTemplateBuilder().build(); + } + + @Bean + public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { return new DeviceDataApi() { @Override - public void saveDeviceData(DeviceDataCreateReqDTO createDTO) { - System.out.println("saveDeviceData"); + public CommonResult updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { + // TODO haohao:待实现 + return null; + } + + @Override + public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { + // TODO haohao:待实现 + return null; + } + + @Override + public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { + // TODO haohao:待完整实现 + String url = "http://127.0.0.1:48080/rpc-api/iot/device-data/report-property"; + try { + restTemplate.postForObject(url, reportReqDTO, CommonResult.class); + return success(true); + } catch (Exception e) { + e.printStackTrace(); + return CommonResult.error(400, "error"); + } } }; diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java index 8542cfefb..b92b0869b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import io.vertx.core.Handler; import io.vertx.ext.web.RequestBody; import io.vertx.ext.web.RoutingContext; @@ -46,12 +46,12 @@ public class HttpVertxHandler implements Handler { try { // 调用主程序的接口保存数据 - DeviceDataCreateReqDTO createDTO = DeviceDataCreateReqDTO.builder() + IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder() .productKey(productKey) .deviceName(deviceName) - .message(jsonData.toString()) + .params(jsonData) // TODO 芋艿:这块要优化 .build(); - deviceDataApi.saveDeviceData(createDTO); + deviceDataApi.reportDevicePropertyData(createDTO); // 构造成功响应内容 JSONObject successRes = createResponseJson( From 0707792755e5e416d13664f4c34d302b8f2be154 Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Wed, 22 Jan 2025 16:59:00 +0800 Subject: [PATCH 092/228] =?UTF-8?q?[fix]=EF=BC=9Acode=20=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../deviceconsumer/DeviceConsumer.java | 37 +++++++++++++++++++ .../simulatesend/SimulateSendConsumer.java | 1 - .../module/iot/mq/message/package-info.java | 4 ++ .../simulatesend/SimulateSendProducer.java | 9 +++++ .../device/IotDeviceLogDataService.java | 4 ++ .../device/IotDeviceLogDataServiceImpl.java | 6 +++ .../device/IotDevicePropertyDataService.java | 9 +++++ .../IotDevicePropertyDataServiceImpl.java | 9 +++++ 8 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java new file mode 100644 index 000000000..63e0fed7f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.deviceconsumer; + + +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; +import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 针对 {@link ThingModelMessage} 的消费者 + * + * @author alwayssuper + */ +@Component +@Slf4j +public class DeviceConsumer { + @Resource + private IotDeviceLogDataService iotDeviceLogDataService; + @Resource + private IotDevicePropertyDataService deviceDataService; + + // TODO @芋艿:这块先用ThingModelMessage,后续看看用啥替代 + @EventListener + @Async + public void onMessage(ThingModelMessage message) { + log.info("[onMessage][消息内容({})]", message); + deviceDataService.saveDeviceDataTest(message); + iotDeviceLogDataService.saveDeviceLog(message); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java index 111cf5007..1003fe7f4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java @@ -4,7 +4,6 @@ package cn.iocoder.yudao.module.iot.mq.consumer.simulatesend; * TODO @alwayssuper:记得实现,还有类注释哈 * * @author alwayssuper - * @since 2024/12/20 8:04 */ public class SimulateSendConsumer { } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java new file mode 100644 index 000000000..c3adf7c06 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java @@ -0,0 +1,4 @@ +/** + * 消息队列的消息 + */ +package cn.iocoder.yudao.module.iot.mq.message; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java index 411ddd6f2..1fb0c80c0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.mq.producer.simulatesend; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; @@ -19,4 +20,12 @@ public class SimulateSendProducer { @Resource private ApplicationContext applicationContext; + /** + * 发送 {@link ThingModelMessage} 消息 + * + * @param thingModelMessage 物模型消息 + */ + public void sendSimulateMessage(ThingModelMessage thingModelMessage) { + applicationContext.publishEvent(thingModelMessage); + } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java index a92d46bf4..2ddf1113a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; /** * IoT 设备日志数据 Service 接口 @@ -36,4 +37,7 @@ public interface IotDeviceLogDataService { */ PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO); + + void saveDeviceLog(ThingModelMessage msg); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java index 85f950d5d..e514d2049 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -76,4 +77,9 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ return new PageResult<>(list, total); } + @Override + public void saveDeviceLog(ThingModelMessage msg) { + + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java index 396cbf79f..63cb5d6d9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import jakarta.validation.Valid; import java.util.List; @@ -30,6 +31,14 @@ public interface IotDevicePropertyDataService { */ void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); + + /** + * 保存设备数据 + * + * @param thingModelMessage 设备数据 + */ + void saveDeviceDataTest(ThingModelMessage thingModelMessage); + /** * 获得设备属性最新数据 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index aefaac696..c89f27346 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -150,6 +150,15 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe thingModelMessageService.saveThingModelMessage(device, thingModelMessage); } + //TODO:后续捋一捋这块逻辑,先借鉴一下目前的代码 + @Override + public void saveDeviceDataTest(ThingModelMessage thingModelMessage) { + // 1. 根据产品 key 和设备名称,获得设备信息 + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(thingModelMessage.getProductKey(), thingModelMessage.getDeviceName()); + // 2. 保存数据 + thingModelMessageService.saveThingModelMessage(device, thingModelMessage); + } + @Override public List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { List list = new ArrayList<>(); From 2b27085ec2284b0db8ad42da553c0678f08ce526 Mon Sep 17 00:00:00 2001 From: alwayssuper <12851801+alwayssuper@user.noreply.gitee.com> Date: Wed, 22 Jan 2025 22:08:10 +0800 Subject: [PATCH 093/228] feat:simulator2 --- .../admin/device/IotDeviceDataController.java | 6 +++-- .../device/IotDevicePropertyDataService.java | 9 +++++++ .../IotDevicePropertyDataServiceImpl.java | 26 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index be451f17a..7879698e3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; @@ -54,10 +55,11 @@ public class IotDeviceDataController { // TODO:数据权限 @PostMapping("/simulator") @Operation(summary = "模拟设备") - public CommonResult simulatorDevice(@Valid @RequestBody IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { + public CommonResult simulatorDevice(@Valid @RequestBody IotDeviceDataSimulatorSaveReqVO simulcatorReqVO) { //TODO:先生成一下设备日志 后续完善模拟设备代码逻辑 // TODO @super:应该 deviceDataService 里面有个 simulatorDevice,然后里面去 insert 日志! - iotDeviceLogDataService.createDeviceLog(simulatorReqVO); + IotDevicePropertyReportReqDTO simulatorReqVO = new IotDevicePropertyReportReqDTO(); + deviceDataService.simulateSend(simulatorReqVO); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java index 63cb5d6d9..4e535c9f2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import jakarta.validation.Valid; @@ -39,6 +40,14 @@ public interface IotDevicePropertyDataService { */ void saveDeviceDataTest(ThingModelMessage thingModelMessage); + /** + * 模拟设备 + * + * @param simulatorReqVO 设备数据 + */ + + void simulateSend(IotDevicePropertyReportReqDTO simulatorReqVO); + /** * 获得设备属性最新数据 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index c89f27346..00b29f07e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -8,6 +8,7 @@ import cn.hutool.json.JSONObject; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; @@ -22,6 +23,7 @@ import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; +import cn.iocoder.yudao.module.iot.mq.producer.simulatesend.SimulateSendProducer; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; @@ -76,6 +78,9 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe @Resource private IotProductService productService; + @Resource + private SimulateSendProducer simulateSendProducer; + @Resource private TdEngineDMLMapper tdEngineDMLMapper; @@ -159,6 +164,27 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe thingModelMessageService.saveThingModelMessage(device, thingModelMessage); } + //TODO: copy了saveDeviceData的逻辑,后续看看这块怎么优化 + @Override + public void simulateSend(IotDevicePropertyReportReqDTO simulatorReqVO) { + // 1. 根据产品 key 和设备名称,获得设备信息 + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(simulatorReqVO.getProductKey(), simulatorReqVO.getDeviceName()); + // 2. 解析消息,保存数据 + JSONObject jsonObject = new JSONObject(simulatorReqVO.getParams()); + log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", simulatorReqVO.getProductKey(), simulatorReqVO.getDeviceName(), jsonObject); + ThingModelMessage thingModelMessage = ThingModelMessage.builder() + .id(jsonObject.getStr("id")) + .sys(jsonObject.get("sys")) + .method(jsonObject.getStr("method")) + .params(jsonObject.get("params")) + .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time")) + .productKey(simulatorReqVO.getProductKey()) + .deviceName(simulatorReqVO.getDeviceName()) + .deviceKey(device.getDeviceKey()) + .build(); + simulateSendProducer.sendSimulateMessage(thingModelMessage); + } + @Override public List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { List list = new ArrayList<>(); From 4f962bd1f73fed4b7fb1c4186300ecd3ca0ac59f Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Thu, 23 Jan 2025 16:54:45 +0800 Subject: [PATCH 094/228] =?UTF-8?q?[fix]=EF=BC=9Acode=20=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../admin/device/IotDeviceDataController.java | 7 ++-- .../IotDeviceDataSimulatorSaveReqVO.java | 1 - .../deviceconsumer/DeviceConsumer.java | 4 +- .../simulatesend/SimulateSendConsumer.java | 9 ----- .../device/IotDeviceLogDataService.java | 6 ++- .../device/IotDeviceLogDataServiceImpl.java | 14 +++++++ .../device/IotDevicePropertyDataService.java | 2 +- .../IotDevicePropertyDataServiceImpl.java | 39 ++++++++++++------- .../iot/service/device/IotDeviceService.java | 9 +++++ .../service/device/IotDeviceServiceImpl.java | 5 +++ .../mapper/device/IotDeviceLogDataMapper.xml | 2 +- 12 files changed, 68 insertions(+), 31 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 4539f1259..305aa6c7f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -30,6 +30,7 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在"); ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备"); ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!"); + ErrorCode DEVICE_DATA_CONTENT_JSON_PARSE_ERROR = new ErrorCode(1_050_003_007, "导入设备数据格式错误!"); // ========== 产品分类 1-050-004-000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 7879698e3..f78a96b24 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -55,11 +55,10 @@ public class IotDeviceDataController { // TODO:数据权限 @PostMapping("/simulator") @Operation(summary = "模拟设备") - public CommonResult simulatorDevice(@Valid @RequestBody IotDeviceDataSimulatorSaveReqVO simulcatorReqVO) { - //TODO:先生成一下设备日志 后续完善模拟设备代码逻辑 + public CommonResult simulatorDevice(@Valid @RequestBody IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { + //TODO:先使用 IotDeviceDataSimulatorSaveReqVO 另外content里数据类型的效验前端也没做,后端应该要要效验一下,这块后续看看怎么安排 // TODO @super:应该 deviceDataService 里面有个 simulatorDevice,然后里面去 insert 日志! - IotDevicePropertyReportReqDTO simulatorReqVO = new IotDevicePropertyReportReqDTO(); - deviceDataService.simulateSend(simulatorReqVO); + deviceDataService.simulatorSend(simulatorReqVO); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java index 5e2b08543..4d09808b1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java @@ -38,7 +38,6 @@ public class IotDeviceDataSimulatorSaveReqVO { @NotEmpty(message = "数据内容不能为空") private String content; - // TODO @芋艿:需要讨论下,reportTime 到底以那个为准! @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED) private Long reportTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java index 63e0fed7f..862fb4d82 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java @@ -30,7 +30,9 @@ public class DeviceConsumer { @Async public void onMessage(ThingModelMessage message) { log.info("[onMessage][消息内容({})]", message); - deviceDataService.saveDeviceDataTest(message); + // 设备数据记录 +// deviceDataService.saveDeviceDataTest(message); + // 设备日志记录 iotDeviceLogDataService.saveDeviceLog(message); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java deleted file mode 100644 index 1003fe7f4..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/simulatesend/SimulateSendConsumer.java +++ /dev/null @@ -1,9 +0,0 @@ -package cn.iocoder.yudao.module.iot.mq.consumer.simulatesend; - -/** - * TODO @alwayssuper:记得实现,还有类注释哈 - * - * @author alwayssuper - */ -public class SimulateSendConsumer { -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java index 2ddf1113a..2d7bf9850 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java @@ -37,7 +37,11 @@ public interface IotDeviceLogDataService { */ PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO); - + /** + * 插入设备日志 + * + * @param msg 设备数据 + */ void saveDeviceLog(ThingModelMessage msg); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java index e514d2049..bee966e72 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; @@ -12,6 +13,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Date; import java.util.List; /** @@ -79,7 +81,19 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ @Override public void saveDeviceLog(ThingModelMessage msg) { + // 1. 构建设备日志对象 + IotDeviceLogDO iotDeviceLogDO = IotDeviceLogDO.builder() + .id(msg.getId()) // 消息ID + .deviceKey(msg.getDeviceKey()) // 设备标识 + .productKey(msg.getProductKey()) // 产品标识 + .type(msg.getMethod()) // 消息类型,使用method作为类型 + .subType("property") // TODO:这块先写死,后续优化 + .content(JSONUtil.toJsonStr(msg)) // TODO:后续优化 + .reportTime(msg.getTime()) // 上报时间 + .build(); + // 2. 插入设备日志 + iotDeviceLogDataMapper.insert(iotDeviceLogDO); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java index 4e535c9f2..92a64c28f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java @@ -46,7 +46,7 @@ public interface IotDevicePropertyDataService { * @param simulatorReqVO 设备数据 */ - void simulateSend(IotDevicePropertyReportReqDTO simulatorReqVO); + void simulatorSend(IotDeviceDataSimulatorSaveReqVO simulatorReqVO); /** * 获得设备属性最新数据 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index 00b29f07e..134803c8e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -3,8 +3,10 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; @@ -39,8 +41,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_CONTENT_JSON_PARSE_ERROR; /** * IoT 设备【属性】数据 Service 实现类 @@ -164,24 +168,33 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe thingModelMessageService.saveThingModelMessage(device, thingModelMessage); } - //TODO: copy了saveDeviceData的逻辑,后续看看这块怎么优化 + //TODO: copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 @Override - public void simulateSend(IotDevicePropertyReportReqDTO simulatorReqVO) { - // 1. 根据产品 key 和设备名称,获得设备信息 - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(simulatorReqVO.getProductKey(), simulatorReqVO.getDeviceName()); - // 2. 解析消息,保存数据 - JSONObject jsonObject = new JSONObject(simulatorReqVO.getParams()); - log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", simulatorReqVO.getProductKey(), simulatorReqVO.getDeviceName(), jsonObject); + public void simulatorSend(IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { + // 1. 根据设备 key ,获得设备信息 + IotDeviceDO device = deviceService.getDeviceByDeviceKey(simulatorReqVO.getDeviceKey()); + + // 2. 解析 content 为 JSON 对象 + JSONObject contentJson; + try { + contentJson = JSONUtil.parseObj(simulatorReqVO.getContent()); + } catch (Exception e) { + throw exception(DEVICE_DATA_CONTENT_JSON_PARSE_ERROR); + } + + // 3. 构建物模型消息 ThingModelMessage thingModelMessage = ThingModelMessage.builder() - .id(jsonObject.getStr("id")) - .sys(jsonObject.get("sys")) - .method(jsonObject.getStr("method")) - .params(jsonObject.get("params")) - .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time")) + .id(IdUtil.fastSimpleUUID()) // TODO:后续优化 + .sys(null)// TODO:这块先写死,后续优化 + .method("thing.event.property.post") // TODO:这块先写死,后续优化 + .params(contentJson) // 将 content 作为 params + .time(simulatorReqVO.getReportTime()) // 使用上报时间 .productKey(simulatorReqVO.getProductKey()) - .deviceName(simulatorReqVO.getDeviceName()) + .deviceName(device.getDeviceName()) .deviceKey(device.getDeviceKey()) .build(); + + // 4. 发送模拟消息 simulateSendProducer.sendSimulateMessage(thingModelMessage); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index b8a3511cd..adf3304d0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -72,6 +72,15 @@ public interface IotDeviceService { */ IotDeviceDO getDevice(Long id); + + /** + * 根据设备 key 获得设备 + * + * @param deviceKey 编号 + * @return IoT 设备 + */ + IotDeviceDO getDeviceByDeviceKey(String deviceKey); + /** * ��得设备分页 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 1896b98b7..6a28b27f3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -197,6 +197,11 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectById(id); } + @Override + public IotDeviceDO getDeviceByDeviceKey(String deviceKey) { + return deviceMapper.selectByDeviceKey(deviceKey); + } + @Override public PageResult getDevicePage(IotDevicePageReqVO pageReqVO) { return deviceMapper.selectPage(pageReqVO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml index 4a60f8f78..1e9b3fdff 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml @@ -27,7 +27,7 @@ - INSERT INTO device_log_${log.deviceKey} (id, product_key, type, subType, content, report_time) + INSERT INTO device_log_${log.deviceKey} (ts, id, product_key, type, subType, content, report_time) USING device_log TAGS ('${log.deviceKey}') VALUES ( From 03d4f60e8027b2e6125e2db4077d87c72ba72ccf Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Fri, 24 Jan 2025 15:56:01 +0800 Subject: [PATCH 095/228] =?UTF-8?q?[fix]=EF=BC=9Acode=20=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dataobject/tdengine/SelectVisualDO.java | 3 ++ .../dal/dataobject/tdengine/TdTableDO.java | 4 ++ .../dal/tdengine/IotDeviceLogDataMapper.java | 11 ++++- .../tdengine/IotDevicePropertyDataMapper.java | 43 +++++++++++++++++++ .../deviceconsumer/DeviceConsumer.java | 4 +- .../device/IotDeviceLogDataServiceImpl.java | 8 +++- .../IotDevicePropertyDataServiceImpl.java | 5 ++- .../IotThingModelMessageServiceImpl.java | 23 +++++++--- .../mapper/device/IotDeviceLogDataMapper.xml | 8 +++- .../device/IotDevicePropertyDataMapper.xml | 42 ++++++++++++++++++ 10 files changed, 138 insertions(+), 13 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java index 584562bfa..c9ac20af2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectVisualDO.java @@ -19,6 +19,9 @@ public class SelectVisualDO { */ private String tableName; + + private String deviceKey; + /** * 属性 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java index 3265c3ebe..104be2683 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java @@ -33,6 +33,10 @@ public class TdTableDO { */ private String tableName; + private String productKey; + + private String deviceKey; + /** * COLUMN 字段 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java index 40516c794..2d8230f1f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java @@ -68,6 +68,15 @@ public interface IotDeviceLogDataMapper { /** * 查询设备日志表是否存在 * + * @return 不存在返回null */ - Object checkDeviceLogTableExists(); + Object checkDeviceLogSTableExists(); + + /** + * 检查设备日志子表是否存在 + * + * @param deviceKey 设备标识 + * @return 不存在返回null + */ + Object checkDeviceLogTableExists(@Param("deviceKey") String deviceKey); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java index 6053444fe..1599ce957 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; @@ -10,6 +13,7 @@ import org.apache.ibatis.annotations.Param; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Mapper @@ -74,4 +78,43 @@ public interface IotDevicePropertyDataMapper { void alterProductPropertySTableDropField(@Param("productKey") String productKey, @Param("field") TDengineTableField field); + //TODO:先参考一下老逻辑,后续改进 + /** + * 插入数据 - 指定列插入数据 + * + * @param table 数据 + * productKey 产品 key + * deviceKey 设备 key + * columns 列 + */ + void insertDevicePropertyData(TdTableDO table); + + //TODO:先参考一下老逻辑,后续改进 + /** + * 查看超级表 - 获取超级表的结构信息 + * SQL:DESCRIBE [db_name.]stb_name; + * + * @param superTable 超级表信息 + * productKey 产品 key + */ + List> describeSuperTable(TdTableDO superTable); + + /** + * 获取历史数据列表 + * + * @param selectVisualDO 查询条件 + * @return 历史数据列表 + */ + @TenantIgnore + List> selectHistoryDataList(SelectVisualDO selectVisualDO); + + /** + * 获取历史数据条数 + * + * @param selectVisualDO 查询条件 + * @return 数据条数 + */ + @TenantIgnore + Long selectHistoryCount(SelectVisualDO selectVisualDO); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java index 862fb4d82..1daa05f92 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java @@ -30,8 +30,10 @@ public class DeviceConsumer { @Async public void onMessage(ThingModelMessage message) { log.info("[onMessage][消息内容({})]", message); + //TODO:数据插入这块整体写的比较混乱,整体借鉴了浩浩哥之前写的逻辑,目前是通过模拟设备科插入数据了,但之前的逻辑有大量弃用的部分,后续看看怎么完善 + // 设备数据记录 -// deviceDataService.saveDeviceDataTest(message); + deviceDataService.saveDeviceDataTest(message); // 设备日志记录 iotDeviceLogDataService.saveDeviceLog(message); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java index bee966e72..f66bcc8ad 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java @@ -43,8 +43,8 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ // } // throw e; // } - if(iotDeviceLogDataMapper.checkDeviceLogTableExists()==null){ - log.info("[TDengine] 设备日志超级表不存在,开始创建 {}",iotDeviceLogDataMapper.checkDeviceLogTableExists()); + if(iotDeviceLogDataMapper.checkDeviceLogSTableExists()==null){ + log.info("[TDengine] 设备日志超级表不存在,开始创建"); iotDeviceLogDataMapper.createDeviceLogSTable(); }else{ log.info("[TDengine] 设备日志超级表已存在,跳过创建"); @@ -72,6 +72,10 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ // 讨论:艿菇 这就是iotDeviceLogDataService的Impl @Override public PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { + // 当设备日志表未创建时,查询会出现报错 + if(iotDeviceLogDataMapper.checkDeviceLogTableExists(pageReqVO.getDeviceKey())==null){ + return null; + } // 查询数据 List list = iotDeviceLogDataMapper.selectPage(pageReqVO); Long total = iotDeviceLogDataMapper.selectCount(pageReqVO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index 134803c8e..2b998e788 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -244,6 +244,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe SelectVisualDO selectVisualDO = new SelectVisualDO(); selectVisualDO.setDataBaseName(getDatabaseName()); selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); + selectVisualDO.setDeviceKey(device.getDeviceKey()); selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier()); selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); @@ -251,8 +252,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe params.put("rows", deviceDataReqVO.getPageSize()); params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); selectVisualDO.setParams(params); - pageResult.setList(tdEngineDMLMapper.selectHistoryDataList(selectVisualDO)); - pageResult.setTotal(tdEngineDMLMapper.selectHistoryCount(selectVisualDO)); + pageResult.setList(devicePropertyDataMapper.selectHistoryDataList(selectVisualDO)); + pageResult.setTotal(devicePropertyDataMapper.selectHistoryCount(selectVisualDO)); return pageResult; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java index e094b34cb..c35bb3a28 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; @@ -61,6 +62,9 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ @Resource private TdEngineDMLMapper tdEngineDMLMapper; + @Resource + private IotDevicePropertyDataMapper iotDevicePropertyDataMapper; + @Resource private DeviceDataRedisDAO deviceDataRedisDAO; @@ -71,7 +75,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态 if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { // 1.1 创建设备表 - createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); +// createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); } @@ -85,14 +89,20 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 3. 过滤并收集有效的属性字段,缓存设备属性 List schemaFieldValues = filterAndCollectValidFields(params, thingModelList, device, thingModelMessage.getTime()); - if (schemaFieldValues.size() == 1) { // 仅有时间字段,无需保存 + if (schemaFieldValues.size() == 0) { // 没有字段,无需保存 return; } // 4. 构建并保存设备属性数据 - tdEngineDMLMapper.insertData(TdTableDO.builder() - .dataBaseName(getDatabaseName()) - .tableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())) +// tdEngineDMLMapper.insertData(TdTableDO.builder() +// .dataBaseName(getDatabaseName()) +// .tableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())) +// .columns(schemaFieldValues) +// .build()); + // TODO:复用了旧逻辑,先过渡一下 + iotDevicePropertyDataMapper.insertDevicePropertyData(TdTableDO.builder() + .productKey(device.getProductKey()) + .deviceKey(device.getDeviceKey()) .columns(schemaFieldValues) .build()); } @@ -145,7 +155,8 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ // 3. 过滤并收集有效的属性字段 List schemaFieldValues = new ArrayList<>(); - schemaFieldValues.add(new TdFieldDO(TIME, time)); + //TODO:新版本是使用ts字段 +// schemaFieldValues.add(new TdFieldDO(TIME, time)); params.forEach((key, val) -> { if (propertyIdentifiers.contains(key)) { schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val)); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml index 1e9b3fdff..828522ed7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml @@ -76,8 +76,14 @@ - SHOW STABLES LIKE 'device_log' + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml index 9894e27a0..3ac238d75 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml @@ -42,4 +42,46 @@ DROP COLUMN ${field.field} + + INSERT INTO device_property_${deviceKey} + USING product_property_${productKey} + TAGS ('${deviceKey}') + (ts + + ,${item.fieldName} + + ) + VALUES + (NOW + + ,#{item.fieldValue} + + ) + + + + + + + + + + + \ No newline at end of file From 698cec92bdf4f5c416874fd89fb6cbc50b8d9c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 24 Jan 2025 23:17:26 +0800 Subject: [PATCH 096/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E9=87=8D=E5=91=BD=E5=90=8D=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E6=A8=A1=E5=9D=97=EF=BC=8C=E9=87=8D=E6=9E=84=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E7=AE=A1=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=EF=BC=8C=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=96=B0=E6=8F=92=E4=BB=B6=E6=9E=B6=E6=9E=84=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/pom.xml | 2 +- .../dependency-reduced-pom.xml | 43 ------------ .../iot/HttpPluginSpringbootApplication.java | 26 ------- .../module/iot/config/TestConfiguration.java | 69 ------------------- .../pom.xml | 3 +- .../yudao-module-iot-plugin-common/pom.xml | 55 +++++++++++++++ .../common/api/DeviceDataApiClient.java | 60 ++++++++++++++++ .../config/DeviceDataApiInitializer.java | 29 ++++++++ .../iot/plugin/common/package-info.java | 1 + .../plugin.properties | 0 .../yudao-module-iot-plugin-emqx/pom.xml | 2 +- .../src/main/assembly/assembly.xml | 0 .../yudao/module/iot/plugin/EmqxPlugin.java | 0 .../plugin.properties | 2 +- .../yudao-module-iot-plugin-http/pom.xml | 20 +----- .../src/main/assembly/assembly.xml | 0 .../http/HttpPluginSpringbootApplication.java | 16 +++++ .../plugin/http}/config/HttpVertxPlugin.java | 4 +- .../config/HttpVertxPluginConfiguration.java | 16 +++++ .../http}/service/HttpVertxHandler.java | 2 +- .../src/main/resources/application.yml | 4 ++ .../plugin.properties | 0 .../yudao-module-iot-plugin-mqtt/pom.xml | 2 +- .../src/main/assembly/assembly.xml | 0 .../yudao/module/iot/plugin/MqttPlugin.java | 0 .../iot/plugin/MqttServerExtension.java | 0 26 files changed, 193 insertions(+), 163 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/pom.xml (87%) create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-emqx/plugin.properties (100%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-emqx/pom.xml (99%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml (100%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java (100%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-http/plugin.properties (67%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-http/pom.xml (87%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml (100%) create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java rename yudao-module-iot/{yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot => yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http}/config/HttpVertxPlugin.java (95%) create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java rename yudao-module-iot/{yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot => yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http}/service/HttpVertxHandler.java (98%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-http/src/main/resources/application.yml (53%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-mqtt/plugin.properties (100%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-mqtt/pom.xml (99%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml (100%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java (100%) rename yudao-module-iot/{yudao-module-iot-plugin => yudao-module-iot-plugins}/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java (100%) diff --git a/yudao-module-iot/pom.xml b/yudao-module-iot/pom.xml index d9002abea..0422c5d6c 100644 --- a/yudao-module-iot/pom.xml +++ b/yudao-module-iot/pom.xml @@ -10,7 +10,7 @@ yudao-module-iot-api yudao-module-iot-biz - yudao-module-iot-plugin + yudao-module-iot-plugins 4.0.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml deleted file mode 100644 index 260ef9c8d..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - yudao-module-iot-plugin - cn.iocoder.boot - 2.2.0-snapshot - - 4.0.0 - yudao-module-iot-plugin-http - ${project.artifactId} - 1.0.0 - 物联网 插件模块 - http 插件 - - - - maven-shade-plugin - 3.2.4 - - - package - - shade - - - - - com.example.HttpPluginSpringbootApplication - - - - - - - - - - ${project.artifactId} - ${project.artifactId}-${project.version} - cn.iocoder.yudao.module.iot.config.HttpVertxPlugin - ${project.version} - yudao - - diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java deleted file mode 100644 index 7b29367d2..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.iot; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -// TODO @haohao:建议包名:cn.iocoder.yudao.module.iot.plugin.${pluginName},例如说 http。然后子包如下: -// config:方配置类,以及 HttpVertxPlugin 初始化 -// service:放 HttpVertxHandler 逻辑; -@SpringBootApplication -public class HttpPluginSpringbootApplication { - - public static void main(String[] args) { -// SpringApplication.run(HttpPluginSpringbootApplication.class, args); - SpringApplication application = new SpringApplication(HttpPluginSpringbootApplication.class); - application.setWebApplicationType(WebApplicationType.NONE); - application.run(args); - } - -} - -// TODO @haohao:如下是 sdk 的包:cn.iocoder.yudao.module.iot.plugin.sdk -// 1. api 包:实现 DeviceDataApi 接口,通过 resttemplate 调用 -// 2. config 包:初始化 DeviceDataApi 等等 - -// 3. 其中 resttemplate 调用的后端地址,通过每个服务的 application.yaml 进行注入。 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java deleted file mode 100644 index 18f6b285e..000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.iocoder.yudao.module.iot.config; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; -import org.pf4j.DefaultPluginManager; -import org.pf4j.PluginWrapper; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -// TODO 芋艿:临时实现; -@Configuration -public class TestConfiguration { - -// @Resource -// private RestTemplate restTemplate; - - // TODO 芋艿:这里,后续看看怎么创建好点 - @Bean - public RestTemplate restTemplate() { - return new RestTemplateBuilder().build(); - } - - @Bean - public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { - return new DeviceDataApi() { - - @Override - public CommonResult updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { - // TODO haohao:待实现 - return null; - } - - @Override - public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { - // TODO haohao:待实现 - return null; - } - - @Override - public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { - // TODO haohao:待完整实现 - String url = "http://127.0.0.1:48080/rpc-api/iot/device-data/report-property"; - try { - restTemplate.postForObject(url, reportReqDTO, CommonResult.class); - return success(true); - } catch (Exception e) { - e.printStackTrace(); - return CommonResult.error(400, "error"); - } - } - - }; - } - - // TODO @haohao:可能要看下,有没更好的方式 - @Bean(initMethod = "start") - public HttpVertxPlugin HttpVertxPlugin() { - PluginWrapper pluginWrapper = new PluginWrapper(new DefaultPluginManager(), null, null, null); - return new HttpVertxPlugin(pluginWrapper); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/pom.xml similarity index 87% rename from yudao-module-iot/yudao-module-iot-plugin/pom.xml rename to yudao-module-iot/yudao-module-iot-plugins/pom.xml index 949ff13e6..d33292527 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/pom.xml @@ -8,6 +8,7 @@ ${revision} + yudao-module-iot-plugin-common yudao-module-iot-plugin-http yudao-module-iot-plugin-mqtt yudao-module-iot-plugin-emqx @@ -15,7 +16,7 @@ 4.0.0 - yudao-module-iot-plugin + yudao-module-iot-plugins pom ${project.artifactId} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml new file mode 100644 index 000000000..568f86200 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml @@ -0,0 +1,55 @@ + + + + yudao-module-iot-plugins + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-module-iot-plugin-common + jar + + ${project.artifactId} + + 物联网 插件 模块 - 通用功能 + + + + + cn.iocoder.boot + yudao-common + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.pf4j + pf4j-spring + + + org.slf4j + slf4j-log4j12 + + + + + + org.projectlombok + lombok + + + + diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java new file mode 100644 index 000000000..183c76e58 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.iot.plugin.common.api; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.client.RestTemplate; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Slf4j +public class DeviceDataApiClient implements DeviceDataApi { + + private final RestTemplate restTemplate; + private final String deviceDataUrl; + + // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 + public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) { + this.restTemplate = restTemplate; + this.deviceDataUrl = deviceDataUrl; + } + + @Override + public CommonResult updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { + // 示例:如果对应的远程地址是 /rpc-api/iot/device-data/update-status + String url = deviceDataUrl + "/rpc-api/iot/device-data/update-status"; + return doPost(url, updateReqDTO, "updateDeviceStatus"); + } + + @Override + public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { + // 示例:如果对应的远程地址是 /rpc-api/iot/device-data/report-event + String url = deviceDataUrl + "/rpc-api/iot/device-data/report-event"; + return doPost(url, reportReqDTO, "reportDeviceEventData"); + } + + @Override + public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { + // 示例:如果对应的远程地址是 /rpc-api/iot/device-data/report-property + String url = deviceDataUrl + "/rpc-api/iot/device-data/report-property"; + return doPost(url, reportReqDTO, "reportDevicePropertyData"); + } + + /** + * 将与远程服务交互的通用逻辑抽取成一个私有方法 + */ + private CommonResult doPost(String url, T requestBody, String actionName) { + log.info("[{}] Sending request to URL: {}", actionName, url); + try { + // 这里指定返回类型为 CommonResult,根据后台服务返回的实际结构做调整 + restTemplate.postForObject(url, requestBody, CommonResult.class); + return success(true); + } catch (Exception e) { + log.error("[{}] Error sending request to URL: {}", actionName, url, e); + return CommonResult.error(400, "Request error: " + e.getMessage()); + } + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java new file mode 100644 index 000000000..9473033c2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.plugin.common.config; + +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class DeviceDataApiInitializer { + + @Value("${iot.device-data.url}") + private String deviceDataUrl; + + @Bean + public RestTemplate restTemplate() { + // 如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 + return new RestTemplateBuilder().build(); + } + + @Bean + public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { + // 返回我们自定义的 Client 实例 + return new DeviceDataApiClient(restTemplate, deviceDataUrl); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java new file mode 100644 index 000000000..f9eae496d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.iot.plugin.common; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml similarity index 99% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml index 266e45fd3..cd8974321 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml @@ -4,7 +4,7 @@ http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - yudao-module-iot-plugin + yudao-module-iot-plugins cn.iocoder.boot ${revision} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties similarity index 67% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties index 49aef5b18..bcdce07c9 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties @@ -1,5 +1,5 @@ plugin.id=yudao-module-iot-plugin-http -plugin.class=cn.iocoder.yudao.module.iot.config.HttpVertxPlugin +plugin.class=cn.iocoder.yudao.module.iot.plugin.http.config.HttpVertxPlugin plugin.version=1.0.0 plugin.provider=yudao plugin.dependencies= diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml similarity index 87% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml index cfea78964..15adef3e1 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml @@ -4,7 +4,7 @@ http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - yudao-module-iot-plugin + yudao-module-iot-plugins cn.iocoder.boot ${revision} @@ -22,7 +22,7 @@ ${project.artifactId} - cn.iocoder.yudao.module.iot.config.HttpVertxPlugin + cn.iocoder.yudao.module.iot.plugin.http.config.HttpVertxPlugin ${project.version} yudao ${project.artifactId}-${project.version} @@ -121,26 +121,12 @@ - - - org.springframework.boot - spring-boot-starter-web - - - - org.pf4j - pf4j-spring - cn.iocoder.boot - yudao-module-iot-api + yudao-module-iot-plugin-common ${revision} - - org.projectlombok - lombok - io.vertx diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java new file mode 100644 index 000000000..74c565101 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.plugin.http; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = "cn.iocoder.yudao.module.iot.plugin") +public class HttpPluginSpringbootApplication { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(HttpPluginSpringbootApplication.class); + application.setWebApplicationType(WebApplicationType.NONE); + application.run(args); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java similarity index 95% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java index d77f990c2..e6145b93d 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.config; +package cn.iocoder.yudao.module.iot.plugin.http.config; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.service.HttpVertxHandler; +import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler; import io.vertx.core.Vertx; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java new file mode 100644 index 000000000..b5e977efb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.plugin.http.config; + +import org.pf4j.DefaultPluginManager; +import org.pf4j.PluginWrapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class HttpVertxPluginConfiguration { + + @Bean(initMethod = "start") + public HttpVertxPlugin httpVertxPlugin() { + PluginWrapper pluginWrapper = new PluginWrapper(new DefaultPluginManager(), null, null, null); + return new HttpVertxPlugin(pluginWrapper); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java similarity index 98% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java index b92b0869b..becba2a08 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.service; +package cn.iocoder.yudao.module.iot.plugin.http.service; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml similarity index 53% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml index c5a1ee84c..e98d46eeb 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml @@ -1,3 +1,7 @@ spring: application: name: yudao-module-iot-plugin-http + +iot: + device-data: + url: http://127.0.0.1:48080 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/plugin.properties b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/plugin.properties similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/plugin.properties rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/plugin.properties diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml similarity index 99% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml index 7e4689b4a..e007596dc 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml @@ -4,7 +4,7 @@ http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - yudao-module-iot-plugin + yudao-module-iot-plugins cn.iocoder.boot ${revision} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java From 88ef8ba2e3be7eed2add375dbc07eaf029df8742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 25 Jan 2025 00:12:06 +0800 Subject: [PATCH 097/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E5=88=A0=E9=99=A4=E6=97=A7=E7=89=88?= =?UTF-8?q?=20HTTP=20=E6=8F=92=E4=BB=B6=EF=BC=8C=E9=87=8D=E6=9E=84=20HttpP?= =?UTF-8?q?lugin=20=E4=BB=A5=E6=94=AF=E6=8C=81=E7=8B=AC=E7=AB=8B=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=EF=BC=8C=E6=96=B0=E5=A2=9E=20VertxService=20=E7=AE=A1?= =?UTF-8?q?=E7=90=86=20HTTP=20=E6=9C=8D=E5=8A=A1=E5=99=A8=E9=80=BB?= =?UTF-8?q?=E8=BE=91=EF=BC=8C=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E5=92=8C=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86=EF=BC=8C?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3=E9=85=8D=E7=BD=AE=E4=BB=A5?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E6=8F=92=E4=BB=B6=E6=80=A7=E8=83=BD=E5=92=8C?= =?UTF-8?q?=E5=8F=AF=E7=BB=B4=E6=8A=A4=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 10353 -> 0 bytes .../yudao-module-iot-plugin-http-1.0.0.jar | Bin 10643 -> 12284 bytes .../http/HttpPluginSpringbootApplication.java | 18 +++- .../plugin/http/config/HttpVertxPlugin.java | 84 ++++++++---------- .../config/HttpVertxPluginConfiguration.java | 65 ++++++++++++-- .../iot/plugin/http/config/VertxService.java | 52 +++++++++++ .../plugin/http/service/HttpVertxHandler.java | 66 +++++--------- 7 files changed, 183 insertions(+), 102 deletions(-) delete mode 100644 plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/VertxService.java diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar deleted file mode 100644 index fef8d5362c38ea47e769e58933c715d492df719f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10353 zcmb_?1zeQd(?6YyEF~o!5`uJtpmf91(jhHfvVhb|hvbqX-6co}NOz}nN=t`;@WS$fkzUr?_<<-}A(n55*z zA1eM%h62NRO{QCLl-6u;D&D zD$7WRFfo)XBef=&t|~@Pbt(6cIZ>S!&c1a&@GWs{j6dauNcJ6D!Rt(I`HpZHoVKSo zx`%Bkm?atsM=I_$PnXx>D^n4-_{CZqAlFv%8nc-zty&=#3hzBU0zCr@pX`Rv>UHj? zW3e8~YLVYhZh~=8YijJxwJQ0D;Az)HPot+MeZr|pEHs#|YDQx~|DsU|Y2UnBIPQU- zyQ}(Vo4oCU*^#dHd0K|eLs>H&bC1sQ3~Nu=A1nV^LGafrH+ueuYJMg_|4v|TV`O7& zV*d+5tp6l*b22ut`2{(_-;rC}7&}>+{DSM=FSyKY9Dl({^)H-8HqW1#oBkgJ*jhQ6 zn%`;?<-09XHyB94!N3F~z`*eRcQa5iad3R{+hm;V4IIsFo--R+88|p3gRB*BM1Y>L zcNrwyu&~5LSHzeIX3PQ}ipT*CIp`&$M-G>cYnXz!znIuy?&+;(({k-0pQeYD%lK*m zh?uKqsy{(ZQ{0@toQD_B!3Z=<`@t@wb>OoGP(T7b?8seZ)@Z#zQ*ot61TXU5+4mFL zXRb)Yt`d;8B{1S7*1Wp_so_K3%L!Ua+4GSS&nU{(GlJe@_4J@+hv?RjrM>JJCp2(X zW=KUe?qw%1iRY^9jB48unlm?%%ba@}Nj-FzrH{o0TuDz%X<3~f!IUNjnnW?`5Ti33 zVz2&4F1;dDqPwis;04MmRSjf!#5Er3+J#Vd@i%QBfkkRUV!rw)3jxJ4&h#0$ox=yf9!%SWT8wRCE= z1o_S^jRc$X;OgMqjpRF7UfyC9j<8W0fR|LT5eBTS*!xvdMX=L+MNWyw*mZ7Y=o)um zX3_c;e)xj#1}YjYvktvB&{0Gf7=iys1EpsDZlb*^Pp?fB_Yw(hDi$#|e;yC30?}B6 z*+&ff0g)5~P}+6ZdV-{D(K)-XZ*2E-uve2_8ZE6xG}K-sY+9{>E|yh<%KIeiXeMN$%yG_|HIWZHa;zngYIQqjvD5n6 zEi$T(jak@Q2l7rn*c!hEqTzdYWJZd12~Ua=%OY8(s#k9xyfH4`*+Q2XMh(`TU#Ee5 zmUZU$zvD<$BI}rTK61P$k|PFn?hHseL)#0wzm2hiSd$YozoLy@2Oyy+4#HD9x>wr7 zsgO<<2LQwqw3t9rkURn6nOq0(aDBM)Nx7ZcT_*2`tAZ?%iV~~5DIi5lOyQY_i1#JZ zyS_;l?64i0>Kdav@zdcnSDEOyv{+9Y#23k|7A>0WY30R5_u6YBIg5Rf;V0WnqznNE zO`%Y=V;OXmym-B)#O(0tj3^m1fjz;G!<$ zuF3`TDWs9RH9w~C2%R>PVny+xxd<==zfSq1QwCjv%N2Y>D-uSvXvVM@A-#mak%ik% zasIGqZ?N9quZbe z$y?Da^;H@QtLQ_0Y=BGSgZyK(q2>uuFXA$42`OS)&GHP1b|LRjPwzeNX8Um=r|6k`JY8|TQm0z2bdaj~n& zEQjMMpdTNQ&Kp=k#h9H9{t(u9w zqpPIBb7LzL`|tMNs{Yg#XPodd4E(8L;$>mWOE_3w3i7X&Y1-0O*c<3bzBY|*95mMD zufsAc)N8xGL^euIanMVdVG|`p$7a1hlrDyi6P@sL=JQy~@aU1v#`LhBu0Nu|^jM3& zG^JTeWJv+A_ekyuKVST<9Ymj|-c}k~% z0_m#DvJR3U?0Q?ez>t%p3>+yzBWe!wD@>GclCoD%?V!Ps=;!H7YF$@c(`1Zev;Ou5 z_{rc)P!uu-zqwu9LJ>6?H_nG)p!m}<rMUZNZ8BWu z!HTw6(p(K0KJ?FrgoMmaMdQG>I>3tEecnc3VB3q>yw3_NRrer_v3E*$*wrys%d3=ak ziHL!%P*3m4@B_`fwF8vWjHhJ1+jp>xsC5+BL`FTuoy2`-xh8zS*_UzgZPH;C0WPG& zjU*ZZI2!yCW1%uAX0Txz!;}D_Ez@ol>3T$!SRq@(fQCNTJ0?lVL?tg^@0gQs9?o$X z0cl=~gvR3_S4T#Vro9)Xjcu|uY3mHw93FV+D~BiV{WQ;0wiyectZmCrKT}r`RFu?F zJv5UJfMutrAsgN`7m(*Ln#C2w(XX+eXiOV1uA z`x=WjYf-N-7dEz-rDaNSMY#jAgFh>;mL2L+xl34Aa2N}llr>@Ahj>rjlU4ap<|^%- z-w4lHn@ncPtgo?i#um3>=t}Xz9fNt{3Z)n4!fz=|X|%&Q=h!4!Nn&UBL?zZf_6;_h zJn#AnHmZdOgFKrRk@P`Fz|u1SmYq0dkpezz9g2%idm(6#qZeOU2B`ND9}g_mTz<;- zq*wca3+S6%CyII-24nlV1i@GrWxZchabUmYDVn^}*Yp=X1C`)jokr0&i(+LgQl~jQ za$Lq}ayqTuDkSXM8Oa$z>X~-aM>$j-Y8RXs#S0Gv70#n5nq$oZJIxyh#)ydTEINHi zngDn5z9$)tsE@CF zpWH4p=!J6a>9;h^4a%u05((EP&N4*xI?k9Xf)*NChSS0%{D&ZcUZ~0BQXj#?8chNU z8-%W}UuW;4qCZAwsACcgV~_1-el*Rb9}QAO-CxRlZ4nr7r@0JCjzS{T#hl~ocq=1& zRDXX`Er-MBZ7pok;Z$u$Q9(OEz-f5 zSQo_MXllmCB8~1U#j*D@lbC_&Vag0Jkez{@I<|7ND?y@lM)Pk%g%n>Yr7RJ@6@SDG z*kC$SSFn6JrvDAEHx5j|*w(G~bUNcYH-x|%RB5z|ag9|Y zhr)53V+>(n3Yd4q?SV0@(LSI|%ADGU1fd_PP|^PA9ouzA*u#M{Yl>IGb!u7w@hASZBz_H0J>p**Jkqrz8f zjuBNU!nmj}EC&5e21JJ{mk6cnOiSUjOK=_<;On+NPrBbH!{MNij^QQBe<`~|OQ!#l z!)4KidT(y6(Q80vZ>nA8u$)K$LKa11P1hj5$cUSRmWOxIa%F`8D%oyWQv}wA;YN#v zug7xh)|1lBn`=UYFHoBWq}niscdyV zqg6Md9rvHN0O^u+vfot`N`2bW{CL8v9hhzI7FjQ`?mpR|GhqFuCbVq%G1jXZ!?&uV z+!wH;Zb{H?c4*q0=_IidqUG-XZ%c65VA&)JCp5i=5F4hI2kj5Rb4hhvILC%im9e>gP{! z#|b?#$>F={@bRL}U}P5IHe6*w^k2ip3hP9}8HSn<8=RDc0N4|unzo4(Tyjxa79+E- zClfNpGSZ|*>AK{MhMo>(nV$=MBi4BLXywt`@J`PbbDWN=vX_28)S#M?t= zOic^wrb0+U3V4}9&qqNV))=xa@?@~*4dG%eb}&Q*M9A?(DS0?8T~u2)bJUJfaN0hM z2G3;kS$tZHs^R8inU8>1QeaXwmT0CobB6qRE2oxdihhQuG;C^ycuxi&KZo4wU1KLy zJBODTrBEGIHF!%UOFfS*P3X*ws2*x29e`;rQnck1SC^O0CC))MreEl1Pk3TL@&vDQ zEu1eam+>OrDEA=QZD7z5iM}V9w&-;sW)I?UL4M_oBKzvH@QxCxBaxr_PMngrG-M^M zx{HwX&NRB&{t6N#`&nOu`-wkhmQ700)?#ecmt})q=K_tDnc<~9_F}a@qr4D3PouNr z&VHNZ8h4Y6KL74vvU(vwyMw-t&eIX->1hR227lf5nIrY(P;S4C;6pfNrX^UcP?PC0 z*?bt{g*Zj3^t(;~MothRwzrB;Rx2KNmMGtHp~+=}FcRE2exko06K+=sF5*OxHFjn9 zgm*GEo!FB-MTlGRkhwTXB(Pe|uzWOCY2Y5rfu;@~X7_}@1WE~`f7)~dfnel#x=0f# zG%pM-hcC21kMl8KYjG!_RjW?05nW3g@AWq*wW&UZpq_ZTA1z_;M7LrB;hhydFXi@1 z|JeItOcpYvT6F8U{LdJVu!7l`*0z>dGiSTYzHN}JCwWHhf&++EmSd%o8w2UFhMoPU zv`pSD(eYL+1@OJaFv+}QDL@L4ea zy)?<_uw4^Xt+wOgLN=Mld%P$c9IuSQB(Dg^9!m9=G%favR&QspEk-^B7KQ}LU4U z>99VA1z`jlVFe-XymT2Q|JZ5_Chk`jnwW;RtEC*jpsw=6A`0t14P%imb4_jCzJvo~ z_RE~shv4tREA!1YggW=2INS5*fiyo)4eCc605PkD+}JQ5DmC9-n6fWmyIfrJ(yiq< z*#C4I$bGQ8-xPfMRDDO+>nR;S#S*oAV0@ku)^M5IGv|}1pGzk5gD*Awh8J^rniUh% zD2$Es);pWS1M4elYt!vNUoh_B;4iL(yPaxOcPs^t!8F&PBxC4P$1q7+@_V5c4m)&)aL9bZc*&t)W8&S^hw zB{E^yHPqXv>mcmrLp=Q!a+fkTDGWY&22c>1g^`CvR07DBIHe)ZAqUwfJVEBtbWY zLyUIgd8viMDg{;S=7zqFWZ~VR{P(QW4JD~Poi0IGs_H@B`f4^N9aA_XI8?>O-62{c zvu{y9=HGQ@!$M}O@8lp!NFE7TMXY7P2MJBLFrkulRE1&^a`ixD*&#i!MF`rNEosLz z>DnwjC!6KfcJeH4XdfVE>d3MVN(9)=9qTNjAJN-;Cs0P|+jp~(+efl^oau+k`awy}l z$E_uYGF0+>7!3-l+&!(wM$nMX`o-FsY~GUqO4ss31J>AWK|!&dV7qArIGxE@zw z^;`oC#w%lEp}snqB+a#ln+^)y0rnWP=`(DQx!Slm7Rd&mqd5d&AV~vKuJKoDG$~N$ z25Pj2-zaxU{W0H|mk-`znFY39SJUVus(>qe;+o+wLbUJDgIBKX!M{h zIGWKR=XcO&?cTZL`*>oL09po;{TG7{K(5&FE!^dHYk8JXVeN3d!`iS2^*7NEbQC-% zC6B-Ek>gHoQ$Bj9&weM0JEe{5g?r`jlPdUrtW}f69;AaP6Lsa|iYR??%S@KE@$&FD z;1I)7Sqf?v+cHMPG(Q120dXLy1Z!_Ko|#-w(VP5}z!98pW=)%xHjnuQ!n}obwh2O5 zHH>)FxFM?>vkHh!QG{olIozr+0(VtSy{z~2QODwp8p9h8M!WTH3eGsvOhY&Ac_K=Ivw7g|8p9#9HQ`_w`iOEB5?`9q#}oLcn$*aR^t9k_+mNEv=CO77`Q zKP|t1PTsQNgCPg+xGksq^rqtcZmX{CYcetJj6;vZV%9>2P@836Wf^IFVPNV9L#5C8 z_34$+#N@0hX-Bt);S@4!*?b+aEcnbB-=ZW&1-rLR$&%)im!GF{ZX?@43iWjPRlDl* zRLoQ@mo@~}No12sW|Mcr`q+t-JgxTE=HO7BfrH!4+=zFJ6r7=#m7VPS<=YY^$S(#I zjftIDngr_gW9VROo`SrqM{~aUeSMU=RuvnD+VHZ1ysbo6eKKd8w%$|H6MptjiL0B6 zm5uq9-q7_8#=O4SnAe{Mf4XsQ)>fRMBJ%L80GJ&&f10YSd}U!(dC8;~IVuC5bb2G%$>F@{$CT8#+qD?Gd6Y*> z)6PMbTUj5}vU<^y>o9+QY2jAM*HBf!10ay%##5M^qHgT#NU5h)APGmO_Q*F0dWBtH z`GDZwNXb_!i8z1y_VnpY*YN(U&Id#X=s)cI=c?4r^8cvoSsOT;+!kJbCMNrt*yuU) z?-ecPn@8XmWuKd*_+OCz%KTfYi|Kpqis`xv#bkEV+SQ&C<%95s(DFmh37U(WL*k zNDZJ<5NkVKqy&F$9v{SCh+3v*&Zx@Dz2h8|obM<#zFaLCSQHwog}+Kr+zGK4MT47? z>_Du)_<|_(1cw8a0fRH63WS5ijs~~*k=+^g|ukBk9r~{=r za2~f;&9GRAT5#RZMQW6TVqtlYvt?u9@GNGW7cm%o(EY06 z>g=?A=j!6v5;z)TW6bKzv@tEMq_``m8U+teSo&a3UcWU(OB}t6UEgx$&G3GPpa=2n z9+_%OBHuBoq-DxyQTq3XPLq*R{3zFH(+1c%VT!ui!#!f;lzy&tA%tvPHN4jq20$)~ zZj_|$P_>H5l6S`n6mOLkF zZE+9EHwUX?9vl1Yw8N{$Jf?k3%dZ*Idq!&3W^+a|9)W8G)Ok85QA|BkvT-t2>vbXx zt!P;@VfXK|*sfG*-hTa@~1Lbc~LzMYziYC^DBgj6Rl>zP#P$ zA(~^u^s%BM9+EYb=o8#BdL|T-MPN-Txp`s5@Qr@%MtCkehSMY_X{qD1CT2%}#8D4c zt9U9psIH$lGG;wbWK5-%sG9K|6zh2|z#E6nKK0?L%@i3`f_XuGR}{?<%oN%-_#<1t zSoVqgy{z}(A~rQW9qt9o4=%kj7)&TI!#{775`9+$soavJB}txR?Q#MIMtCGlCL>59 zJJ2ju3A&&7>LkG>`N|5%CTH= zjZ1gxn}V;ZSJU;r-Ogbf0`H%TE~gZk_cl+ut{Q+z{W44Db8b*FSvxpV~ieCH%ap+%!&nA2+}h z*IV*$Z501J)0;+$TZYHq8E)Gu{+aQnvEr7|@;@1Wv|0Q!`%R<8EqlV>vH#I_@y}B3 z{Sfk-o(Fy*<$D{(KTEo4#P~jL6o+;lv|cOjhaSE!=lA*CNcy8Kzt8X=+BR-Y=V7K75M)`6F=ensJ{Od>91wZTO{)9B;>D< zepk`o7d`(9^Vh8AElm7%p7VbL^Zi`%J;(W1l)s*FZc%ox?fX|K|J8}-&v1ViY2U(q zBKj%rzGeQ|OWee%-vS}`cPk!b{)cV5?e`dakTW^^WuOGoboYZ&bzXqben#oNZ zdn@emzYF`9sP@OSzx&p|#_rP5zhAu#7GzLn?Dg5lRtLrkGR3T9y$&OJs!=@Y$;>3A-qB(P%e-k5-qD~7`F(zE z4aL_W06455XChFe@T`CO!DN3J?t8XfUFzQK=*n7)E?u%rF^9`;PnLBU&MMECoG*LA zLL}|9`9MwxF#;mvCJqxa4~Z$h8a2{kDO__|U4thRFbn7J$Uj(o&R2+S$L`SYT4Gic z-uH|O9gf?+D#pvk2`~=OMspK3)$XYa`P%CI#oOcI8Fxg_@#1RfP191bY6!`9kNnYb zPQ?uf9!ztt%I43fsLV&{a0bUs##h zIR1qt`TwxAwRAEu`zuG#{5=3uM@QSg7zWcnKryhfHa0W)3ozz?0Onw1|I*Chhi~D3 zd58SE2XPPY)_~RB3#9lD(0(17Lt1rcGbF_%2EQUVjqc)} z%-K7Nd5*P@BoAECI6(*0H8(zqNt%3^tgrUWkjbCzF{h1Xm<_akx6-h(*z0 z;u^cW!|;V0vTkv*o=1+@JQ2dIIAGQy_Q$Xf`GyaRPD19KQE(z$RIm|jC+gx(wvnrI z6v8P%#UI}8L~MOkI(s=1_HK+Es#GoaxHDP|lpQLL-1w!mqGnKkw)|s9x^qv-&NHmM zt|`U{`i)Q0H)>6O7!-(W_N7}fNOo$bJw=%zU5(c|>+#+0W z_~zTQOk_q-aX)O8Ca#HBJqtwH5{z1qw~x&L3p7CbOCBr~=r~KU#zb!!R0&GzomU4# zB9En3n01X8IHwfwQwQBF7;_W%j9tndn4rCIgwvLP+Zwp`eh8sruRxAv$kuNRIJehz z{C>0@DC4BpaB)HWGT@2del&c69VYEcav%Q?Iw9H)naUeR{*B!I6*IPNXsPtnX#xtJ zAwq+K^aFh#fZlYg&k^QXD$N&K53c?ln|GE)dN<-XbL{~e19b!SeXIEvU#ibtK6yeyKsAjA>TyOUa#Rzows={%Xx9LI;aXEUp*d4OhHJYb&?agoQz|y<61(>A-KgJuo74@ zhCqS$Fw#$M5Y=@yDaf79@{*xL?6Twix=Up%XY0_Y$&43YtEk%Kj&J<9WcH%aOfQ5c z$SPlhFQSg5Aw`{Vfa}@ohHP&-{JUtJrqa&vJ@m>ZA#U=L**d1Al%=2s;6+DdQ zE3cHZN2~hqFF-QVDIBz2vdeh+^0+0<9;YQePWBF`S9!9PCJd$Qrj65Sct9iaHO{RP{b9(6jv(tHebUNfnwj zy`t?v`$h+~#LIjJU(!}`Sq+Y}fbz^uF!EN)wyC`J%|h~$;qNAa&u_Am0A34!{Odjr#!#Yrpkd(3eyv&^i00IgU+J3f7C zeI$$-{|TyY!Wy9&8$~EK4-V~>F2cW$es!=4m-?ric7Od_9W>0{0y`YlDKqO%^z zU<>G0@vvSYaCPXp6h5(cUuL7icvQ8usA~{MOf%62LZ)*h=VbPk6&`Yu`lR?MSrk38 z>U}+++A>(NjZ$(^{`U*qz%$AcEY^N7f{3Pz_tt>50BS4o_Fl3%f2xJF6%qT7Lv35 z1^x|z4cB*rH>V>buOBpp>qA$>6Ke;SWKjuGm>@mJ zRY*p2$?Z)rME9$8OkDj4)gwH{eEY8-qK#S-a_F&)$YLIm`SUOu1kn#@Rw&U`7-)MQ=PDi?v>7VPNB08AMd<*D@0={S1u zr{1WsqzGp~ItpU|6T7CKnwvyTvErY9^3)2Ct0;i)$wiq~* z%^BlbTJ;bEo%HK(%%A!^ZygqlYD1=;%XAwM!SLxd&G8YaFlbz^P>SFnc(O98 ztDHACi;8U7O~$?>)j5txd-KuhqBz7C->Aa7X@?{UwF&%+(luIB|HaDiXrcpOhc^G* zr5FtGheosE zAlIBF)mOu+M4z}vmHI$rGU+YvpprM}7!jZ99Mc>rKoE~!1x@HcXSJ0^%kONQe306~ zE+?uRfBlL+V|qLtVTv(!C0nkTaIJMi7gX9i)E%N0>lJJxMOR z6xcM!kU5kapKj_9>qSrJO<$9E8*T>2((8z&LaYzFc;|wniviruA>6`4zOG$uQb|Yw z%|VZwUeTH#!+wbC3PJBu2&fn0q2aH%hIDX0hU1v)@A2vd&+he43O__; z<5*)|jXU~qDxTou$?l`t)Qv572riZ)^+0*n39 zEPSj2fp;jz4YAVu!S4go01bV)?A>lVf0rl={qunI%V{3?Em!z88mU;>D2V~Qj2ri? z8XNase)R+RVk25MzCwaTw0w{a&%nskkPjc^=I-3mzBkW1=t)~1^qB(G^Oj3QUq1|A zDvT7q=#xLmweA%`=p}WS$-Z^#U<1HU=jHxT+A*I=hQs>M&EaSNMTlK+J-jgd5?IbfCFz^O2dM$7YbI>D%^6PVX{%+W7*@a$gV8=mlu+c3J=Q?-MDGqVmx z7NMt13tLymY%QpZd;8YBqL&o(5NF`DWt!Gx)|mHrYX9cAHxgB_J^J;HGC!=XXy;?P zh!xy;JxVk!yon4nN30biXX73R8D0@^QST_G>CxiC#n%Prqo&Fd$>jhgi7)v)rILdf zYnyrGj618?@&i$F#ZSVg-X`!yWIe(dtYX@s7s1z?) zeD-3e5fSpl>E^V1?`mUlcc;x>nKd)|Ss07ui{$Fj63CV*Jhu$LibtZ*8+JmS1ayom zvg29LKj*eABbY?gWGpWTBXY)rS#`H6q{Uh(J|SCxJZITzJ>F)pXvMBQF`Vt1;0I1u zlwn94f_v*;hRx1p8^=;5k{=qWFV|>&uD&i0d|!f}^>}DBj@8O*d?dobM5(|ZaU1#z zmDpw7{^kq04*-ewovnz*(KxaSYHVJm?w~?~3F;HgvDV)4+EugmR>KL|L|d&-^>nR_ zLhR+C)}f;Fv&EFB1S*Gm!C~-=Ea!^A8umnLo76b}6#@Ey4Y!Dl$AoXJN`x5wq-_CB zbbRMZUnoDxxQoj;Fkl_T1PW9~fiEpDc1P@+L*-!nge`1afx-+Y0qDsQh^hf#|UH zLs~E-&!Yw7nGppFAk{v`wRm;nYW3jeBo-nP)#yAY_YO7YVDFGMkh#f)7k4}HkIpz* z@#1hiA}o9%7_Q9TK;`v7`eY$6X0tUC)bru1X@|%TGVFCjEZnF}0?T`JIdanatcPam zR`8hULC|#+L@rNBJ0rm3Bi+DJ9XOekkEnAu*5Q7Mu*!7sT8c8uw6I zo$9)~X$W^4w!ye(pH%4hJDy#r<5xb~(Txmkp9V8uYo2C?UZSj&rZRL!skhWP`sx)N zVKhEdnef7?)Q@5B?K&YBNOq?k@EDFEc09yKQKWSw!xQkNn=7f7$@kDv*O4N(#;q({ zGsmS!nIf<57Hd9kUR!bkjeD1eEm9qu3#Sq&XLAYb7}`Qh5Vb9@;6|{eUEiwXraet^ z?W7%DZ8jNH-`Z0exCAWNN7s6$1wWkX3&G$CM@D2Uu=B&fDfS_q?N_XGGaoK3dW6=( z?nlA;z3W{RTSA{Y)uuJwt3E%I0QN+#Pyn)d#vg1oElX)cBl(LURQTG5m$TE_lx zW)!Q2e5C>+1jx_fTQP;c(N@c%|e4`B)8ve6?pOPT7?+tYd*xsKsQMo*I?n zzB<_JE#~wN8rJ0O+>&-gXkkN_iq5fND#|&Y)oAK{225{V$1e4fc3~BFFuUfCC4#BN zFXqKD=dams>!1*w`OcctHmcRuZ+K9l?TAl}s(E30&j0{k;M2f@>14?5Q{-}apJg8_ zrY?*Z-2t@${sAIZJA^L+;qjIgmWiiF_M{!=Gksa|4oL;bSif3G7SeXHz3yyIa0@!A z@3bs%Lv5v-aAxj!6};7jjiM{fkKIf@|`kI#nzdvP-z(W?s-lcqunE$M<@x2QBTj5kv&)U$^$o|_=t5;RSQAri==4{QL zs{27#ohB@ejCxjbz#1T54a1ZGlGGRB5kfGQg*$64o5S0okKNqv!lUL}vgp#G>U3hg zGuW&3?5|J|dezH6Y)ensU#y3sQm&Mi+O+g|XX3rJk~C><*&Z-F%V@uCzn%S}bC!AI zu*Cq8dKd`dK{KIHkqa4*JP9`>G$EP%vTJ(Y*#}G^@`-A&VXYn6s6IM_?p!gSG|K?R z5%krdK`%Hd$N~H$Ej+bLGSr2$*Gv&VS&38cqxkcIuw{Fb(Ga`bbgvUz36%QOmwdfM zpk}*@mklZ7mi=nT1Ua?yX2$g7-fyOPE;MUNj&ULJ0woRXsRjAqCe^Y?i&nAc2CBv} z`m$Cm4oJ-iS3LW)qvI3OO|csCC_yD*w6X3oU>UZu;&8d?Y-t|RDZ=FDH89yqGLA`N z@_NVy1`#Q}5zS}J!*1l|8A(Sf3oqtDt>#xWDI2=n))Q62;Aa7N2_xb|S*iOds?$?i zK(>psB-89+yhN(sUtr1i&G=VTrTu{i2=b3V7;~`J=M;r?%l_5CvwDRn2bKWV->kjyfnfX znlJ6AI56{;%In1-X(gL!N^*f>+beb4Z=@cNXHCUOr8JM%^hulOxj&qTa+)WoF zVbYQ0gk9@^uVJN7n-anz&jVqeVeC;FZ#4nL1EVes+Y6Vf+xf@|rIM{IxVV*f2Gwa% z{oyRg^NnvK+nguMS~ZU7rAh(g_?AS+k8sB`X`DgSA(scST%AHhp^x4VO_D}ax)>_a zI^snDMDxs(S$T$sZpAu8ctB52E4%y=MNSN$5%c$%R?#2oj2$ZT4OHEDZwcZiJXuHw zUKDA?+X)Ehg>KHvN2~+}usvnTlmkNc2SIh2p03AT))ag6(H^hbA#!pNgetP0t@f`N zeeoYNSOve+#^Yx5GJK-racnddS;^vDe}up(l>O z8L4d=NEdX$@q?I%#6!gR`Yo$xsd%wnq%x|CWE~65Wf^6<76Xo2J?)1vY}Q;TlG*C=5L;p%~QjM?ai&DO!m33b@#;_a@TJ}oJ27k zdk$U|869hVbR=1(^V1Sf37~}w4AaM1LDK)SUdjD7@ zJ}A>0NU!V?spRwmVO9wy0;5Z2+f)(C>QZuQUK$(0F}MtK)hc1!aQWnsnNpkN8H2E- zDvvQ$WeM+V41))nU8(qtrPk}J(D4Y>^zI7C2Yx9Rup6+jaXM(hCXZgOB~3UI$vQJGZ)k~1qZ4NS>PYoG0nI>=fuRER9Z|Oj3D1r{QhR^JB@4Z=DIIEjq#j;3jd=wt8M+lr+O!n5^J zHqf=eNkjmhAL=JvPUQ%{%3-}M(mK$hs&_5EHtYFVsTny9b}!gBRc! zS0syA&!-(>yQdfOXoWHrzQ|ylbmRGXJ+T`GvaOw5Rl}mYQ6VpTUL}iXnk;T?Wh2s4 z%`%cAG3CFW4U$u=cywEyhohdPjm5FqNwk>@W&qPsnAL5iJ!P0ziIjLdA~EVyI2x48 zTm)U-jdY^!fv^({o_B#GIAEMVk-%S+K(bp5dadAn&BeY-G9BQp&xSPm*qX7us>Dn) zfZ?1{YBJ==f}!zu!%DZzPrCT~S6mHdo9*JPW)lr&$yCH+uQx*=b+vOl3$LXJ$blu0hdgM(yfuNOidEctQ@t`yQZQSyFLhrL=L-9y|&ZLPDI{ z!7hW{I%;W56D)4nG8`2QA<2+1T<^C}`+{uuz{bS@1t*(PQSt2o_QKh7zexOdURNNQ z6OF3~AB@Z2E}y?$=ae~VQR?0$Dh_ua)Vq(~e8iSK_K{~~>0_@-rGxKkxCeA5;%{7xG1&7s&neA4&#@91|E5c!wL zwl-FbE>@Pqs>9ZEoM;_iX`wq+qb;au5JglJC>Zb`2|cXiaLcFMXEX=~NbW~koR1pF zi-kgPpN?vLg=`0Sre5)ji|0|qsPC!BdTwU)EMJXqrF}dZYoN>Jhz~*VBF@ZuL8zD! z>UY@ddbP);Ly_4RS(96rumUseRHwWv^GRAg+JuaH2A-k5VuZQkZHm39Ipmb&TbPdX zZEmk1V^eGnLh~@AQbcJPWO6?TLSG3@Sp@-a_lOW`MA>%PnU>BDjd&Lf$g zR+@6SswoF)eRx3y@ieBcW+EeDeE_&RP%%}EeL5a+OE^UNy6&xgM3N7MVsJ&kDD6HY zJwbHJuvCSwZ7p4p~wA2S$Sj)D^Trv~iZWRrv5MIY)%4 zKO?Lk9!xLf4C*o)md=TbL;#`~4n7bKSMQ^urNQxdhrKC%4x6^M_o{iPT+PV$ra~Cb z<2Yn<&BuNC4GB_YMkBSxQ53Hzy7YkEC<5}9sO#*$|T^Iiv0ZXS=fQtHtIvsbd6 z1Lur#q~aEcPbO?B2;4ZvbD%61ng4dsdIoR4nk`4+-J%3e~ zkRtRn>htm~98ahp#Rua3LL||~{UG_K}p{9zP4#W?VBB+-$YHGco z$jXDH`;%C0#9e0yCsnx!Z&8fkN+#bJDJ(^b8*!!Rc}kQd91xFCmSqr-R)Q15(E3#< z%${I|Zc7CTbkzIx1*jh1Ua=FWgw=VYd^QolPpjpI(xn_GN%xEM^M4t6GwkGaAGwzmDA~Hz|WLt)o2}lH4g=MgI$^Q^p?YZ0|}N&-w5q zIyy=7r{$rZMP;ydE6_sA(i}i_Y|^LdPNN7#*m`Ul8aZ0w@wWK z`hqbta-5+vHH{3lo~76h3fIQV#m)<^$9E;O2ao`$KbQU8&GD|GLG0b%cKp}`ewh7t z8Q^{A`^p zX~>=9zWd?ZbbcMrJ<@NYygvuLm*stH_l`CAdw{?0#D9*;^d0n29i7l-_9QQyz>KdXFx(C5MZTl(*s zpPxB@7GC_|e03Kq{@s+nRpWkU{P||}2P5{~>Fpmf{_&pmXS$y+2Y%3X-N~5$F5P{h z@qb-`XZneOjuoj-H_oLcYQyZE)C zLEPR#ko`w+|DG89`Kx)K8hmT_#teTn{$rx>=V14#!VfU>{|)v(5{K_h|2=j1&Xwoe z^DmixO(cFe`M;kmeh^~cZK1#Ipx>PQv!DKQYWIXc&KU~QFn9N15D++bKZkem;BL8eUCG74maMrbLY-K(6qstBvJyac=A?_x+$ zz&o*YF_-1ZyMJ3lLqXyFSxinuURpw2MU_oX!YfM728I(Y@GRQ?xh@5MWoXDWv>qN! zu9g!yZBTg%oszc%ysGgDIboK)&qmpNxmh%Si+XRg63v76w z=TnvW!LW*z!=NA?2f8*F#{ue4fEAi)eXC^2i=m=PH+#xPqqap3&Bq8rJ)I^pPBNUF zC;emnW9IkK`^VD0WL$H)KyGIUj51fGJP+ENKMj#LIpm!~e-8u{6v|KWg1rlbk^*UTIRNnztE)q4^1Om z8xwQWUl^eI4+9QhduMZ_ADc(|E!L6VRQAtcprB;op`iHx!@}=dPz5_UivG46Cwq{i zxvdSGkrl|nAzjs40apae8y}?#5lOwotR&MTD-O`zgsXe{Z zQ>@!~Zwo_QpJ&3o4;q?Om6u6UX9xFo`hmy&d$VWcPg|f}F@!_0gQ^}~aG|vYeYkm* z`%bh4_kK(@Mc$#mA`iH40k?eGu}{o_S~Olf2(%tWZr3uP*5}jU!vNFHar1=9T%RK> zfxr?iSS?%H}|SHj4z6_ePv6_UdJ@a zBAA*e7=_o9ItERlH`FI!Ir{SzoA+8Sy@;MyA_KKRHl2}loizi1m>}p#r!c5~tvfoQ zXnd@Z`eD$e|3F``5e#Y4B|E&vww5l9j47z{pjDJC(Hb2UO`*?}IkYKibFxc}Cu`tP zUcg*h9Qitrn{hUZ9MJWaw~4l2WXgar6n&B|bQ=v`C$^x@`O}%)f+d;wV^cf-Eba%z z!E_2A^KC0S0k+7ySpjL!sn%IWXV4mTNnvDJC!e1Huo1N-=yIvgnBvi{^Jy>yX7A4D} z@Tm}ku}IERz79S6dz4x`S(^Jv*V`}Afn0PPO>v|HIEZ1P$ADP27( z9bEXxLjJTHZv`nJnX4h9FMR-)M)A#IbGLBcYsj~}t}iFVV7|-iayTd`!T-y=rs4dS z*(EC0mR~cwTF#-zt=jZs$Jv=`tf~hqUZHAWj3!e@b<&6Z)CQh8`?_$K)JH8BiFm39 z{=%)~w1d{La*D-pn5QPr&g;{r`lnZsZx)~gyXymqg6O?hrPqodbr9_~q#Ab0!7wb%3+cs61wkS&qC6-g>*u{UG|xXiP5`Y4ip?kLQv{6==(h(W zOnNr36IEPF(XH_qj->^S;8P05Mvt)*W~k@;7m#roZ{fuuwu>X;+ut`SU!=fH1XaiI zvv7lHP7#_Sf@d0WQGy<;TnGxTmOnY8HlmYz4su|kTXT}>_G0}Uje_CY@9{V^>BBni zLp)O_qbWY&(Q*q!?Qpe5GSt#elEc#B`B#<4wISR1rE-;(PBCV~4iH#gMi-tBXr1|d z3B3Zr;9Q*)19u(1IIG!rLZ~i8_&zI3iw}Fz)P;Ehv6oa+jLyusT;vXqo0r6M3Ab)3 zfd~zG2<7a~#vfxx*aP+D%oP=$N_ZFGWZP*wpfdX;uLwI0zB76~asU_G-lSD{W66&@ zkY{TPp}NL*~0CyezXcVLJP;y<*@U4krU~ z<4ABfqka+V3bb!{RHC%;!G{11MVGg&^ge0k+_ zx;^P&N;hr%cADv;d37+&V^FB&xY6`z-bb<&rWWxwE~>rkz9B;j5ogY<^5u%sxN7}? zneK*|V_dL#r6s9M(@KYS-P-5f;T6&pO3Fx3mbnu{`Kc2kK)}RY;`zuj8yTW#sf{y7 zTmXDx32JrO^zge9;vo0|yY}IFH~-j3a=xOa$|Co)4VX25vyHJ?Gw z8quwz5P5M04O5@o^JKj>by6Zytr8*&WwuV5va5Lw;EhD5jTF}7L{=9++CiNxCA(Pc z9ZuZ{vPl#4*e%(3gC05mz>9{@UXagm=`vYGtkL_>@#sYkxvtw2SKFL0xi*E1*@`E{ zSgGaWZ9-^ofw?tdGZ1!oYSm=U3vs#$l#JxSf_5*QYTW$?)O?bgYt}MviCn}Soek*0 z*=x<5uQ9-a_I}wtM?8c3*xea}yda?efT&cLXMyu{IY|N~0ffTD^l#Lgs9l zQw{OgEIOt;uj1wOGxqW?l?wD3qg^q1?*(cWbfkIHntY6a%)9~%1`jEkBf+$XJjvrs zw?Rg{QRtk~PszW0W~+dODFV384F?%9Skfn#ekw2&_mcoaDph(shOtA$tdUIFGGbEF zD~oeA86KrSU=T5?rDo0vWBY^#WW9l;&B$MC*53CFhJaOdAM<8Wwu^-w^@cv=*<*B7 zc`=3z1M;U*eW}vvAbMW1gkLpkji3HWM&_jsDl{mgnoe3eG)JPIcs$8xbags{2z3#g z>3JdPY*-+ZY=J2uRl(D!LxyIls(Zt7GbL-AEO`P>83Y#}HJ?mU?K#P7REe6Iy+^um z$(`|@>9iiP)Ye;e#zE^O63U7c|f~t_XC%=kHr-C$)+j?O;>he#7o!zD=WOyLp5Sh3?7vI7moVk@x<* z5MUB9Q-G2jom^rH{Fg0vW) z^I#dfEI$Y*kBW8gsGSl+FXA5K;3R&i6JG256nCWulPJN|tXW0Uw|4?+P&tlk=}EKW z&3ay9AgX?%9T|Zba-p5lV+Z=Rwt4x!9e~>ARtrt(HShb+JC`bt_ZXP#QRKq4{6r)a zG9FwR8L4cnZ+4EFt?Ob5GJ6!+6c?ioAfBbN{NM;*=XsTj?Fu|PZoHZm`f2GJH$^W=2z zEXzz)JtG`HEzi2$IENPnxrB5a+;l{p$ILJ3qgEyc$-QMJEAAn#llG%Rsj1#9>}S*A zbE=UaKfw=Q56p)7!fky?HneH@McMKF)4p?z4C=0@fEB*XQ$!+aw%s!^qbL%z%f}8^ zI5o6i;w3&|u2CWTyjqV=k1y4TBnp-0^jaIXO+HV{=6x~WLHx1`4M_14Fyeq=e3>Vb zm_hrI^)csee|AlLWk@Cwtra0H0q1^WpT2~Tf2E%$EW>a<4=7^fu+7pgFrs|I+OyYvB> zCk1|dzDVKG$c|BzYyQ-q5O7={5L^vj&BO7KEEU5W_fuWsvC*r*ed!EvCUVLV*t9Id z(J7>zh(**XCq@izD^FO@3@;r9WS}<>zs;hGAgh3&54;ulAj`H%?GCjgtVsm|?0$~) zScKXQDNsdH5#Dfr^wJygZ3ma%5Nhr7_cwNxw5z~FpHK>TF#aBGqktY>g-b+a_RyN? zTE`c{=2hmIeM!3;282`0r9+6*IM{QID?+zxvWR^}XZ%eh;>2i0sN(aUY>6Z3(EzBS zvnsexQ?@Hw9K`em@}4}fkKewpDS|^FvQ9)Fb z?{`oOwSw8pj?wj~`EJ_- zowH4sbLyJ_;fA%21A;H;x2<1p|G3kC!{hzs+Q-#*jScF%3%$sHK%uV~=o|b|f!Led zm>SyJI*LFbR^~>3x^Cvh4A|guVs+ozj9S&hX)AwJeuyD;Z{*%Vxa>z6ZsqZId?vp( z-&mIw8$IXU_m;3;Eb^*C2T+2lF4Cej8oqW230i(8=9d7lNkZFtzT#LltnYJE?jZNpT# zXa^mU)1D%$pyUxb*FTMMD-xj|c zwY&bS`S87c@drSb0@)Z_f$hIt(V8@@A*vcg-h=Ba^DK#P){0RB5#Z{jrK<5{D1GxO zv5>5g=qNRdt9cuEQ)Qjc*v{tBb0?TItJE2TvxBuQs|?3s7_BMrn7!3r-`Ml7d!BpHqe+?&?L*pBRebzZCrZ}UNvtBy}8}!ErzOIbU}fE*eM|^fmFik?$j|5y-WZuUhmJ z164TVoZS`^U62j})A-9rfFx2Nuq#8izOPKcv1@k;cTy$2-nw_;qH|=x4U<=VUMC5V zE`kRt4C+jx-Cf86A#itXohA*cF3vF_BF(4ax9^tYcsS`Okd%T{G|VGwn9I0uNP6H_ z%1DHa9mQu}r&*fBgsXS0;mj$QYf~gunX~Tg-M=)Y@RNZDING6r(A6|Wzr3xVS(zr# z6vDrCo}>d}8nnfP5P$q^_ffPZZ=iwub>|#hZlBC&)Hq2dln1u=`iUYM;_o>D%g9LZ zW~m`p#-7A`of6P;F3x=FUFd+=!xX->!Xv4k%ZFPknA8@2gT+Qi^4EKXhsC3 z$8ggtWGZ7WnlV6{}&MKEmjPWwj4P=bN zHCrghy*8W1+750&N23DEg`;yNIlx@O=iR#am_WXZ@Qh(*1*@F-y#7)U7y$bNy3p`lBbT85l5n|qL5AB zQulXrk1Z-md&#t8Z-&O4dL-#yRR(n*68Yj_di(C~Bc8Kt4=o*|WF#4`*N?N7E=hZe z7$oGJ5#^A;$c>Vr&>hO@cXlKB#fEmj@DEvm>Em|~JF@AM-?ph6*Bg{ikgZ$GSFxF@ z2D6*abUvx^Oz2Zog|Z380#m^Bg&- zWH~ql+PSZi_oA?tL2r50w6{Tn8~5U|gVd|WYIgH;D0Q4-XJ*sxa5|NU7pPs4@jS{Y zl4CY>!1|pDm~t5Oxx>Wq_a4fvdj%&AfxXN#K+9ir69CeVjM~Tj*0n)bt5BK)5^8xJ|vp+>Y`W zu}*e3>SnK-k%QLZB^838$aIh6qw=NEjRpS0j)P7WAE9H{I>Gs)CDYPorxRD}y2agv zw58)-kLvdwdi>^?YLN8yp2{|j1O8ACd-e6$p|G|7SgIR#k!O*BhcQx#cAhM2yzgzL z9_pU6E)72EU*591DO%LHVMcw?m*jwrig-@_Z05-CrPP!Tv=3_+jt-BqedfCK{%DKilN*Dw>24DB94B?%PBi=l|-E2sD3ee^W z5P&r+L{anT$S9%|gSQB6?-bRfhY+P&$POAxTAQ!w+ARadgdxc2RJ#1ZB^qV1O8Xd9 zXxUZjS-JwL{tq|Y(Y8#FCW&ffQ1|Pd_2FWW)SGK1nY^X_~Ea-zI@(sdcZ}w;# ziivQ|z}?vy@zSQ+SR)V||4F{$3+|#qFIKX5bFOIHkhuEH4xtBKRV!om2&o6?%~cr^ zq#5ld&Qq+eWM}1W6D#n0O~F@g_t9&EO3u+)n|!U$sY|Y36ds%Iw5AHCfw)(!wQotB zSN3PG5Dm}iwITlO_<#~avIQnCw+urWP68V`%tGArn0^~h|BOr;GD_@4Mf;csEL|-J zV9&swnv@p#rQ-fG?xy2HCii2WG!u(`DukySDQyfb;t{dB0`la8987`pZ(4clibpoI z6&`1~Fu!M<%*e+@XJ{5FkikQO$A(`xy_x8H8h$I0<9A8Ikrg(x&V?LVxM#ALd4Tf# z4VUm)C;w%seF-p=tV%``*~_#C?CF9vv`>HCmNNPBHD9Pf24zcH(IDme(K;` z#y%*heBPWJ5yf;`0If_*<}}=16K1+?#D+Z^-iltNiX44lM|7+a`K-m+-@e9>vA#}y zA4J5KXZlj%CGSh}XI3%q2)p{NddL^X>uq6TWt{wqj;u z=;ycPbwst783i6Y z0%c@SYN5V^yuVLBzk2#(`e_Yv2LE}o_w%Tf{O`g>Hf+BS`q;i+3jQ<=`&s#G&;KV+ zKP&$>0c8C)(qp|F&apy%Yq_$T-CaNau#EKE1Q)r@VCw4b=5p`u0HXhomLay*Y_8T; zCF%natK3-4Ln>m}lT&kVVISu_Q8y##kZCZaG3XdiuWb-YpNigfJbSiYCMk~;(D4G6 z*A<#AxW-qH%wHz0!+3Xv?8)`PCH_X0<94-MQKW$+sLY1p!1W#l;8P zZyts|#K@#GwPWmLm2)c7*ip{2)Q(D|qOIrDw$#%%)Qw_Y3yy<}h>l|RyzXT7^ffWV zA0xJS0)E3q9Y!n;w*Z0)uH}Dc?TX*}X1Eznx2e;nMzn!GeDA{Qe)mG7`vn-5&rsLA zO@)}wfS7D zyvPlEe2ivC?_8|kMDsL8+Bv8*gH`il;+?i*YZh(~7q&AOZmx|E)}LqITx<{Vw%nfX zziEL}8a+_QH=4|5EX1RQUr?Vydd4#7lkLGUmL$uW=n7rab?q}dz{k$k-5|~_&^XZyqU4r`Ka3{?U>SxN7A##Si<2k)J@lJamn8Nv* zi@k?ls_VYgx_u$!>9=HUe3zeI#zCH(ahGgC=f3^`Xi$!7uYG-9^BT?O1zG~jD^8Q? zN3V2o;jbw-gI+JrdR{Uyi`cLAX`90!iwJM|G$WIhzZk%KO~V&}@`?kXu8P?SF;G_I zYC;LecW*HMCP{2bAYf z#^vw#<&B2<+>aixFue~tEhkSG6WeyL>614e={ZTy)@|uT;>#@*l78k`=FJt+FncA8 zR4v~yg|rDPxGYEq7E*d>?)7LWA&LZV=h5COPfDAIBBDua;p;j=qk%(ZoaEAJ=cxlf zNOeH!DPvfZcR6Hm00Xbd%(>a7$se(!H&Rp3vN~_RpssFWFL^ExL(X&qfNpRGCUco>-Wzb&Z6WHJzWrVwztxu8#=u0kyPERs z?jiI4p|(KmZ6S99By+F>dXFqh8wVED2QPWf4^EG9gw3*;39=V^^(o}Khzo#}@+eJB z&AZ#BQkwn-e&+s?n$fDf_X9jA4lriR7c#HrklBW?8&42GPlp-pOPbZ0dXG@?&lug4|hbkzjpWiga6}Hf9d%B?B{1d`@>J%-B;l!c>6>7 zpE2q;Wh|)M+nYP(KPt_4#QGz(e}dx3^~hZR|e~ z?e}f}Gp7CSEZ4W~|IyR$2=~X){`rUQheI-||BTZwkM`B!kDon7S$Kr6w(;)%yzk!K J-dTr&`afenk2e4S diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java index 74c565101..648b7dda6 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java @@ -1,16 +1,30 @@ package cn.iocoder.yudao.module.iot.plugin.http; +import cn.iocoder.yudao.module.iot.plugin.http.config.VertxService; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +/** + * 独立运行入口 + */ +@Slf4j @SpringBootApplication(scanBasePackages = "cn.iocoder.yudao.module.iot.plugin") public class HttpPluginSpringbootApplication { public static void main(String[] args) { + // 这里可选择 NONE / SERVLET / REACTIVE,看你需求 SpringApplication application = new SpringApplication(HttpPluginSpringbootApplication.class); application.setWebApplicationType(WebApplicationType.NONE); - application.run(args); - } + ConfigurableApplicationContext context = application.run(args); + + // 手动获取 VertxService 并启动 + VertxService vertxService = context.getBean(VertxService.class); + vertxService.startServer(); + + log.info("[HttpPluginSpringbootApplication] 独立模式启动完成"); + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java index e6145b93d..85249cdb8 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java @@ -2,80 +2,70 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler; -import io.vertx.core.Vertx; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.handler.BodyHandler; import lombok.extern.slf4j.Slf4j; import org.pf4j.PluginWrapper; import org.pf4j.spring.SpringPlugin; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +/** + * 负责插件的启动和停止,与 Vert.x 的生命周期管理 + */ @Slf4j public class HttpVertxPlugin extends SpringPlugin { - private static final int PORT = 8092; - private Vertx vertx; - public HttpVertxPlugin(PluginWrapper wrapper) { super(wrapper); } @Override public void start() { - log.info("HttpVertxPlugin.start()"); + log.info("[HttpVertxPlugin] start ..."); - // 获取 DeviceDataApi 实例 - DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); - if (deviceDataApi == null) { - log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); + // 1. 获取插件上下文 + ApplicationContext pluginContext = getApplicationContext(); + if (pluginContext == null) { + log.error("[HttpVertxPlugin] pluginContext is null, start failed."); return; } - // 初始化 Vert.x - vertx = Vertx.vertx(); - Router router = Router.router(vertx); - - // 处理 Body - router.route().handler(BodyHandler.create()); - - // 设置路由 - router.post("/sys/:productKey/:deviceName/thing/event/property/post") - .handler(new HttpVertxHandler(deviceDataApi)); - - // 启动 HTTP 服务器 - vertx.createHttpServer() - .requestHandler(router) - .listen(PORT, http -> { - if (http.succeeded()) { - log.info("HTTP 服务器启动成功,端口为: {}", PORT); - } else { - log.error("HTTP 服务器启动失败", http.cause()); - } - }); + // 2. 启动 Vertx + VertxService vertxService = pluginContext.getBean(VertxService.class); + vertxService.startServer(); } + @Override public void stop() { - log.info("HttpVertxPlugin.stop()"); - if (vertx != null) { - vertx.close(ar -> { - if (ar.succeeded()) { - log.info("Vert.x 关闭成功"); - } else { - log.error("Vert.x 关闭失败", ar.cause()); - } - }); + log.info("[HttpVertxPlugin] stop ..."); + ApplicationContext pluginContext = getApplicationContext(); + if (pluginContext != null) { + // 停止服务器 + VertxService vertxService = pluginContext.getBean(VertxService.class); + vertxService.stopServer(); } } @Override protected ApplicationContext createApplicationContext() { - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); - applicationContext.setClassLoader(getWrapper().getPluginClassLoader()); - applicationContext.refresh(); + AnnotationConfigApplicationContext pluginContext = new AnnotationConfigApplicationContext() { + @Override + protected void prepareRefresh() { + // 在刷新容器前注册主程序中的 Bean + ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); + DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); + beanFactory.registerSingleton("deviceDataApi", deviceDataApi); - return applicationContext; + super.prepareRefresh(); + } + }; + + pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); + pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.http.config"); + pluginContext.refresh(); + + return pluginContext; } -} \ No newline at end of file + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java index b5e977efb..55bce6f24 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java @@ -1,16 +1,67 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; -import org.pf4j.DefaultPluginManager; -import org.pf4j.PluginWrapper; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler; +import io.vertx.core.Vertx; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.handler.BodyHandler; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +/** + * 插件与独立运行都可复用的配置类 + */ +@Slf4j @Configuration public class HttpVertxPluginConfiguration { - @Bean(initMethod = "start") - public HttpVertxPlugin httpVertxPlugin() { - PluginWrapper pluginWrapper = new PluginWrapper(new DefaultPluginManager(), null, null, null); - return new HttpVertxPlugin(pluginWrapper); + /** + * 可在 application.yml 中配置,默认端口 8092 + */ + @Value("${plugin.http.server.port:8092}") + private Integer port; + + /** + * 创建 Vert.x 实例 + */ + @Bean + public Vertx vertx() { + return Vertx.vertx(); } -} \ No newline at end of file + + /** + * 创建路由 + */ + @Bean + public Router router(Vertx vertx, HttpVertxHandler httpVertxHandler) { + Router router = Router.router(vertx); + + // 处理 Body + router.route().handler(BodyHandler.create()); + + // 设置路由 + router.post("/sys/:productKey/:deviceName/thing/event/property/post") + .handler(httpVertxHandler); + + return router; + } + + /** + * 注入你的 Http 处理器 Handler,依赖 DeviceDataApi + */ + @Bean + public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) { + return new HttpVertxHandler(deviceDataApi); + } + + /** + * 定义一个 VertxService 来管理服务器启动逻辑 + * 无论是独立运行还是插件方式,都可以共用此类 + */ + @Bean + public VertxService vertxService(Vertx vertx, Router router) { + return new VertxService(port, vertx, router); + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/VertxService.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/VertxService.java new file mode 100644 index 000000000..5a57be8ee --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/VertxService.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.iot.plugin.http.config; + +import io.vertx.core.Vertx; +import io.vertx.ext.web.Router; +import lombok.extern.slf4j.Slf4j; + +/** + * 封装 Vert.x HTTP 服务的启动/关闭逻辑 + */ +@Slf4j +public class VertxService { + + private final Integer port; + private final Vertx vertx; + private final Router router; + + public VertxService(Integer port, Vertx vertx, Router router) { + this.port = port; + this.vertx = vertx; + this.router = router; + } + + /** + * 启动 HTTP 服务器 + */ + public void startServer() { + vertx.createHttpServer() + .requestHandler(router) + .listen(port, http -> { + if (http.succeeded()) { + log.info("[VertxService] HTTP 服务器启动成功, 端口: {}", port); + } else { + log.error("[VertxService] HTTP 服务器启动失败", http.cause()); + } + }); + } + + /** + * 关闭 HTTP 服务器 + */ + public void stopServer() { + if (vertx != null) { + vertx.close(ar -> { + if (ar.succeeded()) { + log.info("[VertxService] Vert.x 关闭成功"); + } else { + log.error("[VertxService] Vert.x 关闭失败", ar.cause()); + } + }); + } + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java index becba2a08..df55c68fd 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java @@ -22,77 +22,51 @@ public class HttpVertxHandler implements Handler { public void handle(RoutingContext ctx) { String productKey = ctx.pathParam("productKey"); String deviceName = ctx.pathParam("deviceName"); - RequestBody requestBody = ctx.body(); + RequestBody requestBody = ctx.body(); JSONObject jsonData; try { jsonData = JSONUtil.parseObj(requestBody.asJsonObject()); } catch (Exception e) { - JSONObject res = createResponseJson( - 400, - new JSONObject(), - null, - "请求数据不是合法的 JSON 格式: " + e.getMessage(), - "thing.event.property.post", - "1.0"); - ctx.response() - .setStatusCode(400) + log.error("[HttpVertxHandler] 请求数据解析失败", e); + ctx.response().setStatusCode(400) .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(res.toString()); + .end(createResponseJson(400, null, null, + "请求数据不是合法的 JSON 格式: " + e.getMessage(), + "thing.event.property.post", "1.0").toString()); return; } - String id = jsonData.getStr("id", null); + String id = jsonData.getStr("id"); try { - // 调用主程序的接口保存数据 - IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder() + IotDevicePropertyReportReqDTO reportReqDTO = IotDevicePropertyReportReqDTO.builder() .productKey(productKey) .deviceName(deviceName) - .params(jsonData) // TODO 芋艿:这块要优化 + .params(jsonData) .build(); - deviceDataApi.reportDevicePropertyData(createDTO); - // 构造成功响应内容 - JSONObject successRes = createResponseJson( - 200, - new JSONObject(), - id, - "success", - "thing.event.property.post", - "1.0"); + deviceDataApi.reportDevicePropertyData(reportReqDTO); + ctx.response() .setStatusCode(200) .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(successRes.toString()); + .end(createResponseJson(200, new JSONObject(), id, "success", + "thing.event.property.post", "1.0").toString()); + } catch (Exception e) { - JSONObject errorRes = createResponseJson( - 500, - new JSONObject(), - id, - "The format of result is error!", - "thing.event.property.post", - "1.0"); + log.error("[HttpVertxHandler] 上报属性数据失败", e); ctx.response() .setStatusCode(500) .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(errorRes.toString()); + .end(createResponseJson(500, new JSONObject(), id, + "The format of result is error!", + "thing.event.property.post", "1.0").toString()); } } - /** - * 创建标准化的响应 JSON 对象 - * - * @param code 响应状态码(业务层面的) - * @param data 返回的数据对象(JSON) - * @param id 请求的 id(可选) - * @param message 返回的提示信息 - * @param method 返回的 method 标识 - * @param version 返回的版本号 - * @return 构造好的 JSON 对象 - */ - private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, - String version) { + private JSONObject createResponseJson(int code, JSONObject data, String id, + String message, String method, String version) { JSONObject res = new JSONObject(); res.set("code", code); res.set("data", data != null ? data : new JSONObject()); From 5264de077d71f2a24414caf75497d6519cdf9e8f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 25 Jan 2025 11:26:10 +0800 Subject: [PATCH 098/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=8F=92=E4=BB=B6=E4=BD=93?= =?UTF-8?q?=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao-module-iot-plugin-common/pom.xml | 1 + .../iot/plugin/common/api/DeviceDataApiClient.java | 9 ++++++--- .../plugin/common/config/DeviceDataApiInitializer.java | 6 ++++-- .../yudao/module/iot/plugin/common/package-info.java | 1 + .../iot/plugin/http/HttpPluginSpringbootApplication.java | 6 +++--- .../module/iot/plugin/http/config/HttpVertxPlugin.java | 5 +++-- .../plugin/http/config/HttpVertxPluginConfiguration.java | 6 +++--- 7 files changed, 21 insertions(+), 13 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml index 568f86200..676b25f9e 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml @@ -13,6 +13,7 @@ ${project.artifactId} + 物联网 插件 模块 - 通用功能 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java index 183c76e58..f63267b27 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java @@ -10,6 +10,7 @@ import org.springframework.web.client.RestTemplate; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +// TODO @haohao:类注释,写一下,比较好 @Slf4j public class DeviceDataApiClient implements DeviceDataApi { @@ -17,32 +18,32 @@ public class DeviceDataApiClient implements DeviceDataApi { private final String deviceDataUrl; // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 + // TODO @haohao:可以用 lombok 简化 public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) { this.restTemplate = restTemplate; this.deviceDataUrl = deviceDataUrl; } + // TODO @haohao:返回结果,不用 CommonResult 哈。 @Override public CommonResult updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { - // 示例:如果对应的远程地址是 /rpc-api/iot/device-data/update-status String url = deviceDataUrl + "/rpc-api/iot/device-data/update-status"; return doPost(url, updateReqDTO, "updateDeviceStatus"); } @Override public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { - // 示例:如果对应的远程地址是 /rpc-api/iot/device-data/report-event String url = deviceDataUrl + "/rpc-api/iot/device-data/report-event"; return doPost(url, reportReqDTO, "reportDeviceEventData"); } @Override public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { - // 示例:如果对应的远程地址是 /rpc-api/iot/device-data/report-property String url = deviceDataUrl + "/rpc-api/iot/device-data/report-property"; return doPost(url, reportReqDTO, "reportDevicePropertyData"); } + // TODO @haohao:未来可能有 get 类型哈 /** * 将与远程服务交互的通用逻辑抽取成一个私有方法 */ @@ -51,10 +52,12 @@ public class DeviceDataApiClient implements DeviceDataApi { try { // 这里指定返回类型为 CommonResult,根据后台服务返回的实际结构做调整 restTemplate.postForObject(url, requestBody, CommonResult.class); + // TODO @haohao:check 结果,是否成功 return success(true); } catch (Exception e) { log.error("[{}] Error sending request to URL: {}", actionName, url, e); return CommonResult.error(400, "Request error: " + e.getMessage()); } } + } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java index 9473033c2..ed3944930 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java @@ -8,21 +8,23 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; +// TODO @haohao:这个最好是 autoconfiguration @Configuration public class DeviceDataApiInitializer { + // TODO @haohao:这个要不搞个配置类哈 @Value("${iot.device-data.url}") private String deviceDataUrl; @Bean public RestTemplate restTemplate() { - // 如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 + // TODO haohao:如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 return new RestTemplateBuilder().build(); } + // TODO @haohao:不存在时,才构建 @Bean public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { - // 返回我们自定义的 Client 实例 return new DeviceDataApiClient(restTemplate, deviceDataUrl); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java index f9eae496d..83b5bb58a 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java @@ -1 +1,2 @@ +// TODO @芋艿:注释 package cn.iocoder.yudao.module.iot.plugin.common; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java index 648b7dda6..91be33097 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java @@ -11,20 +11,20 @@ import org.springframework.context.ConfigurableApplicationContext; * 独立运行入口 */ @Slf4j -@SpringBootApplication(scanBasePackages = "cn.iocoder.yudao.module.iot.plugin") +@SpringBootApplication(scanBasePackages = "cn.iocoder.yudao.module.iot.plugin") // TODO @haohao:建议不扫描 cn.iocoder.yudao.module.iot.plugin;而是通过自动配置,初始化 common 的 public class HttpPluginSpringbootApplication { public static void main(String[] args) { - // 这里可选择 NONE / SERVLET / REACTIVE,看你需求 SpringApplication application = new SpringApplication(HttpPluginSpringbootApplication.class); application.setWebApplicationType(WebApplicationType.NONE); - ConfigurableApplicationContext context = application.run(args); // 手动获取 VertxService 并启动 + // TODO @haohao:可以放在 bean 的 init 里么? VertxService vertxService = context.getBean(VertxService.class); vertxService.startServer(); log.info("[HttpPluginSpringbootApplication] 独立模式启动完成"); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java index 85249cdb8..40694cf40 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java @@ -21,7 +21,8 @@ public class HttpVertxPlugin extends SpringPlugin { @Override public void start() { - log.info("[HttpVertxPlugin] start ..."); + // TODO @haohao:这种最好启动中,启动完成,成对打印日志,方便定位问题 + log.info("[HttpVertxPlugin][start ...]"); // 1. 获取插件上下文 ApplicationContext pluginContext = getApplicationContext(); @@ -38,7 +39,7 @@ public class HttpVertxPlugin extends SpringPlugin { @Override public void stop() { - log.info("[HttpVertxPlugin] stop ..."); + log.info("[HttpVertxPlugin][stop ...]"); ApplicationContext pluginContext = getApplicationContext(); if (pluginContext != null) { // 停止服务器 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java index 55bce6f24..5c221e795 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java @@ -17,6 +17,7 @@ import org.springframework.context.annotation.Configuration; @Configuration public class HttpVertxPluginConfiguration { + // TODO @haohao:这个要不要搞个配置类,更容易维护; /** * 可在 application.yml 中配置,默认端口 8092 */ @@ -42,15 +43,13 @@ public class HttpVertxPluginConfiguration { router.route().handler(BodyHandler.create()); // 设置路由 + // TODO @haohao:这个后续,我们是多个 Handler ,还是一个哈? router.post("/sys/:productKey/:deviceName/thing/event/property/post") .handler(httpVertxHandler); return router; } - /** - * 注入你的 Http 处理器 Handler,依赖 DeviceDataApi - */ @Bean public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) { return new HttpVertxHandler(deviceDataApi); @@ -64,4 +63,5 @@ public class HttpVertxPluginConfiguration { public VertxService vertxService(Vertx vertx, Router router) { return new VertxService(port, vertx, router); } + } From 269dec1b2e04552dfc5ad7820a81a174e1ccfef2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 25 Jan 2025 11:46:26 +0800 Subject: [PATCH 099/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=A8=A1=E6=8B=9F=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceDataController.java | 5 +- .../IotDeviceDataSimulatorSaveReqVO.java | 2 +- .../dal/dataobject/device/IotDeviceLogDO.java | 2 - .../dal/tdengine/IotDeviceLogDataMapper.java | 17 ++--- .../TDengineTableInitConfiguration.java | 6 +- .../deviceconsumer/DeviceConsumer.java | 6 +- .../simulatesend/SimulateSendProducer.java | 3 +- .../device/IotDeviceLogDataService.java | 6 +- .../device/IotDeviceLogDataServiceImpl.java | 70 ++++++------------- .../device/IotDevicePropertyDataService.java | 2 - .../IotDevicePropertyDataServiceImpl.java | 4 +- .../mapper/device/IotDeviceLogDataMapper.xml | 27 +++---- .../src/main/resources/application-local.yaml | 58 +++++---------- 13 files changed, 66 insertions(+), 142 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index f78a96b24..638c88046 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; @@ -52,7 +51,7 @@ public class IotDeviceDataController { return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); } - // TODO:数据权限 + // TODO:功能权限 @PostMapping("/simulator") @Operation(summary = "模拟设备") public CommonResult simulatorDevice(@Valid @RequestBody IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { @@ -62,7 +61,7 @@ public class IotDeviceDataController { return success(true); } - // TODO:数据权限 + // TODO:功能权限 @GetMapping("/log/page") @Operation(summary = "获得设备日志分页") public CommonResult> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java index 4d09808b1..efa608e57 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java @@ -19,7 +19,6 @@ public class IotDeviceDataSimulatorSaveReqVO { @NotEmpty(message = "产品标识不能为空") private String productKey; - // TODO @super:中文写作规范,中英文之间,要有空格。例如说,设备 ID。ps:这里应该是设备标识 @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123") @NotEmpty(message = "设备标识不能为空") private String deviceKey; @@ -38,6 +37,7 @@ public class IotDeviceDataSimulatorSaveReqVO { @NotEmpty(message = "数据内容不能为空") private String content; + // TODO @芋艿:需要讨论下,reportTime 到底以那个为准! @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED) private Long reportTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java index 609c9c43a..158b0f57b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java @@ -25,7 +25,6 @@ public class IotDeviceLogDO { */ private String id; - // TODO @super:关联要 @下 /** * 产品标识 *

@@ -33,7 +32,6 @@ public class IotDeviceLogDO { */ private String productKey; - // TODO @super:关联要 @下 /** * 设备标识 *

diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java index 2d8230f1f..f9d18bdcc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java @@ -10,9 +10,7 @@ import org.apache.ibatis.annotations.Param; import java.util.List; /** - * IOT 设备日志数据 Mapper 接口 - * - * 基于 TDengine 实现设备日志的存储 + * 设备日志 {@link IotDeviceLogDO} Mapper 接口 */ @Mapper @TDengineDS @@ -21,12 +19,11 @@ public interface IotDeviceLogDataMapper { /** * 创建设备日志超级表 - * 初始化只创建一次 */ void createDeviceLogSTable(); - // TODO @super:单个参数,不用加 @Param + // TODO @芋艿:在瞅瞅 //讨论:艿菇这里有些特殊情况,我也学习了一下这块知识: // 如果使用的是Java 8及以上版本,并且编译器保留了参数名(通过编译器选项-parameters启用),则可以去掉@Param注解。MyBatis会自动使用参数的实际名称 // 但在TDengine中 @Param去掉后TDengine会报错,以下是大模型的回答: @@ -65,18 +62,12 @@ public interface IotDeviceLogDataMapper { */ Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO); + // TODO @芋艿:这个方法名,后续看看叫啥好 /** * 查询设备日志表是否存在 * - * @return 不存在返回null + * @return 不存在返回 null */ Object checkDeviceLogSTableExists(); - /** - * 检查设备日志子表是否存在 - * - * @param deviceKey 设备标识 - * @return 不存在返回null - */ - Object checkDeviceLogTableExists(@Param("deviceKey") String deviceKey); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java index c9f08903e..9f3c79c22 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java @@ -6,17 +6,15 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; /** * TDengine 表初始化的 Configuration * * @author alwayssuper */ +@Configuration @Slf4j @RequiredArgsConstructor -@Configuration -@Order public class TDengineTableInitConfiguration implements ApplicationRunner { private final IotDeviceLogDataService deviceLogService; @@ -26,9 +24,7 @@ public class TDengineTableInitConfiguration implements ApplicationRunner { try { // 初始化设备日志表 deviceLogService.defineDeviceLog(); - // TODO @super:这个日志,是不是不用打,不然重复啦!!! } catch (Exception ex) { - // TODO @super:初始化失败,打印 error 日志,退出系统。。不然跑起来,就初始啦!!! // 初始化失败时打印错误日志并退出系统 log.error("[TDengine] 初始化设备日志表结构失败,系统无法正常运行,即将退出", ex); System.exit(1); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java index 1daa05f92..7403fb668 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.mq.consumer.deviceconsumer; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; @@ -20,8 +19,9 @@ import javax.annotation.Resource; @Component @Slf4j public class DeviceConsumer { + @Resource - private IotDeviceLogDataService iotDeviceLogDataService; + private IotDeviceLogDataService deviceLogDataService; @Resource private IotDevicePropertyDataService deviceDataService; @@ -35,7 +35,7 @@ public class DeviceConsumer { // 设备数据记录 deviceDataService.saveDeviceDataTest(message); // 设备日志记录 - iotDeviceLogDataService.saveDeviceLog(message); + deviceLogDataService.saveDeviceLog(message); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java index 1fb0c80c0..7366f4da5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java @@ -6,7 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; -// TODO @alwayssuper:是不是还没用起来哈?Producer 最好属于某个模块; +// TODO @芋艿:@alwayssuper:是不是还没用起来哈?Producer 最好属于某个模块; /** * SimulateSend 模拟设备上报的 Producer * @@ -28,4 +28,5 @@ public class SimulateSendProducer { public void sendSimulateMessage(ThingModelMessage thingModelMessage) { applicationContext.publishEvent(thingModelMessage); } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java index 2d7bf9850..637c8f51a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java @@ -16,7 +16,7 @@ public interface IotDeviceLogDataService { /** * 初始化 TDengine 超级表 * - *系统启动时,会自动初始化一次 + * 系统启动时,会自动初始化一次 */ void defineDeviceLog(); @@ -40,8 +40,8 @@ public interface IotDeviceLogDataService { /** * 插入设备日志 * - * @param msg 设备数据 + * @param message 设备数据 */ - void saveDeviceLog(ThingModelMessage msg); + void saveDeviceLog(ThingModelMessage message); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java index f66bcc8ad..bfe319955 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java @@ -13,7 +13,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.util.Date; import java.util.List; /** @@ -27,28 +26,18 @@ import java.util.List; public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ @Resource - private IotDeviceLogDataMapper iotDeviceLogDataMapper; + private IotDeviceLogDataMapper deviceLogDataMapper; - // TODO @super:方法名。defineDeviceLog。。未来,有可能别人使用别的记录日志,例如说 es 之类的。 @Override public void defineDeviceLog() { - // TODO @super:改成不存在才创建。 -// try { -// // 创建超级表(使用 IF NOT EXISTS 语句避免重复创建错误) -// iotDeviceLogDataMapper.createDeviceLogSTable(); -// } catch (Exception e) { -// if (e.getMessage().contains("already exists")) { -// log.info("[TDengine] 设备日志超级表已存在,跳过创建"); -// return; -// } -// throw e; -// } - if(iotDeviceLogDataMapper.checkDeviceLogSTableExists()==null){ - log.info("[TDengine] 设备日志超级表不存在,开始创建"); - iotDeviceLogDataMapper.createDeviceLogSTable(); - }else{ - log.info("[TDengine] 设备日志超级表已存在,跳过创建"); + if (deviceLogDataMapper.checkDeviceLogSTableExists() != null) { + log.info("[defineDeviceLog][设备日志超级表已存在,跳过创建]"); + return; } + + log.info("[defineDeviceLog][设备日志超级表不存在,开始创建]"); + deviceLogDataMapper.createDeviceLogSTable(); + log.info("[defineDeviceLog][设备日志超级表不存在,创建完成]"); } @Override @@ -57,47 +46,32 @@ public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ IotDeviceLogDO iotDeviceLogDO = BeanUtils.toBean(simulatorReqVO, IotDeviceLogDO.class); // 2. 处理时间字段 - // TODO @super:一次性的字段,不用单独给个变量 -// long currentTime = System.currentTimeMillis(); - // 2.1 设置时序时间为当前时间 // iotDeviceLogDO.setTs(currentTime); // TODO @super:TS在SQL中直接NOW 咱们的TS数据获取是走哪一种;走 now() // 3. 插入数据 - // TODO @super:不要直接调用对方的 IotDeviceLogDataMapper,通过 service 哈! - // 讨论:艿菇 这就是iotDeviceLogDataService的Impl - iotDeviceLogDataMapper.insert(iotDeviceLogDO); + deviceLogDataMapper.insert(iotDeviceLogDO); } - // TODO @super:在 iotDeviceLogDataService 写 - // 讨论:艿菇 这就是iotDeviceLogDataService的Impl @Override public PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { - // 当设备日志表未创建时,查询会出现报错 - if(iotDeviceLogDataMapper.checkDeviceLogTableExists(pageReqVO.getDeviceKey())==null){ - return null; - } - // 查询数据 - List list = iotDeviceLogDataMapper.selectPage(pageReqVO); - Long total = iotDeviceLogDataMapper.selectCount(pageReqVO); - // 构造分页结果 + // TODO @芋艿:增加一个表不存在的 try catch + List list = deviceLogDataMapper.selectPage(pageReqVO); + Long total = deviceLogDataMapper.selectCount(pageReqVO); return new PageResult<>(list, total); } @Override - public void saveDeviceLog(ThingModelMessage msg) { - // 1. 构建设备日志对象 - IotDeviceLogDO iotDeviceLogDO = IotDeviceLogDO.builder() - .id(msg.getId()) // 消息ID - .deviceKey(msg.getDeviceKey()) // 设备标识 - .productKey(msg.getProductKey()) // 产品标识 - .type(msg.getMethod()) // 消息类型,使用method作为类型 - .subType("property") // TODO:这块先写死,后续优化 - .content(JSONUtil.toJsonStr(msg)) // TODO:后续优化 - .reportTime(msg.getTime()) // 上报时间 + public void saveDeviceLog(ThingModelMessage message) { + IotDeviceLogDO log = IotDeviceLogDO.builder() + .id(message.getId()) + .deviceKey(message.getDeviceKey()) + .productKey(message.getProductKey()) + .type(message.getMethod()) // 消息类型,使用method作为类型 TODO 芋艿:在看看 + .subType("property") // TODO 芋艿:这块先写死,后续优化 + .content(JSONUtil.toJsonStr(message)) // TODO 芋艿:后续优化 + .reportTime(message.getTime()) // 上报时间 TODO 芋艿:在想想时间 .build(); - - // 2. 插入设备日志 - iotDeviceLogDataMapper.insert(iotDeviceLogDO); + deviceLogDataMapper.insert(log); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java index 92a64c28f..672785694 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java @@ -32,7 +32,6 @@ public interface IotDevicePropertyDataService { */ void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); - /** * 保存设备数据 * @@ -45,7 +44,6 @@ public interface IotDevicePropertyDataService { * * @param simulatorReqVO 设备数据 */ - void simulatorSend(IotDeviceDataSimulatorSaveReqVO simulatorReqVO); /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java index 2b998e788..abd788948 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java @@ -159,7 +159,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe thingModelMessageService.saveThingModelMessage(device, thingModelMessage); } - //TODO:后续捋一捋这块逻辑,先借鉴一下目前的代码 + //TODO @芋艿:后续捋一捋这块逻辑,先借鉴一下目前的代码 @Override public void saveDeviceDataTest(ThingModelMessage thingModelMessage) { // 1. 根据产品 key 和设备名称,获得设备信息 @@ -168,7 +168,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe thingModelMessageService.saveThingModelMessage(device, thingModelMessage); } - //TODO: copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 + //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 @Override public void simulatorSend(IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { // 1. 根据设备 key ,获得设备信息 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml index 828522ed7..039180857 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml @@ -4,28 +4,20 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - CREATE STABLE IF NOT EXISTS device_log ( - ts TIMESTAMP, - id NCHAR(50), - product_key NCHAR(50), - type NCHAR(50), - - sub_type NCHAR(50), - content NCHAR(1024), - report_time TIMESTAMP + ts TIMESTAMP, + id NCHAR(50), + product_key NCHAR(50), + type NCHAR(50), + sub_type NCHAR(50), + content NCHAR(1024), + report_time TIMESTAMP ) TAGS ( device_key NCHAR(50) ) - - - CREATE TABLE device_log_${deviceKey} USING device_log TAGS('${deviceKey}') - - - INSERT INTO device_log_${log.deviceKey} (ts, id, product_key, type, subType, content, report_time) USING device_log @@ -42,7 +34,7 @@ - - - \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 08918a667..4a23c0d57 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -45,7 +45,7 @@ spring: primary: master datasource: master: - url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 @@ -53,8 +53,8 @@ spring: # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 - username: ruoyi-vue-pro - password: ruoyi-@h2ju02hebp + username: root + password: ahh@123456 # username: sa # SQL Server 连接的示例 # password: Yudao@2024 # SQL Server 连接的示例 # username: SYSDBA # DM 连接的示例 @@ -63,25 +63,17 @@ spring: # password: Yudao@2024 # OpenGauss 连接的示例 slave: # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true - username: ruoyi-vue-pro - password: ruoyi-@h2ju02hebp - tdengine: # IOT 数据库 -# lazy: true # 开启懒加载,保证启动速度 - url: jdbc:TAOS-RS://chaojiniu.top:6041/ruoyi_vue_pro - driver-class-name: com.taosdata.jdbc.rs.RestfulDriver + url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true username: root - password: taosdata - druid: - validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL + password: ahh@123456 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: redis: - host: chaojiniu.top # 地址 + host: 127.0.0.1 # 地址 port: 6379 # 端口 - database: 15 # 数据库索引 - password: fsknKD7UvQYZsyf2hXXn # 密码,建议生产环境开启 + database: 0 # 数据库索引 +# password: dev # 密码,建议生产环境开启 --- #################### 定时任务相关配置 #################### @@ -191,12 +183,12 @@ debug: false --- #################### 微信公众号、小程序相关配置 #################### wx: mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 -# app-id: wx041349c6f39b268b # 测试号(牛希尧提供的) -# secret: 5abee519483bc9f8cb37ce280e814bd0 + # app-id: wx041349c6f39b268b # 测试号(牛希尧提供的) + # secret: 5abee519483bc9f8cb37ce280e814bd0 app-id: wx5b23ba7a5589ecbb # 测试号(自己的) secret: 2a7b3b20c537e52e74afd395eb85f61f -# app-id: wxa69ab825b163be19 # 测试号(Kongdy 提供的) -# secret: bd4f9fab889591b62aeac0d7b8d8b4a0 + # app-id: wxa69ab825b163be19 # 测试号(Kongdy 提供的) + # secret: bd4f9fab889591b62aeac0d7b8d8b4a0 # 存储配置,解决 AccessToken 的跨节点的共享 config-storage: type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 @@ -205,10 +197,10 @@ wx: miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 # appid: wx62056c0d5e8db250 # 测试号(牛希尧提供的) # secret: 333ae72f41552af1e998fe1f54e1584a -# appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 -# secret: 6f270509224a7ae1296bbf1c8cb97aed -# appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的) -# secret: 4a1a04e07f6a4a0751b39c3064a92c8b + # appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 + # secret: 6f270509224a7ae1296bbf1c8cb97aed + # appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的) + # secret: 4a1a04e07f6a4a0751b39c3064a92c8b appid: wx66186af0759f47c9 # 测试号(puhui 提供的) secret: 3218bcbd112cbc614c7264ceb20144ac config-storage: @@ -267,7 +259,7 @@ justauth: iot: emq: # 账号 - username: haohao + username: anhaohao # 密码 password: ahh@123456 # 主机地址 @@ -279,18 +271,4 @@ iot: # 保持连接 keepalive: 60 # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) - clearSession: true - -# MQTT-RPC 配置 -mqtt: - broker: tcp://chaojiniu.top:1883 - username: haohao - password: ahh@123456 - clientId: mqtt-rpc-server-${random.int} - requestTopic: rpc/request - responseTopicPrefix: rpc/response/ - - -# 插件配置 -pf4j: - pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录 \ No newline at end of file + clearSession: true \ No newline at end of file From 7bfa83062859d0e32e58cae406d60b66f7593e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 26 Jan 2025 17:29:03 +0800 Subject: [PATCH 100/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91=E9=87=8D=E6=9E=84=20HTTP=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=B9=B6=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=8A=A8=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao-module-iot-plugin-http-1.0.0.jar | Bin 12284 -> 12522 bytes .../plugin/PluginInstanceServiceImpl.java | 90 +++++++++--------- .../common/api/DeviceDataApiClient.java | 68 ++++++++++--- .../config/DeviceDataApiInitializer.java | 31 ------ .../YudaoDeviceDataApiAutoConfiguration.java | 51 ++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../http/HttpPluginSpringbootApplication.java | 3 +- .../plugin/http/config/HttpVertxPlugin.java | 50 ++++++---- .../config/HttpVertxPluginConfiguration.java | 14 +++ .../src/main/resources/application.yml | 5 + 10 files changed, 204 insertions(+), 109 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/plugins/yudao-module-iot-plugin-http-1.0.0.jar b/plugins/yudao-module-iot-plugin-http-1.0.0.jar index d3c4facae3d94154105193a3a07734640566e65f..c504342cf851e2a8ca4ad345e8f7f090f795960e 100644 GIT binary patch delta 4924 zcmaJ_2QZvp_g=m2FM2GZTYc5VMvtDDjRimL9psZ4^~Okh!QPCiB7bri55hU z2+>P|NQC&a-F|N2ca4s>j`h-k%&l# z_QGyqt3*`0PXqwCQ2+o2I0H?B&Y(CnG%Y~!h=C;qnjbbn`Z+3c zJk*Jm9en%RL)Fb&N`v2Qu#dhhpdvW^CSS~aF-o^^@QI3;YSS}n?}&nNEG{P%6M*nIaler`u>YWEeASyhyu z(PDalzz!QwHMojGzwJ}{A@PV)T7JV+lHFHzz8+4+(DKHsolnEKfVi2`1pk5`F3D>T zYRV!t^V^CgnW#ye!<4sJA{)_5Qt@;-fGDKG;y~_O<-P>+-hbwMAlLzK6!<*^*7ez? z=JrSDb@h>Nk)_F>k^Nkv3~N;LF-w(U6y`w#;w*X(xe$RIcJ0Ayd--y^MI1O_+v*8S?XDCZ;^cGc{BO)+ua&rhfo ztE&{gZC{fQcf$7JfF%4F5S`X0Hrv50_MT|Cl(3AuYrH$LZMV@E=Qn!%UbG(ALx(1_ zamAN$3GK7)`?0p{)ZG4#HUxL2wu5*lHY)uhFk79@lTvAr1)#rnyQwjWSoD zU{FEBc{GxT-IhjwP1)ewzaif#P%|KtQqd`e8 zUAK|Tif`Xxu+W2+dlqZ!)nUdJV?USrxx4oRc(7Ryj7?`8s&}SbKMu>=PWl#6B0jk= zX{H~1W5jUZxj{ik;?*?fGY|z6f!Z4RNU{4*j8zpK$F4*z|M^J8+jJh zF4B1?^xxJJJ6&pi`CLqjo9SAxPqZ>)881~!F`t%BYIP@q70@k~Cue@1r_i0ID$EyQ z;KHnc^?F$6yZu$ioAQbGv-huUufMYttrsiL1axAXmh0$ChBgaZ+~X_1?7YZ3;LjQNk~L&dOgx zK4_2F&`L`NqpaMKNTXY+1V<(q&D*suZ=y7jOhYh&?~=n!ojpJZ|Uqj0r-`&EsrZ`Q4Gajb3s0 zL7&+P{l|v22T3qxYUkqvL9Hu4sQ(lcasZs>;^<>(@@Iny0RRG$iwg7S=%Em}*ZhuOJ&K=P_B@45nL7O*Ce=Y7 zpi2?hxiGs^nj2DecjWNxF~{9@LjTxFfHD9K6t;8v`SWg~pU5bG>@w@t`1C!BjxfvTlsNd&1G*DO|UZI7wgK?;K< z2KRs59pYAfB)d|*cC&p(I;$%>VN}NsD2oH#_n@K&O7)EGf{KFljvPHjAAM;4lJ+$S zyAmJ>JZRd?hh3d#VnBS?U`YF>n7ekQwvmaTybr>%w3(AhM73zodwX!a2d16Bq5<+) z)c1?|CiDk6F$~;UPcxU2(Zy`k+-kWi_*Tx}CX1WinVAxDx4$^uAS*w+1wFS)4O(^x zmjar$sqFeDZX#aSfyM3b7de&pw!b{Woknw68M5sRx{VA!I_s>rKcXKqSvnDV7CXGJ zEh1TArC$;O_P|n@>L6E)t=dmA7TaLZ3<)rHA~*h)hDPLlzi^dJG^V?s{JqaDgpbQh z*D33((9HsO8gKhGC#cR;;CR&XgO^>JydP&A6$&xR<~D3phx+2YizwO#RxLEuf_l8Q zP1!zy+T>WWe&g4Fcv{|!&Bf(OFcT%eJLO}2es~qvaaD4m1*hD7D8{hr^@EuX*ciq$?l>XTVupvO9G#3+hKD1&k(+_u z%;#5#T7Oc*Ht+l4>LYuYvG%Cf3wuEyufN_qwi@O*pZ~?&LEFj!CnBT^mt-01c{x+# zeN(9g1NZz^k3oM)mC%o8iONPxLXS3zciA1L8FaVFYY8JQX-|hJJi#XxfuRp27RE?QUxIm8}8pz6JW9 zt@$ox<(8<|4$Y@EL!+z-KPCKAQEtA8cWbuIX&c0E=YG#8mzB&eV?~-wCJaQ6AZNhO zhhHgGZRtlPWS(jnFIySK2XYueo|x3QK0h$YVC@UQmPBCX0KgjBCay z#E#5Qk~a?mBaMlc8!*24bvUi?J8RkJLR(?zy<$}3m*TGVE;O@256D7+l9(nrO9d*! zt{To|ogs`y@d;-K{rcMd2z_(9d$c{MzjTOY1Va_XB>?Q(bT_IlcRl`*;qnOmQNXI@ zcpWESM8=VR_3EI{9=*>oT?q@gR@EClTQ6E_NU9&h`Tc`-V_H?^dU>Am>6f7sM#yxa zcJEO5iw&n^cp&KHKN7^;%y8s)+NyP;|)x~qQ4vw17#pg$SKQOkIcn*=~ znP7cZy(xE`;rJPf1;_WpA`Gzk=Puw$DCENy?`qGu%WEdo3sK7*k7Ei3);#BW$>{0E z$Xe*HvN-8T?}>%XCnEH@hvfPvk+^YP%t<6a$tUeR58Bbj_yd0&-}8bPzP)(83HBVP zR1$#-Sco^NaeRIRnZ7xK?%CkGY0EUz*Ka4Q8!terU5?Y_C&U!!bk$=p1IgOzREmKX z#uVFTg5XazV)0RUYbEs-#e zoRJ?hgQnMJP)vhuz|iC{S1y{V(48dcuP;eqAiAVmgdk?F9<>%LC!xBQ3NK$yOei)P zd-t&{FI%dC_q?bWs~hX(J4`NS`S2q8_<2aIq!qOAOs3vO_?4;#SNE#eIK;6#Rkxw= z$iC#K)y|4NjOSFVsVKCHJlRri*kZaj>1=G+-&gW^e_FfclCz$_LKxe$6EY)V0b~#R zxn%(o$=mYWMLdfrt(wbp&owGL0er{IYCXBGH&It!NBhS38il=wdDv569&`xV}xUGS5eDG`HC6L z@iWbp_wvqHRB*gq%uc8}jggWjP0zPoo~-;HDM-76BZ?325$~jWN(J&jmg%dQ^0%Oq zD)s!Uj3Hdv^wP*OHZ0-;ec2OR;u=IsLyk7P*Q&F1v2gXZS9#WG>&PIXved?A=UH_! zM$_AxGIiJ5xWOUGTb4CJ1JXNFcML)wmj{Jc8i+Z%rtF5tr}ptjBInO?G9NvL0fQ5G zV<8C8ukVIlJdn2Dr(b(RSk5IeD(NVh8!j|9)2_Xd;yNb$p9GNdNX-Q~jVTjV_;hjr z<@dX1<7S`lJtgxz#lBZZg)pup(B}FRYz1yJE`ONA#dH}~3{orhW|Fvq21RTR-UJVX z-J4#-%7PxVSa;<1Y4JbI>vZatJOe0(aB62&WK0dp)yQ&1D8)bJ=yT$i%9e-)^-?q^ z{Sxuhv|^;u=lk84%&#R&Wvzi2p{xINjgMtfdx_`oBNYQWB*$EI=@wHCOyT|)4SfE^ zq`sI)4-Z!-JEV`3J6bfr%@rJPaHX3QsCMohdnYu_1lQ}8Rie&DN20D)w9sDEuUvn$ zT`-X(L#Qqa#->THOz_w)Tall?^Okw=9TH1nt{dYxgRtmOG$w@+1RUB$|8qDm>L0pUKcMd;Qrwj!fOI@+;Vul z&ux0C9n_9->l0I4iUhF&*+_q!Aip`Lo0A4Gx=;n{uP8~nP54AEl|imZ+2$~lawBJ2 zD(SWR$CGAOx+%`bHj1BUukcPn5|-G>PXTDquc393I~n}`TMu3tqaE}Nd2!dhx|~f= z2KhHbq6E(6EGa9Lvu6|KYS(KTAh?h?249;qRPg|_OU21WxgsEBAi^sl#FtVCj#vPC zsfFO=1(fj`N3eh>9xDZ8@VF+RfJZ(-H9WcsYT~h8P!GR9G9g1eS_xU;v02CxzfHUr zf@2r<M`%>mT)x;{_ImMN(e)!f|L3AbzP} z5mrJF&4ozvFM{bMK?!#z3dF|=D8@=yeQDCbp~e37f$H^I|Ndp9Lq2mJXNY* zibw@C1{9y8-A6GFjT^=HXo4u7poyZ$2b4n51t^PR15gD;5J;8ewjQJ4u0ikt2mo-z z0RXg-Bp@!NG!G>*8$VuJNJ#Js?Mgdsub+@#!N&IR@$8h{&o3LNU-y<8;WwaVV~N;2 zyanxJaCmkKZ24n(+C2XPGd%qfX|lzpX|<_wK;LMl(zlDTFavV9E9eReMmYBW)u~g} z%qH34Ze$%kN#iCIKZF2VUAWSV=7OQna3+C=wIo#(aJEB#GySA}j=E{xZ=^ZWJo_7_ zuZTqn{DVny$+DqQY~o*#=S58vJ*h!+Ov&6<^vjy}CP~8#D!zvf{40 zm2D;9xf(Yim{7G;Zkpx>>=BBcCeJ#dLP! zDRsPRjFfnH7PekOsH6^AKHI>IbP2)Bl@y}P@>uo}mx|Gde)CBq%-EcHCP#X|%YipC z-`;EwT20p|Ss**w6#(ndZmVu=U9yoXXuo4gMjQ;4z)~-Oi)Q(RVs(p0I{<_&LLi zkO#qg@z{l~WSpyMy^=#Dbi_N%`X6{DH}dvY?F6^cl`}JDXj#pM=qw8}_bpzM!)97v z9+I7AaQx)-7wzA1jtk_!qWWfI6MOKM-o8F*(wx?Wk?@n7BuOfAYxEK)`MUe(?m5G~ zPb0yzSN@m@pli_Yh=L73{rlBt-d_WN000^W0HE;izkh>;3t!S9<0rnB!FxKOjmw;y z4GccUA~p9f6G#Sv1Tm<~+KQ&@Bqex7o5@#(;r&=}sRvTO6vdoyIaoIFo_(u%n6cpe zUR~t;dTsD2K(l&0mVuRy)$}+wb|sC<&CI8iN%+y0P{?Xn=@5!#vqZ;Txz%< z#NmRcUH+nd68_D*s#T<)*t-&25!~GZI6x-R) zeV>-&u?)m#^>R3ggWX;6*6=4n#`eGkK#dbySB2Q=mer&K5avcXIilI*M4AqV0o$zv zojFGJ94~p}1hkd*1lJ3UNlR5rXin-yKkx3!sDp2O^A`&kQST6Mx=j;=G0u@I29LKH zo)Id54+`!26hPNjgB&B&@~v6x{FyS0dL0oedo7MBOV5?`Io`mEx5L~T-3?MM3V4E; zT3OVMg-=5&vNrqhx6-$5HJvVA1RN99$q#0|6p`W6;@9(_`C%ReJMon>CKiLj`)tO_Aj9Xt*=#V=?R`kBQ8a*Xis8 zSu5B~Ioh$f{6mgD`K~by2e9t?32M6Y$^Mw*PB;bhJIGGQXQQc6N}0bE7r4X`ZHIXm zJ#h0|5xh@&@9ox-xn&{)$3zSad4gknv0|0XW@l!f@fu5rdtsZ$GFSaQpQ+9&X)|oXbsN&75$L`IR`YWjObMNu@5N($aYR;9dC-Fl5o#N{w0j}8}IY38kM4^(MZ@s0yw@}7Ug^;Ov>rH1y&Lnd8eeH=GOO5d& z&m`mx;S(}}8TiUZ%gzI-6k~>4T`7<>g&t~_hz@T-5qug>_blVYVt86D#Kx2hJ9+&1 z3y~K;n|V@5!F|H?ocYu(vThLKq^MI}U#=MZE~TXiiX{29uH^!K&H9*~wBNGoOtQ#9OVcT@kRQU%l)4gPtmkdO4vxK0 z>5ZvInF9BAJ>9vk61ayu>2}uUa%)o&OujF`iu&_4-$?Stxqw=2^SJjALdZBt+WEs* zcrIA%DULSr77sy|7Q2X-F&$CyvBO9>x~NP?bjxxb=j{nWI$w-eiCwXEMjl%n3o_PQ zHn%VGWLc7b*4F}|QQuEk?sx{wI8*Dgq{oneHO))V>hl=GFIL%Psc-@Wc#ZVWnw#Zh zw_K-?pP0;!V%~iC;(1;Y5kzBM32)kAOeJdS3uW_(H?c5W9Ue__muP<`IsbL_wR}vz z-rs|g@0;vOxRrS~0lVkQ6doZ2-J?2j$pLYVka!)ndd#jko(Gvrkmm>1bI}N&+~udC z!%ykIijC^_!V%1BnJu3{X&Vq;Txqi-jzcW~!{}xBgc*8vTUos3&c^X)hnIo!rVRtN%yE%jyAB*JFpVrMWJ9E4(C^P1-=Rqj*^O~XUr2)?z7Fc zf<}tbK&B5U47)q7dz%#6z<&!bzmHiiqWJus`s~r@QizyWgqX}wkWXiuaw=X(b2wL1 zD5w1q=I6xD2$D{%kow2s9Fmn+KzF}WVW)M0kb12yEaCb7?!cbDx!wLL83H0f;dOx} zQ7bxDMY$8RADuLq#ln@VBsOvEsm?TV+LM01Hy^L8C={#nUO7r6!@E=ZK@Hn6$)aLYHrj`nT%$HWH75JMOnJKe4fvd{b?ZK?+ z(=63p^36xh>&u>qad<`4()}ZQnG9OJ98noFD;IP{`nHu-aE#!as~aQm8|hS^4$jfF z=I4V(Tf1=GfeZ3QxA@wCH?Ik%dm~82qw#Th3tfXrsY+fl&Gl>7`PvVc72hLn5ejDR zH}!d38{m3&FwDpRhaZjY{%BzIZw=Tf+O2YSzBwDtt8%h-A$5M}-PhClK;C_F=cPDj zV%fl{ZC1Lr>rx*Up+@V2SGD-R{Hpj|mN?$^#}($oFS}+$c}C=VUG{6`(%*9O_D4er z9UBUC3+c5SkR&BGrWJmXGPuLhwxdb9X#<)_W1Ip5m2}UXs#$@tu=_+M%wz$^RSH37 zl;2wHx!sMOScJrsTQPu3H6$9w2*VHKY6QBt&#xIuy;W4mHl50og6t*b$E~sVxl8cmW zvyKMOoZWmDB&iFz2n26@g45a>U9K+R{f+^s%-ZNK!~R`}ZZFj3kpwJMs4SVCMI1#d zmZx{DZD-L$C%tPf8y(A$*RAf$+d~C_H0NVNN^|hRJE6pYQAsn`Q86YS8%_^5Vmyr# ztjc~v&59t>q`K2?r za%+?7HAWP7l%9ub-*`5JSUgIY)ewoCt!d<`4Je~@*SfM z+Iq+#bhlH0Qf+(Woe24~$ClDPJRk@5%Eao!C zx%*_)P5~01`vv2j^hfS++X=r*eo#I#hgDz+7A$>?~m(cFs<`K8_Cm+tYW( zzm@O!Ut?mx%?*J0&Wm&(^C)X5@HxU>SUd6kKV#beF=zbu`p%k%`PQF!P@NISM+>yS y6Yt!M9=XH!Paj>}-tPW=n+a(MB|?o5$|;eqPzoR=`+sb>kdshi%oFyz7yKXjiz3qi diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java index 65a6cf32b..cf10d2e3d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java @@ -40,9 +40,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @Slf4j public class PluginInstanceServiceImpl implements PluginInstanceService { - // TODO @haohao:这个可以后续确认下,有没更合适的标识。例如说 mac 地址之类的 - // 简化的 UUID + mac 地址 会不会好一些,一台机子有可能会部署多个插件; - // 那就 mac@uuid ? + // TODO @haohao:mac@uuid public static final String MAIN_ID = IdUtil.fastSimpleUUID(); @Resource @@ -60,32 +58,31 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { @Override public void stopAndUnloadPlugin(String pluginKey) { PluginWrapper plugin = pluginManager.getPlugin(pluginKey); - // TODO @haohao:改成 if return 会更简洁一点; - if (plugin != null) { - if (plugin.getPluginState().equals(PluginState.STARTED)) { - pluginManager.stopPlugin(pluginKey); // 停止插件 - log.info("已停止插件: {}", pluginKey); - } - pluginManager.unloadPlugin(pluginKey); // 卸载插件 - log.info("已卸载插件: {}", pluginKey); - } else { + if (plugin == null) { log.warn("插件不存在或已卸载: {}", pluginKey); + return; } + if (plugin.getPluginState().equals(PluginState.STARTED)) { + pluginManager.stopPlugin(pluginKey); // 停止插件 + log.info("已停止插件: {}", pluginKey); + } + pluginManager.unloadPlugin(pluginKey); // 卸载插件 + log.info("已卸载插件: {}", pluginKey); } @Override public void deletePluginFile(PluginInfoDO pluginInfoDO) { File file = new File(pluginsDir, pluginInfoDO.getFileName()); - // TODO @haohao:改成 if return 会更简洁一点; - if (file.exists()) { - try { - TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 - if (!file.delete()) { - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName()); - } - } catch (InterruptedException e) { - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), e); + if (!file.exists()) { + return; + } + try { + TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 + if (!file.delete()) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName()); } + } catch (InterruptedException e) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), e); } } @@ -120,25 +117,25 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { String pluginKey = pluginInfoDo.getPluginKey(); PluginWrapper plugin = pluginManager.getPlugin(pluginKey); - // TODO @haohao:改成 if return 会更简洁一点; - if (plugin != null) { - // 启动插件 - if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) - && plugin.getPluginState() != PluginState.STARTED) { - pluginManager.startPlugin(pluginKey); - log.info("已启动插件: {}", pluginKey); - } - // 停止插件 - else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) - && plugin.getPluginState() == PluginState.STARTED) { - pluginManager.stopPlugin(pluginKey); - log.info("已停止插件: {}", pluginKey); - } - } else { + if (plugin == null) { // 插件不存在且状态为停止,抛出异常 if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { throw exception(ErrorCodeConstants.PLUGIN_STATUS_INVALID); } + return; + } + + // 启动插件 + if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) + && plugin.getPluginState() != PluginState.STARTED) { + pluginManager.startPlugin(pluginKey); + log.info("已启动插件: {}", pluginKey); + } + // 停止插件 + else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) + && plugin.getPluginState() == PluginState.STARTED) { + pluginManager.stopPlugin(pluginKey); + log.info("已停止插件: {}", pluginKey); } } @@ -152,10 +149,10 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { Map pluginInfoMap = pluginInfos.stream() .collect(Collectors.toMap(PluginInfoDO::getPluginKey, Function.identity())); - // 1.3 获取本机 IP 和 MAC 地址 + // 1.3 获取本机 IP 和 MAC 地址,mac@uuid String ip = NetUtil.getLocalhostStr(); String mac = NetUtil.getLocalMacAddress(); - String mainId = MAIN_ID + "-" + mac; + String mainId = mac + "@" + MAIN_ID; // 2. 遍历插件列表,并保存为插件实例 for (PluginWrapper plugin : plugins) { @@ -173,14 +170,21 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { pluginInfo.getId()); if (pluginInstance == null) { // 4.4 如果插件实例不存在,则创建 - pluginInstance = PluginInstanceDO.builder().pluginId(pluginInfo.getId()).mainId(MAIN_ID + "-" + mac) - .ip(ip).port(port).heartbeatAt(System.currentTimeMillis()).build(); + pluginInstance = PluginInstanceDO.builder() + .pluginId(pluginInfo.getId()) + .mainId(MAIN_ID + "-" + mac) + .ip(ip) + .port(port) + .heartbeatAt(System.currentTimeMillis()) + .build(); pluginInstanceMapper.insert(pluginInstance); } else { // 2.2 情况二:如果存在,则更新 heartbeatAt - // TODO @haohao:这里最好 new 去 update;避免并发更新(虽然目前没有) - pluginInstance.setHeartbeatAt(System.currentTimeMillis()); - pluginInstanceMapper.updateById(pluginInstance); + PluginInstanceDO updatePluginInstance = PluginInstanceDO.builder() + .id(pluginInstance.getId()) + .heartbeatAt(System.currentTimeMillis()) + .build(); + pluginInstanceMapper.updateById(updatePluginInstance); } } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java index f63267b27..9fdb29ea8 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java @@ -5,24 +5,30 @@ import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.client.RestTemplate; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -// TODO @haohao:类注释,写一下,比较好 +/** + * 用于通过 {@link RestTemplate} 向远程 IoT 服务发送设备数据相关的请求, + * 包括设备状态更新、事件数据上报、属性数据上报等操作。 + */ @Slf4j +@RequiredArgsConstructor public class DeviceDataApiClient implements DeviceDataApi { + /** + * 用于发送 HTTP 请求的工具 + */ private final RestTemplate restTemplate; - private final String deviceDataUrl; - // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 - // TODO @haohao:可以用 lombok 简化 - public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) { - this.restTemplate = restTemplate; - this.deviceDataUrl = deviceDataUrl; - } + /** + * 远程 IoT 服务的基础 URL + * 例如:http://127.0.0.1:8080 + */ + private final String deviceDataUrl; // TODO @haohao:返回结果,不用 CommonResult 哈。 @Override @@ -43,17 +49,51 @@ public class DeviceDataApiClient implements DeviceDataApi { return doPost(url, reportReqDTO, "reportDevicePropertyData"); } - // TODO @haohao:未来可能有 get 类型哈 + /** - * 将与远程服务交互的通用逻辑抽取成一个私有方法 + * 发送 GET 请求 + * + * @param 请求体类型 + * @param url 请求 URL + * @param requestBody 请求体 + * @param actionName 操作名称 + * @return 响应结果 + */ + private CommonResult doGet(String url, T requestBody, String actionName) { + log.info("[{}] Sending request to URL: {}", actionName, url); + try { + CommonResult response = restTemplate.getForObject(url, CommonResult.class); + if (response != null && response.isSuccess()) { + return success(true); + } else { + log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response); + return CommonResult.error(500, "Request failed"); + } + } catch (Exception e) { + log.error("[{}] Error sending request to URL: {}", actionName, url, e); + return CommonResult.error(400, "Request error: " + e.getMessage()); + } + } + + /** + * 发送 POST 请求 + * + * @param 请求体类型 + * @param url 请求 URL + * @param requestBody 请求体 + * @param actionName 操作名称 + * @return 响应结果 */ private CommonResult doPost(String url, T requestBody, String actionName) { log.info("[{}] Sending request to URL: {}", actionName, url); try { - // 这里指定返回类型为 CommonResult,根据后台服务返回的实际结构做调整 - restTemplate.postForObject(url, requestBody, CommonResult.class); - // TODO @haohao:check 结果,是否成功 - return success(true); + CommonResult response = restTemplate.postForObject(url, requestBody, CommonResult.class); + if (response != null && response.isSuccess()) { + return success(true); + } else { + log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response); + return CommonResult.error(500, "Request failed"); + } } catch (Exception e) { log.error("[{}] Error sending request to URL: {}", actionName, url, e); return CommonResult.error(400, "Request error: " + e.getMessage()); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java deleted file mode 100644 index ed3944930..000000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.common.config; - -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -// TODO @haohao:这个最好是 autoconfiguration -@Configuration -public class DeviceDataApiInitializer { - - // TODO @haohao:这个要不搞个配置类哈 - @Value("${iot.device-data.url}") - private String deviceDataUrl; - - @Bean - public RestTemplate restTemplate() { - // TODO haohao:如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 - return new RestTemplateBuilder().build(); - } - - // TODO @haohao:不存在时,才构建 - @Bean - public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { - return new DeviceDataApiClient(restTemplate, deviceDataUrl); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java new file mode 100644 index 000000000..6ba82ed5d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.iot.plugin.common.config; + +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +import java.time.Duration; + +/** + * 设备数据 API 初始化器 + * + * @author haohao + */ +@AutoConfiguration +public class YudaoDeviceDataApiAutoConfiguration { + + + // TODO @haohao:这个要不搞个配置类哈 + @Value("${iot.device-data.url}") + private String deviceDataUrl; + + /** + * 创建 RestTemplate 实例 + * + * @return RestTemplate 实例 + */ + @Bean + public RestTemplate restTemplate() { + // 如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 + return new RestTemplateBuilder() + .setConnectTimeout(Duration.ofMillis(5000)) // 设置连接超时时间 + .setReadTimeout(Duration.ofMillis(5000)) // 设置读取超时时间 + .build(); + } + + /** + * 创建 DeviceDataApi 实例 + * + * @param restTemplate RestTemplate 实例 + * @return DeviceDataApi 实例 + */ + @Bean + public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { + return new DeviceDataApiClient(restTemplate, deviceDataUrl); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..65bd7ad7d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +cn.iocoder.yudao.module.iot.plugin.common.config.YudaoDeviceDataApiAutoConfiguration \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java index 91be33097..062b01808 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java @@ -11,7 +11,7 @@ import org.springframework.context.ConfigurableApplicationContext; * 独立运行入口 */ @Slf4j -@SpringBootApplication(scanBasePackages = "cn.iocoder.yudao.module.iot.plugin") // TODO @haohao:建议不扫描 cn.iocoder.yudao.module.iot.plugin;而是通过自动配置,初始化 common 的 +@SpringBootApplication public class HttpPluginSpringbootApplication { public static void main(String[] args) { @@ -21,6 +21,7 @@ public class HttpPluginSpringbootApplication { // 手动获取 VertxService 并启动 // TODO @haohao:可以放在 bean 的 init 里么? + // 会和插件模式冲突 VertxService vertxService = context.getBean(VertxService.class); vertxService.startServer(); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java index 40694cf40..9cc96ef10 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java @@ -21,30 +21,41 @@ public class HttpVertxPlugin extends SpringPlugin { @Override public void start() { - // TODO @haohao:这种最好启动中,启动完成,成对打印日志,方便定位问题 - log.info("[HttpVertxPlugin][start ...]"); + log.info("[HttpVertxPlugin][start][begin] 开始启动 HttpVertxPlugin 插件..."); - // 1. 获取插件上下文 - ApplicationContext pluginContext = getApplicationContext(); - if (pluginContext == null) { - log.error("[HttpVertxPlugin] pluginContext is null, start failed."); - return; + try { + // 1. 获取插件上下文 + ApplicationContext pluginContext = getApplicationContext(); + if (pluginContext == null) { + log.error("[HttpVertxPlugin][start][fail] pluginContext is null, 启动失败!"); + return; + } + + // 2. 启动 Vert.x + VertxService vertxService = pluginContext.getBean(VertxService.class); + vertxService.startServer(); + + log.info("[HttpVertxPlugin][start][end] 启动完成"); + } catch (Exception e) { + log.error("[HttpVertxPlugin][start][exception] 启动过程出现异常!", e); } - - // 2. 启动 Vertx - VertxService vertxService = pluginContext.getBean(VertxService.class); - vertxService.startServer(); } - @Override public void stop() { - log.info("[HttpVertxPlugin][stop ...]"); - ApplicationContext pluginContext = getApplicationContext(); - if (pluginContext != null) { - // 停止服务器 - VertxService vertxService = pluginContext.getBean(VertxService.class); - vertxService.stopServer(); + log.info("[HttpVertxPlugin][stop][begin] 开始停止 HttpVertxPlugin 插件..."); + + try { + ApplicationContext pluginContext = getApplicationContext(); + if (pluginContext != null) { + // 停止服务器 + VertxService vertxService = pluginContext.getBean(VertxService.class); + vertxService.stopServer(); + } + + log.info("[HttpVertxPlugin][stop][end] 停止完成"); + } catch (Exception e) { + log.error("[HttpVertxPlugin][stop][exception] 停止过程出现异常!", e); } } @@ -68,5 +79,4 @@ public class HttpVertxPlugin extends SpringPlugin { return pluginContext; } - -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java index 5c221e795..e61a4cf8f 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java @@ -34,6 +34,10 @@ public class HttpVertxPluginConfiguration { /** * 创建路由 + * + * @param vertx Vertx 实例 + * @param httpVertxHandler HttpVertxHandler 实例 + * @return Router 实例 */ @Bean public Router router(Vertx vertx, HttpVertxHandler httpVertxHandler) { @@ -50,6 +54,12 @@ public class HttpVertxPluginConfiguration { return router; } + /** + * 创建 HttpVertxHandler 实例 + * + * @param deviceDataApi DeviceDataApi 实例 + * @return HttpVertxHandler 实例 + */ @Bean public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) { return new HttpVertxHandler(deviceDataApi); @@ -58,6 +68,10 @@ public class HttpVertxPluginConfiguration { /** * 定义一个 VertxService 来管理服务器启动逻辑 * 无论是独立运行还是插件方式,都可以共用此类 + * + * @param vertx Vertx 实例 + * @param router Router 实例 + * @return VertxService 实例 */ @Bean public VertxService vertxService(Vertx vertx, Router router) { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml index e98d46eeb..3a64c0f37 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml @@ -5,3 +5,8 @@ spring: iot: device-data: url: http://127.0.0.1:48080 + +plugin: + http: + server: + port: 8092 From f4ad3e9d2d66ba93303ce3c7f70ff0b90527da87 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 26 Jan 2025 17:55:04 +0800 Subject: [PATCH 101/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=8F=92=E4=BB=B6=E4=BD=93?= =?UTF-8?q?=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../YudaoDeviceDataApiAutoConfiguration.java | 1 - .../http/HttpPluginSpringbootApplication.java | 3 +- .../plugin/http/config/HttpVertxPlugin.java | 29 +++++++++---------- .../src/main/resources/application.yml | 2 +- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java index 6ba82ed5d..2c1554474 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java @@ -18,7 +18,6 @@ import java.time.Duration; @AutoConfiguration public class YudaoDeviceDataApiAutoConfiguration { - // TODO @haohao:这个要不搞个配置类哈 @Value("${iot.device-data.url}") private String deviceDataUrl; diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java index 062b01808..bd64c8bb0 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java @@ -20,8 +20,7 @@ public class HttpPluginSpringbootApplication { ConfigurableApplicationContext context = application.run(args); // 手动获取 VertxService 并启动 - // TODO @haohao:可以放在 bean 的 init 里么? - // 会和插件模式冲突 + // TODO @haohao:可以放在 bean 的 init 里么?回复:会和插件模式冲突 @芋艿,测试下 VertxService vertxService = context.getBean(VertxService.class); vertxService.startServer(); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java index 9cc96ef10..f9a589a24 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; +import cn.hutool.core.lang.Assert; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import lombok.extern.slf4j.Slf4j; @@ -21,62 +22,60 @@ public class HttpVertxPlugin extends SpringPlugin { @Override public void start() { - log.info("[HttpVertxPlugin][start][begin] 开始启动 HttpVertxPlugin 插件..."); - + log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动开始...]"); try { // 1. 获取插件上下文 ApplicationContext pluginContext = getApplicationContext(); - if (pluginContext == null) { - log.error("[HttpVertxPlugin][start][fail] pluginContext is null, 启动失败!"); - return; - } + Assert.notNull(pluginContext, "pluginContext 不能为空"); // 2. 启动 Vert.x VertxService vertxService = pluginContext.getBean(VertxService.class); vertxService.startServer(); - log.info("[HttpVertxPlugin][start][end] 启动完成"); + log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动成功...]"); } catch (Exception e) { - log.error("[HttpVertxPlugin][start][exception] 启动过程出现异常!", e); + log.error("[HttpVertxPlugin][HttpVertxPlugin 插件开启动异常...]", e); } } @Override public void stop() { - log.info("[HttpVertxPlugin][stop][begin] 开始停止 HttpVertxPlugin 插件..."); - + log.info("[HttpVertxPlugin][HttpVertxPlugin 插件停止开始...]"); try { + // 停止服务器 ApplicationContext pluginContext = getApplicationContext(); if (pluginContext != null) { - // 停止服务器 VertxService vertxService = pluginContext.getBean(VertxService.class); vertxService.stopServer(); } - log.info("[HttpVertxPlugin][stop][end] 停止完成"); + log.info("[HttpVertxPlugin][HttpVertxPlugin 插件停止成功...]"); } catch (Exception e) { - log.error("[HttpVertxPlugin][stop][exception] 停止过程出现异常!", e); + log.error("[HttpVertxPlugin][HttpVertxPlugin 插件停止异常...]", e); } } @Override protected ApplicationContext createApplicationContext() { + // TODO @haohao:这个加 deviceDataApi 的目的是啥呀? AnnotationConfigApplicationContext pluginContext = new AnnotationConfigApplicationContext() { + @Override protected void prepareRefresh() { // 在刷新容器前注册主程序中的 Bean ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); beanFactory.registerSingleton("deviceDataApi", deviceDataApi); - super.prepareRefresh(); } + }; pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); + // TODO @芋艿:枚举 pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.http.config"); pluginContext.refresh(); - return pluginContext; } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml index 3a64c0f37..f7f89e3e6 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml @@ -9,4 +9,4 @@ iot: plugin: http: server: - port: 8092 + port: 8092 \ No newline at end of file From 8089f3a319efb919fce809b8e144c3fcc0694b4f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 27 Jan 2025 14:15:07 +0800 Subject: [PATCH 102/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=201.=20DeviceDataApi=20=3D>=20Io?= =?UTF-8?q?tDeviceUpstreamApi=EF=BC=8C=E5=B9=B6=E6=96=B0=E5=BB=BA=20upstre?= =?UTF-8?q?am=20=E5=8C=85=202.=20ThingModelMessage=20=3D>=20IotDeviceMessa?= =?UTF-8?q?ge=20=E8=AE=BE=E5=A4=87=E6=B6=88=E6=81=AF=203.=20=E5=9F=BA?= =?UTF-8?q?=E4=BA=8E=20spring=20event=20=E5=BC=82=E6=AD=A5=E6=B6=88?= =?UTF-8?q?=E8=B4=B9=20IotDeviceMessage=EF=BC=8C=E5=B9=B6=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20IotDeviceLogMessageConsumer=20=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/db/TenantDatabaseInterceptor.java | 2 +- .../tenant/core/util/TenantUtils.java | 20 ++ ...DataApi.java => IotDeviceUpstreamApi.java} | 33 +-- .../dto/IotDeviceEventReportReqDTO.java | 22 +- .../dto/IotDevicePropertyReportReqDTO.java | 23 +- .../dto/IotDeviceStatusUpdateReqDTO.java | 21 +- .../dto/IotDeviceUpstreamAbstractReqDTO.java | 46 +++ .../IotDeviceMessageIdentifierEnum.java | 22 ++ .../device/IotDeviceMessageTypeEnum.java | 22 ++ ...mpl.java => IoTDeviceUpstreamApiImpl.java} | 22 +- .../admin/device/IotDeviceDataController.java | 10 +- .../dal/dataobject/device/IotDeviceDO.java | 2 + .../dal/dataobject/device/IotDeviceLogDO.java | 36 ++- .../tdengine/ThingModelMessage.java | 70 ----- .../dal/tdengine/IotDeviceLogDataMapper.java | 32 +- .../iot/emq/service/EmqxServiceImpl.java | 8 +- .../iot/framework/aspect/TaosAspect.java | 1 + .../config/SecurityConfiguration.java | 29 ++ .../framework/security/core/package-info.java | 4 + .../TDengineTableInitConfiguration.java | 4 +- .../iot/job/plugin/PluginInstancesJob.java | 1 + .../device/IotDeviceLogMessageConsumer.java | 30 ++ .../IotDevicePropertyMessageConsumer.java | 34 +++ .../deviceconsumer/DeviceConsumer.java | 41 --- .../iot/mq/consumer/rule/package-info.java | 4 + .../iot/mq/message/IotDeviceMessage.java | 66 +++++ .../module/iot/mq/message/package-info.java | 4 - .../IotDeviceProducer.java} | 13 +- .../module/iot/mq/producer/package-info.java | 4 + .../device/IotDeviceLogDataServiceImpl.java | 77 ----- .../IotDeviceLogService.java} | 20 +- .../device/data/IotDeviceLogServiceImpl.java | 60 ++++ .../IotDevicePropertyService.java} | 12 +- .../IotDevicePropertyServiceImpl.java} | 60 +--- .../upstream/IotDeviceUpstreamService.java | 37 +++ .../IotDeviceUpstreamServiceImpl.java | 103 +++++++ .../product/IotProductServiceImpl.java | 4 +- .../tdengine/IotThingModelMessageService.java | 21 -- .../IotThingModelMessageServiceImpl.java | 277 ------------------ .../mapper/device/IotDeviceLogDataMapper.xml | 33 +-- .../common/api/DeviceDataApiClient.java | 81 ++--- .../YudaoDeviceDataApiAutoConfiguration.java | 4 +- .../yudao/module/iot/plugin/EmqxPlugin.java | 4 +- .../plugin/http/config/HttpVertxPlugin.java | 4 +- .../config/HttpVertxPluginConfiguration.java | 4 +- .../plugin/http/service/HttpVertxHandler.java | 11 +- 46 files changed, 648 insertions(+), 790 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/{DeviceDataApi.java => IotDeviceUpstreamApi.java} (72%) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceUpstreamAbstractReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/{DeviceDataApiImpl.java => IoTDeviceUpstreamApiImpl.java} (69%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageConsumer.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/{simulatesend/SimulateSendProducer.java => device/IotDeviceProducer.java} (50%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/package-info.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/{IotDeviceLogDataService.java => data/IotDeviceLogService.java} (55%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/{IotDevicePropertyDataService.java => data/IotDevicePropertyService.java} (82%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/{IotDevicePropertyDataServiceImpl.java => data/IotDevicePropertyServiceImpl.java} (81%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java index e220f8bcf..8ea1a96b8 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java @@ -13,7 +13,7 @@ import java.util.Set; /** * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能 * - * @author + * @author 芋道源码 */ public class TenantDatabaseInterceptor implements TenantLineHandler { diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java index 7ec9c69e3..b05b3c06b 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java @@ -45,6 +45,7 @@ public class TenantUtils { * * @param tenantId 租户编号 * @param callable 逻辑 + * @return 结果 */ public static V execute(Long tenantId, Callable callable) { Long oldTenantId = TenantContextHolder.getTenantId(); @@ -78,6 +79,25 @@ public class TenantUtils { } } + /** + * 忽略租户,执行对应的逻辑 + * + * @param callable 逻辑 + * @return 结果 + */ + public static V executeIgnore(Callable callable) { + Boolean oldIgnore = TenantContextHolder.isIgnore(); + try { + TenantContextHolder.setIgnore(true); + // 执行逻辑 + return callable.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + TenantContextHolder.setIgnore(oldIgnore); + } + } + /** * 将多租户编号,添加到 header 中 * diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java similarity index 72% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java index c2d36e18c..996ff1f5a 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java @@ -5,49 +5,44 @@ import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; import cn.iocoder.yudao.module.iot.enums.ApiConstants; -import jakarta.annotation.security.PermitAll; import jakarta.validation.Valid; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; -// TODO 芋艿:名字可能看情况改下 /** - * 设备数据 API + * 设备数据 Upstream 上行 API + * + * 目的:设备 -> 插件 -> 服务端 * * @author haohao */ -public interface DeviceDataApi { +public interface IotDeviceUpstreamApi { - // TODO @芋艿:可能会调整 - String PREFIX = ApiConstants.PREFIX + "/device-data"; + String PREFIX = ApiConstants.PREFIX + "/device/upstream"; /** * 更新设备状态 * - * @param updateReqDTO 更新请求 + * @param updateReqDTO 更新设备状态 DTO */ @PutMapping(PREFIX + "/update-status") - @PermitAll // TODO 芋艿:后续看看怎么优化下 CommonResult updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqDTO updateReqDTO); + /** + * 上报设备属性数据 + * + * @param reportReqDTO 上报设备属性数据 DTO + */ + @PostMapping(PREFIX + "/report-property") + CommonResult reportDevicePropertyData(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO); + /** * 上报设备事件数据 * * @param reportReqDTO 设备事件 */ @PostMapping(PREFIX + "/report-event") - @PermitAll // TODO 芋艿:后续看看怎么优化下 CommonResult reportDeviceEventData(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO); - /** - * 上报设备属性数据 - * - * @param reportReqDTO 设备数据 - */ - @PostMapping(PREFIX + "/report-property") - @PermitAll // TODO 芋艿:后续看看怎么优化下 - CommonResult reportDevicePropertyData(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO); - - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java index 373905c94..6376eb8a4 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java @@ -1,10 +1,9 @@ package cn.iocoder.yudao.module.iot.api.device.dto; import jakarta.validation.constraints.NotEmpty; -import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; import java.util.Map; @@ -12,24 +11,9 @@ import java.util.Map; * IoT 设备【事件】数据上报 Request DTO */ @Data +@SuperBuilder @NoArgsConstructor -@AllArgsConstructor -@Builder -public class IotDeviceEventReportReqDTO { - - // TODO 芋艿:要不要 id - // TODO 芋艿:要不要 time - - /** - * 产品标识 - */ - @NotEmpty(message = "产品标识不能为空") - private String productKey; - /** - * 设备名称 - */ - @NotEmpty(message = "设备名称不能为空") - private String deviceName; +public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO { /** * 事件标识 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java index 37a4c6c98..9173a39ca 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java @@ -1,10 +1,9 @@ package cn.iocoder.yudao.module.iot.api.device.dto; import jakarta.validation.constraints.NotEmpty; -import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; import java.util.Map; @@ -12,28 +11,14 @@ import java.util.Map; * IoT 设备【属性】数据上报 Request DTO */ @Data +@SuperBuilder @NoArgsConstructor -@AllArgsConstructor -@Builder -public class IotDevicePropertyReportReqDTO { +public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO { - // TODO 芋艿:要不要 id - // TODO 芋艿:要不要 time - - /** - * 产品标识 - */ - @NotEmpty(message = "产品标识不能为空") - private String productKey; - /** - * 设备名称 - */ - @NotEmpty(message = "设备名称不能为空") - private String deviceName; /** * 属性参数 */ @NotEmpty(message = "属性参数不能为空") - private Map params; + private Map properties; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java index 0b08f2bd1..111427a03 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java @@ -3,33 +3,18 @@ package cn.iocoder.yudao.module.iot.api.device.dto; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import jakarta.validation.constraints.NotEmpty; -import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; /** * IoT 设备状态更新 Request DTO */ @Data +@SuperBuilder @NoArgsConstructor -@AllArgsConstructor -@Builder -public class IotDeviceStatusUpdateReqDTO { +public class IotDeviceStatusUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO { - // TODO 芋艿:要不要 id - // TODO 芋艿:要不要 time - - /** - * 产品标识 - */ - @NotEmpty(message = "产品标识不能为空") - private String productKey; - /** - * 设备名称 - */ - @NotEmpty(message = "设备名称不能为空") - private String deviceName; /** * 设备状态 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceUpstreamAbstractReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceUpstreamAbstractReqDTO.java new file mode 100644 index 000000000..b2a843eff --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceUpstreamAbstractReqDTO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.iot.api.device.dto; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import java.time.LocalDateTime; + +/** + * IoT 设备上行的抽象 Request DTO + * + * @author 芋道源码 + */ +@Data +@SuperBuilder +@NoArgsConstructor +public abstract class IotDeviceUpstreamAbstractReqDTO { + + /** + * 请求编号 + */ + private String requestId; + + /** + * 插件标识 + */ + private String pluginKey; + + /** + * 产品标识 + */ + @NotEmpty(message = "产品标识不能为空") + private String productKey; + /** + * 设备名称 + */ + @NotEmpty(message = "设备名称不能为空") + private String deviceName; + + /** + * 上报时间 + */ + private LocalDateTime reportTime; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java new file mode 100644 index 000000000..bb639f49a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.enums.device; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * IoT 设备消息标识符枚举 + */ +@Getter +@RequiredArgsConstructor +public enum IotDeviceMessageIdentifierEnum { + + PROPERTY_GET("get"), + PROPERTY_SET("set"), + PROPERTY_REPORT("report"); + + /** + * 标志符 + */ + private final String identifier; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java new file mode 100644 index 000000000..b3f00e860 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.enums.device; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * IoT 设备消息类型枚举 + */ +@Getter +@RequiredArgsConstructor +public enum IotDeviceMessageTypeEnum { + + STATE("state"), // 设备状态 + PROPERTY("property"), // 设备属性 + EVENT("event"); // 设备事件 + + /** + * 属性 + */ + private final String type; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java similarity index 69% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java index cdcfdfdfd..0e6df1480 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; +import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; @@ -13,28 +13,30 @@ import javax.annotation.Resource; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; /** - * 设备数据 API 实现类 + * * 设备数据 Upstream 上行 API 实现类 */ @RestController @Validated -public class DeviceDataApiImpl implements DeviceDataApi { +public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi { @Resource - private IotDevicePropertyDataService deviceDataService; + private IotDeviceUpstreamService deviceUpstreamService; @Override public CommonResult updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { - return success(true); - } - - @Override - public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { + deviceUpstreamService.updateDeviceStatus(updateReqDTO); return success(true); } @Override public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { - deviceDataService.saveDeviceData(reportReqDTO); + deviceUpstreamService.reportDevicePropertyData(reportReqDTO); + return success(true); + } + + @Override + public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { + deviceUpstreamService.reportDeviceEventData(reportReqDTO); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 638c88046..15366cf9c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -27,13 +27,13 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; public class IotDeviceDataController { @Resource - private IotDevicePropertyDataService deviceDataService; + private IotDevicePropertyService deviceDataService; @Resource - private IotDeviceLogDataService iotDeviceLogDataService; + private IotDeviceLogService iotDeviceLogDataService; @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性 - private IotDeviceLogDataService deviceLogDataService; + private IotDeviceLogService deviceLogDataService; // TODO @浩浩:这里的 /latest-list,包括方法名。 @GetMapping("/latest") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index f396855f1..f1d5f9792 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -36,6 +36,8 @@ public class IotDeviceDO extends BaseDO { private Long id; /** * 设备唯一标识符,全局唯一,用于识别设备 + * + * 类似阿里云 QueryDeviceInfo 的 IotInstanceId */ private String deviceKey; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java index 158b0f57b..afd066941 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java @@ -1,6 +1,10 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; +import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -19,37 +23,51 @@ import lombok.NoArgsConstructor; @AllArgsConstructor public class IotDeviceLogDO { - // TODO @芋艿:消息 ID 的生成逻辑 /** - * 消息 ID + * 日志编号 + * + * 通过 {@link IdUtil#fastSimpleUUID()} 生成 */ private String id; + /** + * 请求编号 + * + * 对应 {@link IotDeviceMessage#getRequestId()} 字段 + */ + private String requestId; + /** * 产品标识 *

* 关联 {@link IotProductDO#getProductKey()} */ private String productKey; - + /** + * 设备名称 + * + * 关联 {@link IotDeviceDO#getDeviceName()} + */ + private String deviceName; /** * 设备标识 *

* 关联 {@link IotDeviceDO#getDeviceKey()}} */ - private String deviceKey; + private String deviceKey; // 非存储字段,用于 TDengine 的 TAG - // TODO @super:枚举类 /** * 日志类型 + * + * 枚举 {@link IotDeviceMessageTypeEnum} */ private String type; - - // TODO @super:枚举类 /** - * 标识符:用于标识具体的属性、事件或服务 + * 标识符 + * + * 枚举 {@link IotDeviceMessageIdentifierEnum} */ - private String subType; + private String identifier; /** * 数据内容 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java deleted file mode 100644 index d5009dc24..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessage.java +++ /dev/null @@ -1,70 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.HashMap; -import java.util.Map; - -/** - * 物模型消息 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class ThingModelMessage { - - /** - * 消息ID - */ - private String id; - - /** - * 扩展功能的参数 - */ - private Object sys; - - /** - * 请求方法 例如:thing.event.property.post - */ - private String method; - - /** - * 请求参数 - */ - private Object params; - - /** - * 属性上报时间戳 - */ - private Long time; - - /** - * 设备信息 - */ - private String productKey; - - /** - * 设备名称 - */ - private String deviceName; - - /** - * 设备 key - */ - private String deviceKey; - - /** - * 转换为 Map 类型 - */ - public Map dataToMap() { - Map mapData = new HashMap<>(); - if (params instanceof Map) { - ((Map) params).forEach((key, value) -> mapData.put(key.toString(), value)); - } - return mapData; - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java index f9d18bdcc..cd9f387a7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java @@ -22,21 +22,13 @@ public interface IotDeviceLogDataMapper { */ void createDeviceLogSTable(); - // TODO @super:单个参数,不用加 @Param - // TODO @芋艿:在瞅瞅 - //讨论:艿菇这里有些特殊情况,我也学习了一下这块知识: - // 如果使用的是Java 8及以上版本,并且编译器保留了参数名(通过编译器选项-parameters启用),则可以去掉@Param注解。MyBatis会自动使用参数的实际名称 - // 但在TDengine中 @Param去掉后TDengine会报错,以下是大模型的回答: - // 不用加 @Param在普通的 MySQL 场景下是正确的 - 对于 MyBatis,当方法只有一个参数时,确实可以不用添加 @Param 注解。 - //但是在 TDengine 的场景下,情况不同: - //TDengine 的特殊性: - //TDengine 使用特殊的 SQL 语法 - //需要处理超级表(STable)和子表的概念 - //参数绑定的方式与普通 MySQL 不同 - //为什么这里必须要 @Param: - //XML 中使用了 ${log.deviceKey} 这样的参数引用方式 - //需要在 SQL 中动态构建表名(device_log_${log.deviceKey}) - //没有 @Param("log") 的话,MyBatis 无法正确解析参数 + /** + * 查询设备日志表是否存在 + * + * @return 存在则返回表名;不存在则返回 null + */ + String showDeviceLogSTable(); + /** * 插入设备日志数据 * @@ -44,7 +36,7 @@ public interface IotDeviceLogDataMapper { * * @param log 设备日志数据 */ - void insert(@Param("log") IotDeviceLogDO log); + void insert(IotDeviceLogDO log); /** * 获得设备日志分页 @@ -62,12 +54,4 @@ public interface IotDeviceLogDataMapper { */ Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO); - // TODO @芋艿:这个方法名,后续看看叫啥好 - /** - * 查询设备日志表是否存在 - * - * @return 不存在返回 null - */ - Object checkDeviceLogSTableExists(); - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index 222d1d50a..ca9a6bac7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.emq.service; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttClient; @@ -20,7 +20,7 @@ import org.springframework.scheduling.annotation.Async; public class EmqxServiceImpl implements EmqxService { @Resource - private IotDevicePropertyDataService iotDeviceDataService; + private IotDevicePropertyService iotDeviceDataService; // TODO 多线程处理消息 @Override @@ -35,8 +35,8 @@ public class EmqxServiceImpl implements EmqxService { String deviceName = topic.split("/")[3]; String message = new String(mqttMessage.getPayload()); IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder() - .productKey(productKey) - .deviceName(deviceName) +// .productKey(productKey) +// .deviceName(deviceName) // .properties(message) // TODO 芋艿:临时去掉,看看 .build(); iotDeviceDataService.saveDeviceData(createDTO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java index 7c9fe7000..61b03dc42 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/aspect/TaosAspect.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Component; import java.sql.Timestamp; import java.util.Map; +// TODO @haohao:这个还需要的么? /** * TaosAspect 是一个处理 Taos 数据库返回值的切面。 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java new file mode 100644 index 000000000..9cf00cc10 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.framework.security.config; + +import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; +import cn.iocoder.yudao.module.iot.enums.ApiConstants; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; + +/** + * IoT 模块的 Security 配置 + */ +@Configuration(proxyBeanMethods = false, value = "iotSecurityConfiguration") +public class SecurityConfiguration { + + @Bean("iotAuthorizeRequestsCustomizer") + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { + return new AuthorizeRequestsCustomizer() { + + @Override + public void customize(AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry registry) { + // RPC 服务的安全配置 + registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); + } + + }; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java new file mode 100644 index 000000000..c714d1027 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java @@ -0,0 +1,4 @@ +/** + * 占位 + */ +package cn.iocoder.yudao.module.iot.framework.security.core; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java index 9f3c79c22..3e84ac11c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.framework.tdengine.config; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; @@ -17,7 +17,7 @@ import org.springframework.context.annotation.Configuration; @RequiredArgsConstructor public class TDengineTableInitConfiguration implements ApplicationRunner { - private final IotDeviceLogDataService deviceLogService; + private final IotDeviceLogService deviceLogService; @Override public void run(ApplicationArguments args) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java index d32148b47..fbcfea340 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.concurrent.TimeUnit; +// TODO 芋艿:后续再看看 /** * 插件实例 Job * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageConsumer.java new file mode 100644 index 000000000..297267791 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageConsumer.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.device; + +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +/** + * 针对 {@link IotDeviceMessage} 的消费者,记录设备日志 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class IotDeviceLogMessageConsumer { + + @Resource + private IotDeviceLogService deviceLogService; + + @EventListener + @Async + public void onMessage(IotDeviceMessage message) { + log.info("[onMessage][消息内容({})]", message); + deviceLogService.createDeviceLog(message); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java new file mode 100644 index 000000000..63b4c9a5e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.device; + +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 针对 {@link IotDeviceMessage} 的消费者,记录设备属性 + * + * @author alwayssuper + */ +@Component +@Slf4j +public class IotDevicePropertyMessageConsumer { + + @Resource + private IotDevicePropertyService deviceDataService; + + @EventListener + @Async + public void onMessage(IotDeviceMessage message) { + log.info("[onMessage][消息内容({})]", message); + + // 设备日志记录 + // TODO @芋艿:重新写下 +// deviceLogDataService.createDeviceLog(message); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java deleted file mode 100644 index 7403fb668..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/deviceconsumer/DeviceConsumer.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.iot.mq.consumer.deviceconsumer; - - -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 针对 {@link ThingModelMessage} 的消费者 - * - * @author alwayssuper - */ -@Component -@Slf4j -public class DeviceConsumer { - - @Resource - private IotDeviceLogDataService deviceLogDataService; - @Resource - private IotDevicePropertyDataService deviceDataService; - - // TODO @芋艿:这块先用ThingModelMessage,后续看看用啥替代 - @EventListener - @Async - public void onMessage(ThingModelMessage message) { - log.info("[onMessage][消息内容({})]", message); - //TODO:数据插入这块整体写的比较混乱,整体借鉴了浩浩哥之前写的逻辑,目前是通过模拟设备科插入数据了,但之前的逻辑有大量弃用的部分,后续看看怎么完善 - - // 设备数据记录 - deviceDataService.saveDeviceDataTest(message); - // 设备日志记录 - deviceLogDataService.saveDeviceLog(message); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java new file mode 100644 index 000000000..392044317 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 芋艿:未来实现一个 IotRuleMessageConsumer + */ +package cn.iocoder.yudao.module.iot.mq.consumer.rule; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java new file mode 100644 index 000000000..db42b4fe1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.iot.mq.message; + +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * 设备消息 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class IotDeviceMessage { + + /** + * 请求编号 + */ + private String requestId; + + /** + * 设备信息 + */ + private String productKey; + /** + * 设备名称 + */ + private String deviceName; + /** + * 设备标识 + */ + private String deviceKey; + + /** + * 消息类型 + * + * 枚举 {@link IotDeviceMessageTypeEnum} + */ + private String type; + /** + * 标识符 + * + * 枚举 {@link IotDeviceMessageIdentifierEnum} + */ + private String identifier; + + /** + * 请求参数 + * + * 例如说:属性上报的 properties、事件上报的 params + */ + private Object data; + + /** + * 上报时间 + */ + private LocalDateTime reportTime; + + // TODO @芋艿 code; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java deleted file mode 100644 index c3adf7c06..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 消息队列的消息 - */ -package cn.iocoder.yudao.module.iot.mq.message; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java similarity index 50% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java index 7366f4da5..c3855fbfe 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/simulatesend/SimulateSendProducer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java @@ -1,31 +1,30 @@ -package cn.iocoder.yudao.module.iot.mq.producer.simulatesend; +package cn.iocoder.yudao.module.iot.mq.producer.device; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; -// TODO @芋艿:@alwayssuper:是不是还没用起来哈?Producer 最好属于某个模块; /** - * SimulateSend 模拟设备上报的 Producer + * Iot 设备相关消息的 Producer * * @author alwayssuper * @since 2024/12/17 16:35 */ @Slf4j @Component -public class SimulateSendProducer { +public class IotDeviceProducer { @Resource private ApplicationContext applicationContext; /** - * 发送 {@link ThingModelMessage} 消息 + * 发送 {@link IotDeviceMessage} 消息 * * @param thingModelMessage 物模型消息 */ - public void sendSimulateMessage(ThingModelMessage thingModelMessage) { + public void sendDeviceMessage(IotDeviceMessage thingModelMessage) { applicationContext.publishEvent(thingModelMessage); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/package-info.java new file mode 100644 index 000000000..37d0ba016 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO 芋艿:临时占位 + */ +package cn.iocoder.yudao.module.iot.mq.producer; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java deleted file mode 100644 index bfe319955..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataServiceImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.device; - -import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.List; - -/** - * IoT 设备日志数据 Service 实现了 - * - * @author alwayssuper - */ -@Service -@Slf4j -@Validated -public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ - - @Resource - private IotDeviceLogDataMapper deviceLogDataMapper; - - @Override - public void defineDeviceLog() { - if (deviceLogDataMapper.checkDeviceLogSTableExists() != null) { - log.info("[defineDeviceLog][设备日志超级表已存在,跳过创建]"); - return; - } - - log.info("[defineDeviceLog][设备日志超级表不存在,开始创建]"); - deviceLogDataMapper.createDeviceLogSTable(); - log.info("[defineDeviceLog][设备日志超级表不存在,创建完成]"); - } - - @Override - public void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { - // 1. 转换请求对象为 DO - IotDeviceLogDO iotDeviceLogDO = BeanUtils.toBean(simulatorReqVO, IotDeviceLogDO.class); - - // 2. 处理时间字段 -// iotDeviceLogDO.setTs(currentTime); // TODO @super:TS在SQL中直接NOW 咱们的TS数据获取是走哪一种;走 now() - - // 3. 插入数据 - deviceLogDataMapper.insert(iotDeviceLogDO); - } - - @Override - public PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { - // TODO @芋艿:增加一个表不存在的 try catch - List list = deviceLogDataMapper.selectPage(pageReqVO); - Long total = deviceLogDataMapper.selectCount(pageReqVO); - return new PageResult<>(list, total); - } - - @Override - public void saveDeviceLog(ThingModelMessage message) { - IotDeviceLogDO log = IotDeviceLogDO.builder() - .id(message.getId()) - .deviceKey(message.getDeviceKey()) - .productKey(message.getProductKey()) - .type(message.getMethod()) // 消息类型,使用method作为类型 TODO 芋艿:在看看 - .subType("property") // TODO 芋艿:这块先写死,后续优化 - .content(JSONUtil.toJsonStr(message)) // TODO 芋艿:后续优化 - .reportTime(message.getTime()) // 上报时间 TODO 芋艿:在想想时间 - .build(); - deviceLogDataMapper.insert(log); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java similarity index 55% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java index 637c8f51a..ff695a782 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceLogDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java @@ -1,17 +1,16 @@ -package cn.iocoder.yudao.module.iot.service.device; +package cn.iocoder.yudao.module.iot.service.device.data; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; /** * IoT 设备日志数据 Service 接口 * * @author alwayssuper */ -public interface IotDeviceLogDataService { +public interface IotDeviceLogService { /** * 初始化 TDengine 超级表 @@ -23,11 +22,9 @@ public interface IotDeviceLogDataService { /** * 插入设备日志 * - * 当该设备第一次插入日志时,自动创建该设备的设备日志子表 - * - * @param simulatorReqVO 设备日志模拟数据 + * @param message 设备数据 */ - void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO); + void createDeviceLog(IotDeviceMessage message); /** * 获得设备日志分页 @@ -37,11 +34,4 @@ public interface IotDeviceLogDataService { */ PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO); - /** - * 插入设备日志 - * - * @param message 设备数据 - */ - void saveDeviceLog(ThingModelMessage message); - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java new file mode 100644 index 000000000..fa5398a79 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.iot.service.device.data; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * IoT 设备日志数据 Service 实现类 + * + * @author alwayssuper + */ +@Service +@Slf4j +@Validated +public class IotDeviceLogServiceImpl implements IotDeviceLogService { + + @Resource + private IotDeviceLogDataMapper deviceLogDataMapper; + + @Override + public void defineDeviceLog() { + if (StrUtil.isNotEmpty(deviceLogDataMapper.showDeviceLogSTable())) { + log.info("[defineDeviceLog][设备日志超级表已存在,创建跳过]"); + return; + } + + log.info("[defineDeviceLog][设备日志超级表不存在,创建开始...]"); + deviceLogDataMapper.createDeviceLogSTable(); + log.info("[defineDeviceLog][设备日志超级表不存在,创建成功]"); + } + + @Override + public void createDeviceLog(IotDeviceMessage message) { + IotDeviceLogDO log = BeanUtils.toBean(message, IotDeviceLogDO.class) + .setId(IdUtil.fastSimpleUUID()) + .setContent(JsonUtils.toJsonString(message.getData())); + deviceLogDataMapper.insert(log); + } + + @Override + public PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { + // TODO @芋艿:增加一个表不存在的 try catch + List list = deviceLogDataMapper.selectPage(pageReqVO); + Long total = deviceLogDataMapper.selectCount(pageReqVO); + return new PageResult<>(list, total); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java index 672785694..828f2fef5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java @@ -1,11 +1,10 @@ -package cn.iocoder.yudao.module.iot.service.device; +package cn.iocoder.yudao.module.iot.service.device.data; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import jakarta.validation.Valid; import java.util.List; @@ -16,7 +15,7 @@ import java.util.Map; * * @author 芋道源码 */ -public interface IotDevicePropertyDataService { +public interface IotDevicePropertyService { /** * 定义设备属性数据的结构 @@ -32,13 +31,6 @@ public interface IotDevicePropertyDataService { */ void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); - /** - * 保存设备数据 - * - * @param thingModelMessage 设备数据 - */ - void saveDeviceDataTest(ThingModelMessage thingModelMessage); - /** * 模拟设备 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java similarity index 81% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index abd788948..741ba70cb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDevicePropertyDataServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -1,9 +1,8 @@ -package cn.iocoder.yudao.module.iot.service.device; +package cn.iocoder.yudao.module.iot.service.device.data; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; @@ -16,18 +15,15 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; -import cn.iocoder.yudao.module.iot.mq.producer.simulatesend.SimulateSendProducer; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; -import cn.iocoder.yudao.module.iot.service.tdengine.IotThingModelMessageService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import jakarta.annotation.Resource; import jakarta.validation.Valid; @@ -53,7 +49,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_C */ @Service @Slf4j -public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataService { +public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { /** * 物模型的数据类型,与 TDengine 数据类型的映射关系 @@ -76,25 +72,16 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe @Resource private IotDeviceService deviceService; @Resource - private IotThingModelMessageService thingModelMessageService; - @Resource private IotThingModelService thingModelService; @Resource private IotProductService productService; - @Resource - private SimulateSendProducer simulateSendProducer; - - @Resource - private TdEngineDMLMapper tdEngineDMLMapper; - @Resource private DeviceDataRedisDAO deviceDataRedisDAO; @Resource private IotDevicePropertyDataMapper devicePropertyDataMapper; - @Override public void defineDevicePropertyData(Long productId) { // 1.1 查询产品和物模型 @@ -144,28 +131,8 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe // 1. 根据产品 key 和设备名称,获得设备信息 IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName()); // 2. 解析消息,保存数据 - JSONObject jsonObject = new JSONObject(createDTO.getParams()); + JSONObject jsonObject = new JSONObject(createDTO.getProperties()); log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject); - ThingModelMessage thingModelMessage = ThingModelMessage.builder() - .id(jsonObject.getStr("id")) - .sys(jsonObject.get("sys")) - .method(jsonObject.getStr("method")) - .params(jsonObject.get("params")) - .time(jsonObject.getLong("time") == null ? System.currentTimeMillis() : jsonObject.getLong("time")) - .productKey(createDTO.getProductKey()) - .deviceName(createDTO.getDeviceName()) - .deviceKey(device.getDeviceKey()) - .build(); - thingModelMessageService.saveThingModelMessage(device, thingModelMessage); - } - - //TODO @芋艿:后续捋一捋这块逻辑,先借鉴一下目前的代码 - @Override - public void saveDeviceDataTest(ThingModelMessage thingModelMessage) { - // 1. 根据产品 key 和设备名称,获得设备信息 - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(thingModelMessage.getProductKey(), thingModelMessage.getDeviceName()); - // 2. 保存数据 - thingModelMessageService.saveThingModelMessage(device, thingModelMessage); } //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 @@ -182,20 +149,17 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe throw exception(DEVICE_DATA_CONTENT_JSON_PARSE_ERROR); } + // TODO @芋艿:后续优化 // 3. 构建物模型消息 - ThingModelMessage thingModelMessage = ThingModelMessage.builder() - .id(IdUtil.fastSimpleUUID()) // TODO:后续优化 - .sys(null)// TODO:这块先写死,后续优化 - .method("thing.event.property.post") // TODO:这块先写死,后续优化 - .params(contentJson) // 将 content 作为 params - .time(simulatorReqVO.getReportTime()) // 使用上报时间 - .productKey(simulatorReqVO.getProductKey()) - .deviceName(device.getDeviceName()) - .deviceKey(device.getDeviceKey()) - .build(); +// IotDeviceMessage thingModelMessage = IotDeviceMessage.builder() +// .params(contentJson) // 将 content 作为 params +// .time(simulatorReqVO.getReportTime()) // 使用上报时间 +// .productKey(simulatorReqVO.getProductKey()) +// .deviceName(device.getDeviceName()) +// .build(); // 4. 发送模拟消息 - simulateSendProducer.sendSimulateMessage(thingModelMessage); +// simulateSendProducer.sendDeviceMessage(thingModelMessage); } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java new file mode 100644 index 000000000..16d387d7b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.service.device.upstream; + +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; + +/** + * 设备上行 Service 接口 + * + * 目的:设备 -> 插件 -> 服务端 + * + * @author 芋道源码 + */ +public interface IotDeviceUpstreamService { + + /** + * 更新设备状态 + * + * @param updateReqDTO 更新设备状态 DTO + */ + void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO); + + /** + * 上报设备属性数据 + * + * @param reportReqDTO 上报设备属性数据 DTO + */ + void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO); + + /** + * 上报设备事件数据 + * + * @param reportReqDTO 设备事件 + */ + void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java new file mode 100644 index 000000000..d930d0ad0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.iot.service.device.upstream; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceUpstreamAbstractReqDTO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDateTime; + +/** + * 设备上行 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { + + @Resource + private IotDeviceService deviceService; + + @Resource + private IotDeviceProducer deviceProducer; + + @Override + public void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { + log.info("[updateDeviceStatus][更新设备状态: {}]", updateReqDTO); + // TODO 芋艿:插件状态 + } + + @Override + public void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { + // 1.1 获得设备 + log.info("[reportDevicePropertyData][上报设备属性数据: {}]", reportReqDTO); + IotDeviceDO device = getDevice(reportReqDTO); + if (device == null) { + log.error("[reportDevicePropertyData][设备({}/{})不存在]", + reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); + return; + } + // 1.2 记录设备的最后时间 + updateDeviceLastTime(device, reportReqDTO); + + // 2. 发送设备消息 + IotDeviceMessage message = BeanUtils.toBean(reportReqDTO, IotDeviceMessage.class) + .setType(IotDeviceMessageTypeEnum.PROPERTY.getType()) + .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier()) + .setData(reportReqDTO.getProperties()); + sendDeviceMessage(message, device); + } + + @Override + public void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { + log.info("[reportDeviceEventData][上报设备事件数据: {}]", reportReqDTO); + + // TODO 芋艿:待实现 + } + + private IotDeviceDO getDevice(IotDeviceUpstreamAbstractReqDTO reqDTO) { + return TenantUtils.executeIgnore(() -> // 需要忽略租户,因为请求时,未带租户编号 + deviceService.getDeviceByProductKeyAndDeviceName(reqDTO.getProductKey(), reqDTO.getDeviceName())); + } + + private void updateDeviceLastTime(IotDeviceDO deviceDO, IotDeviceUpstreamAbstractReqDTO reqDTO) { + // TODO 芋艿:插件状态 + // TODO 芋艿:操作时间 + } + + private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { + // 1. 完善消息 + message.setDeviceKey(device.getDeviceKey()); + if (StrUtil.isEmpty(message.getRequestId())) { + message.setRequestId(IdUtil.fastSimpleUUID()); + } + if (message.getReportTime() == null) { + message.setReportTime(LocalDateTime.now()); + } + + // 2. 发送消息 + try { + deviceProducer.sendDeviceMessage(message); + log.info("[sendDeviceMessage][message({}) 发送消息成功]", message); + } catch (Exception e) { + log.error("[sendDeviceMessage][message({}) 发送消息失败]", message, e); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index ad3ff94e2..3fa0bcf0b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; @@ -35,7 +35,7 @@ public class IotProductServiceImpl implements IotProductService { @Resource @Lazy // 延迟加载,解决循环依赖 - private IotDevicePropertyDataService devicePropertyDataService; + private IotDevicePropertyService devicePropertyDataService; @Override public Long createProduct(IotProductSaveReqVO createReqVO) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java deleted file mode 100644 index 7f52411d8..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageService.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; - -/** - * 物模型消息 Service - */ -public interface IotThingModelMessageService { - - /** - * 保存物模型消息 - * - * @param device 设备 - * @param thingModelMessage 物模型消息 - */ - void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); - - - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java deleted file mode 100644 index c35bb3a28..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/tdengine/IotThingModelMessageServiceImpl.java +++ /dev/null @@ -1,277 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.tdengine; - -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; -import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; -import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; -import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; -import cn.iocoder.yudao.module.iot.enums.IotConstants; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.product.IotProductService; -import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import java.util.*; -import java.util.stream.Collectors; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; - -/** - * 物模型消息 Service 实现类 - */ -@Slf4j -@Service -public class IotThingModelMessageServiceImpl implements IotThingModelMessageService { - - private static final String TAG_NOTE = "TAG"; - private static final String NOTE = "note"; - private static final String TIME = "time"; - private static final String DEVICE_KEY = "device_key"; - private static final String DEVICE_NAME = "device_name"; - private static final String PRODUCT_KEY = "product_key"; - private static final String DEVICE_TYPE = "device_type"; - - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") - private String url; - - @Resource - private IotThingModelService iotThingModelService; - @Resource - private IotDeviceService iotDeviceService; - @Resource - private IotProductService productService; - - @Resource - private TdEngineDDLMapper tdEngineDDLMapper; - @Resource - private TdEngineDMLMapper tdEngineDMLMapper; - - @Resource - private IotDevicePropertyDataMapper iotDevicePropertyDataMapper; - - @Resource - private DeviceDataRedisDAO deviceDataRedisDAO; - - // TODO @haohao:这个方法,可以考虑加下 1. 2. 3. 更有层次感 - @Override - @TenantIgnore - public void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage) { - // 1. 判断设备状态,如果为未激活状态,创建数据表并更新设备状态 - if (IotDeviceStatusEnum.INACTIVE.getStatus().equals(device.getStatus())) { - // 1.1 创建设备表 -// createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); - iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() - .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); - } - - // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 - Map params = thingModelMessage.dataToMap(); - List thingModelList = getValidThingModelList(thingModelMessage.getProductKey()); - if (thingModelList.isEmpty()) { - return; - } - - // 3. 过滤并收集有效的属性字段,缓存设备属性 - List schemaFieldValues = filterAndCollectValidFields(params, thingModelList, device, thingModelMessage.getTime()); - if (schemaFieldValues.size() == 0) { // 没有字段,无需保存 - return; - } - - // 4. 构建并保存设备属性数据 -// tdEngineDMLMapper.insertData(TdTableDO.builder() -// .dataBaseName(getDatabaseName()) -// .tableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())) -// .columns(schemaFieldValues) -// .build()); - // TODO:复用了旧逻辑,先过渡一下 - iotDevicePropertyDataMapper.insertDevicePropertyData(TdTableDO.builder() - .productKey(device.getProductKey()) - .deviceKey(device.getDeviceKey()) - .columns(schemaFieldValues) - .build()); - } - - private List getValidThingModelList(String productKey) { - return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey), - thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); - } - -// @Override -// @TenantIgnore -// public void createSuperTable(Long productId) { -// // 1. 查询产品 -// IotProductDO product = productService.getProduct(productId); -// // 2. 创建日志超级表 -// tdThingModelMessageMapper.createSuperTable(product.getProductKey()); -// -// // 2. 获取超级表的名称和数据库名称 -// // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 -//// String databaseName = IotTdDatabaseUtils.getDatabaseName(url); -//// String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey()); -//// -//// // 解析物模型,获取字段列表 -//// List schemaFields = List.of( -//// TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(), -//// TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(), -//// TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(), -//// TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(), -//// TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build() -//// ); -//// // 设置超级表的标签 -//// List tagsFields = List.of( -//// TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build() -//// ); -//// // 3. 创建超级表 -//// tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); -// } - - private List getValidFunctionList(String productKey) { - return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey), - thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); - } - - private List filterAndCollectValidFields(Map params, List thingModelList, IotDeviceDO device, Long time) { - // 1. 获取属性标识符集合 - Set propertyIdentifiers = convertSet(thingModelList, IotThingModelDO::getIdentifier); - - // 2. 构建属性标识符和属性的映射 - Map thingModelMap = convertMap(thingModelList, IotThingModelDO::getIdentifier); - - // 3. 过滤并收集有效的属性字段 - List schemaFieldValues = new ArrayList<>(); - //TODO:新版本是使用ts字段 -// schemaFieldValues.add(new TdFieldDO(TIME, time)); - params.forEach((key, val) -> { - if (propertyIdentifiers.contains(key)) { - schemaFieldValues.add(new TdFieldDO(key.toLowerCase(), val)); - // 缓存设备属性 - // TODO @haohao:这个缓存的写入,可以使用的时候 cache 么?被动读 - setDeviceDataCache(device, thingModelMap.get(key), val, time); - } - }); - return schemaFieldValues; - } - - /** - * 缓存设备属性 - * - * @param device 设备信息 - * @param iotThingModelDO 物模型属性 - * @param val 属性值 - * @param time 时间 - */ - private void setDeviceDataCache(IotDeviceDO device, IotThingModelDO iotThingModelDO, Object val, Long time) { - IotDeviceDataDO deviceData = IotDeviceDataDO.builder() - .productKey(device.getProductKey()) - .deviceName(device.getDeviceName()) - .identifier(iotThingModelDO.getIdentifier()) - .value(val != null ? val.toString() : null) - .updateTime(DateUtil.toLocalDateTime(new Date(time))) - .deviceId(device.getId()) - .thingModelId(iotThingModelDO.getId()) - .name(iotThingModelDO.getName()) - .dataType(iotThingModelDO.getProperty().getDataType()) - .build(); - deviceDataRedisDAO.set(deviceData); - } - - /** - * 创建设备数据表 - * - * @param deviceType 设备类型 - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @param deviceKey 设备 Key - */ - private void createDeviceTable(Integer deviceType, String productKey, String deviceName, String deviceKey) { - // 1. 获取超级表名和数据库名 - String superTableName = getProductPropertySTableName(deviceType, productKey); - String dataBaseName = getDatabaseName(); - - // 2. 获取超级表的结构信息 - List> maps = tdEngineDDLMapper.describeSuperTable(new TdTableDO(dataBaseName, superTableName)); - List tagsFieldValues = new ArrayList<>(); - if (maps != null) { - // 2.1 过滤出 TAG 类型的字段 - List> taggedNotesList = CollectionUtils.filterList(maps, map -> TAG_NOTE.equals(map.get(NOTE))); - - // 2.2 解析字段信息 - tagsFieldValues = FieldParser.parse(taggedNotesList.stream() - .map(map -> List.of(map.get("field"), map.get("type"), map.get("length"))) - .collect(Collectors.toList())); - - // 2.3 设置 TAG 字段的值 - for (TdFieldDO tagsFieldValue : tagsFieldValues) { - switch (tagsFieldValue.getFieldName()) { - case PRODUCT_KEY -> tagsFieldValue.setFieldValue(productKey); - case DEVICE_KEY -> tagsFieldValue.setFieldValue(deviceKey); - case DEVICE_NAME -> tagsFieldValue.setFieldValue(deviceName); - case DEVICE_TYPE -> tagsFieldValue.setFieldValue(deviceType); - } - } - } - - // 3. 创建设备数据表 - String tableName = getDeviceTableName(productKey, deviceName); - tdEngineDDLMapper.createTable(TdTableDO.builder().build() - .setDataBaseName(dataBaseName) - .setSuperTableName(superTableName) - .setTableName(tableName) - .setTags(tagsFieldValues)); - } - - - - /** - * 获取数据库名称 - * - * @return 数据库名称 - */ - private String getDatabaseName() { - return StrUtil.subAfter(url, "/", true); - } - - /** - * 获取产品属性表名 - * - * @param deviceType 设备类型 - * @param productKey 产品 Key - * @return 产品属性表名 - */ - private static String getProductPropertySTableName(Integer deviceType, String productKey) { - // TODO @haohao:枚举下,会好点哈。 - return switch (deviceType) { - case 1 -> String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); - case 2 -> String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); - default -> String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); - }; - } - - /** - * 获取设备表名 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @return 设备表名 - */ - private static String getDeviceTableName(String productKey, String deviceName) { - return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey.toLowerCase(), deviceName.toLowerCase()); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml index 039180857..bbc1fb718 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml @@ -9,8 +9,9 @@ ts TIMESTAMP, id NCHAR(50), product_key NCHAR(50), + device_name NCHAR(50), type NCHAR(50), - sub_type NCHAR(50), + identifier NCHAR(255), content NCHAR(1024), report_time TIMESTAMP ) TAGS ( @@ -18,18 +19,23 @@ ) + + - INSERT INTO device_log_${log.deviceKey} (ts, id, product_key, type, subType, content, report_time) + INSERT INTO device_log_${deviceKey} (ts, id, product_key, device_name, type, identifier, content, report_time) USING device_log - TAGS ('${log.deviceKey}') + TAGS ('${deviceKey}') VALUES ( NOW, - #{log.id}, - #{log.productKey}, - #{log.type}, - #{log.subType}, - #{log.content}, - #{log.reportTime} + #{id}, + #{productKey}, + #{deviceName}, + #{type}, + #{identifier}, + #{content}, + #{reportTime} ) @@ -51,6 +57,7 @@ LIMIT #{reqVO.pageSize} OFFSET #{reqVO.pageNo} + - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java index 9fdb29ea8..a10e9ec3d 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java @@ -1,99 +1,62 @@ package cn.iocoder.yudao.module.iot.plugin.common.api; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.client.RestTemplate; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -/** - * 用于通过 {@link RestTemplate} 向远程 IoT 服务发送设备数据相关的请求, - * 包括设备状态更新、事件数据上报、属性数据上报等操作。 - */ +// TODO @haohao:类注释,写一下,比较好 +// TODO @haohao:类名要改下 @Slf4j -@RequiredArgsConstructor -public class DeviceDataApiClient implements DeviceDataApi { +public class DeviceDataApiClient implements IotDeviceUpstreamApi { + + public static final String URL_PREFIX = "/rpc-api/iot/device/upstream"; - /** - * 用于发送 HTTP 请求的工具 - */ private final RestTemplate restTemplate; - - /** - * 远程 IoT 服务的基础 URL - * 例如:http://127.0.0.1:8080 - */ private final String deviceDataUrl; + // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 + // TODO @haohao:可以用 lombok 简化 + public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) { + this.restTemplate = restTemplate; + this.deviceDataUrl = deviceDataUrl; + } + // TODO @haohao:返回结果,不用 CommonResult 哈。 @Override public CommonResult updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { - String url = deviceDataUrl + "/rpc-api/iot/device-data/update-status"; + String url = deviceDataUrl + URL_PREFIX + "/update-status"; return doPost(url, updateReqDTO, "updateDeviceStatus"); } @Override public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { - String url = deviceDataUrl + "/rpc-api/iot/device-data/report-event"; + String url = deviceDataUrl + URL_PREFIX + "/report-event"; return doPost(url, reportReqDTO, "reportDeviceEventData"); } @Override public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { - String url = deviceDataUrl + "/rpc-api/iot/device-data/report-property"; + String url = deviceDataUrl + URL_PREFIX + "/report-property"; return doPost(url, reportReqDTO, "reportDevicePropertyData"); } - + // TODO @haohao:未来可能有 get 类型哈 /** - * 发送 GET 请求 - * - * @param 请求体类型 - * @param url 请求 URL - * @param requestBody 请求体 - * @param actionName 操作名称 - * @return 响应结果 - */ - private CommonResult doGet(String url, T requestBody, String actionName) { - log.info("[{}] Sending request to URL: {}", actionName, url); - try { - CommonResult response = restTemplate.getForObject(url, CommonResult.class); - if (response != null && response.isSuccess()) { - return success(true); - } else { - log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response); - return CommonResult.error(500, "Request failed"); - } - } catch (Exception e) { - log.error("[{}] Error sending request to URL: {}", actionName, url, e); - return CommonResult.error(400, "Request error: " + e.getMessage()); - } - } - - /** - * 发送 POST 请求 - * - * @param 请求体类型 - * @param url 请求 URL - * @param requestBody 请求体 - * @param actionName 操作名称 - * @return 响应结果 + * 将与远程服务交互的通用逻辑抽取成一个私有方法 */ private CommonResult doPost(String url, T requestBody, String actionName) { log.info("[{}] Sending request to URL: {}", actionName, url); try { - CommonResult response = restTemplate.postForObject(url, requestBody, CommonResult.class); - if (response != null && response.isSuccess()) { - return success(true); - } else { - log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response); - return CommonResult.error(500, "Request failed"); - } + // 这里指定返回类型为 CommonResult,根据后台服务返回的实际结构做调整 + restTemplate.postForObject(url, requestBody, CommonResult.class); + // TODO @haohao:check 结果,是否成功 + return success(true); } catch (Exception e) { log.error("[{}] Error sending request to URL: {}", actionName, url, e); return CommonResult.error(400, "Request error: " + e.getMessage()); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java index 2c1554474..ef613d5be 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin.common.config; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -43,7 +43,7 @@ public class YudaoDeviceDataApiAutoConfiguration { * @return DeviceDataApi 实例 */ @Bean - public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { + public IotDeviceUpstreamApi deviceDataApi(RestTemplate restTemplate) { return new DeviceDataApiClient(restTemplate, deviceDataUrl); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java index 27b90426b..b5fed5518 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin; import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import lombok.extern.slf4j.Slf4j; import org.pf4j.Plugin; import org.pf4j.PluginWrapper; @@ -27,7 +27,7 @@ public class EmqxPlugin extends Plugin { executorService = Executors.newSingleThreadExecutor(); } - DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); + IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class); if (deviceDataApi == null) { log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); return; diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java index f9a589a24..2c263673a 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; import cn.hutool.core.lang.Assert; import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import lombok.extern.slf4j.Slf4j; import org.pf4j.PluginWrapper; import org.pf4j.spring.SpringPlugin; @@ -64,7 +64,7 @@ public class HttpVertxPlugin extends SpringPlugin { protected void prepareRefresh() { // 在刷新容器前注册主程序中的 Bean ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); - DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); + IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class); beanFactory.registerSingleton("deviceDataApi", deviceDataApi); super.prepareRefresh(); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java index e61a4cf8f..af54d1f53 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler; import io.vertx.core.Vertx; import io.vertx.ext.web.Router; @@ -61,7 +61,7 @@ public class HttpVertxPluginConfiguration { * @return HttpVertxHandler 实例 */ @Bean - public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) { + public HttpVertxHandler httpVertxHandler(IotDeviceUpstreamApi deviceDataApi) { return new HttpVertxHandler(deviceDataApi); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java index df55c68fd..ec4431d2d 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java @@ -2,19 +2,21 @@ package cn.iocoder.yudao.module.iot.plugin.http.service; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import io.vertx.core.Handler; import io.vertx.ext.web.RequestBody; import io.vertx.ext.web.RoutingContext; import lombok.extern.slf4j.Slf4j; +import java.util.Map; + @Slf4j public class HttpVertxHandler implements Handler { - private final DeviceDataApi deviceDataApi; + private final IotDeviceUpstreamApi deviceDataApi; - public HttpVertxHandler(DeviceDataApi deviceDataApi) { + public HttpVertxHandler(IotDeviceUpstreamApi deviceDataApi) { this.deviceDataApi = deviceDataApi; } @@ -23,6 +25,7 @@ public class HttpVertxHandler implements Handler { String productKey = ctx.pathParam("productKey"); String deviceName = ctx.pathParam("deviceName"); + // TODO @haohao:requestBody.asJsonObject() 貌似天然就是 json 对象哈? RequestBody requestBody = ctx.body(); JSONObject jsonData; try { @@ -43,7 +46,7 @@ public class HttpVertxHandler implements Handler { IotDevicePropertyReportReqDTO reportReqDTO = IotDevicePropertyReportReqDTO.builder() .productKey(productKey) .deviceName(deviceName) - .params(jsonData) + .properties((Map) requestBody.asJsonObject().getMap().get("properties")) .build(); deviceDataApi.reportDevicePropertyData(reportReqDTO); From b319485ca60539fd2f343920c3f97d09cd13d8ee Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 27 Jan 2025 14:23:34 +0800 Subject: [PATCH 103/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E6=B8=85=E7=90=86=E9=80=9A?= =?UTF-8?q?=E7=94=A8=20TDengine=20=E5=B0=81=E8=A3=85=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=20SQL=20=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/dataobject/tdengine/FieldParser.java | 85 ---------- .../iot/dal/dataobject/tdengine/SelectDO.java | 48 ------ .../dal/dataobject/tdengine/TagsSelectDO.java | 37 ----- .../dal/dataobject/tdengine/TdFieldDO.java | 49 ------ .../dal/dataobject/tdengine/TdResponse.java | 42 ----- .../dal/dataobject/tdengine/TdRestApi.java | 59 ------- .../dal/dataobject/tdengine/TdTableDO.java | 71 --------- .../tdengine/ThingModelMessageDO.java | 61 -------- .../tdengine/IotDevicePropertyDataMapper.java | 22 --- .../iot/dal/tdengine/TdEngineDDLMapper.java | 147 ------------------ .../iot/dal/tdengine/TdEngineDMLMapper.java | 103 ------------ ...tion.java => TDengineTableInitRunner.java} | 10 +- .../mapper/tdengine/TdEngineDDLMapper.xml | 101 ------------ .../mapper/tdengine/TdEngineDMLMapper.xml | 86 ---------- .../tdengine/TdThinkModelMessageMapper.xml | 35 ----- 15 files changed, 5 insertions(+), 951 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDMLMapper.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/{TDengineTableInitConfiguration.java => TDengineTableInitRunner.java} (74%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDDLMapper.xml delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java deleted file mode 100644 index 2e4e0f507..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/FieldParser.java +++ /dev/null @@ -1,85 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelRespVO; - -import java.util.HashMap; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; - -/** - * FieldParser 类用于解析和转换物模型字段到 TDengine 字段 - */ -public class FieldParser { - - /** - * 物模型到td数据类型映射 - */ - @Deprecated - private static final HashMap TYPE_MAPPING = new HashMap<>() { - { - put("INT", "INT"); - put("FLOAT", "FLOAT"); - put("DOUBLE", "DOUBLE"); - put("BOOL", "BOOL"); - put("ENUM", "NCHAR"); - put("TEXT", "NCHAR"); - put("DATE", "NCHAR"); - } - }; - - /** - * 将物模型字段转换为td字段 - * - * @param property 物模型属性 - * @return TdField对象 - */ - public static TdFieldDO parse(ThingModelProperty property) { - // 将物模型字段类型映射为 td 字段类型 - String fieldName = property.getIdentifier().toLowerCase(); - String fType = TYPE_MAPPING.get(property.getDataType().toUpperCase()); - // 如果字段类型为NCHAR,默认长度为64 - int dataLength = 0; - if ("NCHAR".equals(fType)) { - dataLength = 64; - } - return new TdFieldDO(fieldName, fType, dataLength); - } - - /** - * 从物模型中获取字段列表 - * - * @param thingModel 物模型响应对象 - * @return 字段列表 - */ - public static List parse(ThingModelRespVO thingModel) { - return convertList(thingModel.getModel().getProperties(), FieldParser::parse); - } - - /** - * 将从库中查出来的字段信息转换为 TDengine 字段对象 - * - * @param rows 从库中查出的字段信息列表 - * @return 转换后的 TDengine 字段对象列表 - */ - public static List parse(List> rows) { - return convertList(rows, row -> { - String type = row.get(1).toString().toUpperCase(); - // TODO @puhui999:"NCHAR" 最好枚举下 - int dataLength = "NCHAR".equals(type) ? Integer.parseInt(row.get(2).toString()) : -1; - return new TdFieldDO(row.get(0).toString(), type, dataLength); - }); - } - - /** - * 获取字段字义 - */ - @Deprecated - public static String getFieldDefine(TdFieldDO field) { - return "`" + field.getFieldName() + "`" + " " - + (field.getDataLength() > 0 ? String.format("%s(%d)", field.getDataType(), field.getDataLength()) - : field.getDataType()); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java deleted file mode 100644 index fb4cd459a..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/SelectDO.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import lombok.Data; - -// TODO @haohao:类似这个,其实可以参考 mybatis plus,querywrapper,搞个 TdEngineQueryWrapper。这样看起来会更好懂。 -/** - * 查询DO - */ -@Data -@Deprecated -public class SelectDO { - - // TODO @haoha:database 是个单词 - /** - * 数据库名称 - */ - private String dataBaseName; - - /** - * 超级表名称 - */ - private String tableName; - - /** - * 查询字段 - */ - private String fieldName; - - /** - * 开始时间 - */ - private Long startTime; - - /** - * 结束时间 - */ - private Long endTime; - - /** - * 查询类型 - */ - private String type; - - /** - * 设备ID - */ - private String deviceId; -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java deleted file mode 100644 index 353830824..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TagsSelectDO.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import lombok.Data; - -/** - * tags查询DO - */ -@Data -@Deprecated -public class TagsSelectDO { - - /** - * 数据库名称 - */ - private String dataBaseName; - - /** - * 超级表名称 - */ - private String stableName; - - /** - * tags名称 - */ - private String tagsName; - - /** - * tags值 - */ - private Long startTime; - - /** - * tags值 - */ - private Long endTime; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java deleted file mode 100644 index 10c9b9fe7..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdFieldDO.java +++ /dev/null @@ -1,49 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -// TODO 芋艿:看看是不是后续简化掉。 -/** - * TD 引擎的字段 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@Deprecated -public class TdFieldDO { - - /** - * 字段名称 - */ - private String fieldName; - - /** - * 字段类型 - */ - private String dataType; - - /** - * 字段长度 - */ - private Integer dataLength = 0; - - /** - * 字段值 - */ - private Object fieldValue; - - public TdFieldDO(String fieldName, String dataType, Integer dataLength) { - this.fieldName = fieldName; - this.dataType = dataType; - this.dataLength = dataLength; - } - - public TdFieldDO(String fieldName, Object fieldValue) { - this.fieldName = fieldName; - this.fieldValue = fieldValue; - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java deleted file mode 100644 index 8b64f6854..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdResponse.java +++ /dev/null @@ -1,42 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -/** - * TdResponse 类用于处理 TDengine 的响应 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -@Deprecated -public class TdResponse { - - public static final int CODE_SUCCESS = 0; - public static final int CODE_TB_NOT_EXIST = 866; - - /** - * 状态 - */ - private String status; - - /** - * 错误码 - */ - private int code; - - /** - * 错误信息 - */ - private String desc; - - /** - * 列信息 - * [["time","TIMESTAMP",8,""],["powerstate","TINYINT",1,""],["brightness","INT",4,""],["deviceid","NCHAR",32,"TAG"]] - */ - private List data; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java deleted file mode 100644 index 1bb793a45..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdRestApi.java +++ /dev/null @@ -1,59 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import cn.hutool.http.HttpRequest; -import cn.hutool.http.HttpResponse; -import cn.hutool.json.JSONUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -// TODO @haohao:有部分非实体的部分,是不是可以搞到 iot 的 framework 包下,搞个 tdengine 包,作为框架级的封装,放在 dataobject,感觉不是很合理哈。【可以微信讨论下】 -/** - * TdRestApi 类用于处理 TDengine 的 REST API 请求 - */ -@Slf4j -@Service -@Deprecated // TODO 芋艿:貌似没用到 -public class TdRestApi { - - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") - private String url; - - @Value("${spring.datasource.dynamic.datasource.tdengine.username}") - private String username; - - @Value("${spring.datasource.dynamic.datasource.tdengine.password}") - private String password; - - /** - * 获取 REST API URL - */ - private String getRestApiUrl() { - String restUrl = url.replace("jdbc:TAOS-RS://", "") - .replaceAll("\\?.*", ""); - int idx = restUrl.lastIndexOf("/"); - return String.format("%s/rest/sql/%s", restUrl.substring(0, idx), restUrl.substring(idx + 1)); - } - - - /** - * 新建td api请求对象 - */ - public HttpRequest newApiRequest(String sql) { - return HttpRequest - .post(getRestApiUrl()) - .body(sql) - .basicAuth(username, password); - } - - /** - * 执行sql - */ - public TdResponse execSql(String sql) { - log.info("exec td sql:{}", sql); - HttpRequest request = newApiRequest(sql); - HttpResponse response = request.execute(); - return JSONUtil.toBean(response.body(), TdResponse.class); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java deleted file mode 100644 index 104be2683..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/TdTableDO.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Deprecated -/** - * TD 引擎的数据库 - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class TdTableDO { - - /** - * 数据库名称 - */ - private String dataBaseName; - - // TODO @haohao:superTableName 和 tableName 是不是合并。因为每个 mapper 操作的时候,有且只会使用到其中一个。 - /** - * 超级表名称 - */ - private String superTableName; - - /** - * 表名称 - */ - private String tableName; - - private String productKey; - - private String deviceKey; - - /** - * COLUMN 字段 - */ - private TdFieldDO column; - - /** - * TAG 字段 - */ - private TdFieldDO tag; - - /** - * COLUMN 字段 - 列表 - */ - private List columns; - - /** - * TAG 字段 - 列表 - */ - private List tags; - - public TdTableDO(String dataBaseName, String superTableName, List columns, List tags) { - this.dataBaseName = dataBaseName; - this.superTableName = superTableName; - this.columns = columns; - this.tags = tags; - } - - public TdTableDO(String dataBaseName, String superTableName) { - this.dataBaseName = dataBaseName; - this.superTableName = superTableName; - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java deleted file mode 100644 index ae70da37b..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/tdengine/ThingModelMessageDO.java +++ /dev/null @@ -1,61 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.tdengine; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -// TODO @芋艿:纠结下字段 -@Deprecated // TODO @super:看看啥时候删除下哈。 -/** - * TD 物模型消息日志的数据库 - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class ThingModelMessageDO { - - - - /** - * 消息 ID - */ - private String id; - - /** - * 系统扩展参数 - * - * 例如:设备状态、系统时间、固件版本等系统级信息 - */ - private Object system; - - /** - * 请求方法 - * - * 例如:thing.event.property.post - */ - private String method; - - /** - * 请求参数 - */ - private Object params; - - /** - * 属性上报时间戳 - */ - private Long time; - - /** - * 设备信息 - */ - private String productKey; - - - /** - * 设备 key - */ - private String deviceKey; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java index 1599ce957..42b5e01eb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; @@ -78,27 +77,6 @@ public interface IotDevicePropertyDataMapper { void alterProductPropertySTableDropField(@Param("productKey") String productKey, @Param("field") TDengineTableField field); - //TODO:先参考一下老逻辑,后续改进 - /** - * 插入数据 - 指定列插入数据 - * - * @param table 数据 - * productKey 产品 key - * deviceKey 设备 key - * columns 列 - */ - void insertDevicePropertyData(TdTableDO table); - - //TODO:先参考一下老逻辑,后续改进 - /** - * 查看超级表 - 获取超级表的结构信息 - * SQL:DESCRIBE [db_name.]stb_name; - * - * @param superTable 超级表信息 - * productKey 产品 key - */ - List> describeSuperTable(TdTableDO superTable); - /** * 获取历史数据列表 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java deleted file mode 100644 index eeb061cc5..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDDLMapper.java +++ /dev/null @@ -1,147 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.tdengine; - -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import com.baomidou.dynamic.datasource.annotation.DS; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.util.List; -import java.util.Map; - -/** - * 专门处理 DDL(数据定义语言)操作,包含所有的数据库和表的定义操作,例如创建数据库、创建超级表、创建子表等 - */ -@Mapper -@DS("tdengine") -public interface TdEngineDDLMapper { - - /** - * 创建数据库 - * SQL:CREATE DATABASE [IF NOT EXISTS] db_name [database_options]; - * - * @param dataBaseName 数据库名称 - */ - @TenantIgnore - void createDatabase(@Param("dataBaseName") String dataBaseName); - - /** - * 创建超级表 - * SQL:CREATE STABLE [IF NOT EXISTS] stb_name (create_definition [, create_definition] ...) TAGS (create_definition [, create_definition] ...) [table_options]; - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * columns 列信息 - * tags 标签信息 - */ - @TenantIgnore - void createSuperTable(TdTableDO superTable); - - /** - * 查看超级表 - 显示当前数据库下的所有超级表信息 - * SQL:SHOW STABLES [LIKE tb_name_wildcard]; - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - */ - @TenantIgnore - List> showSuperTables(TdTableDO superTable); - - /** - * 查看超级表 - 获取超级表的结构信息 - * SQL:DESCRIBE [db_name.]stb_name; - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - */ - @TenantIgnore - List> describeSuperTable(TdTableDO superTable); - - /** - * 修改超级表 - 增加列 - * SQL:ALTER STABLE stb_name ADD COLUMN col_name column_type; - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * column 列信息 - */ - @TenantIgnore - void addColumnForSuperTable(TdTableDO superTable); - - /** - * 修改超级表 - 删除列 - * SQL:ALTER STABLE stb_name DROP COLUMN col_name; - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * column 列信息 - */ - @TenantIgnore - void dropColumnForSuperTable(TdTableDO superTable); - - /** - * 修改超级表 - 修改列宽 - * SQL:ALTER STABLE stb_name MODIFY COLUMN col_name data_type(length); - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * column 列信息 - */ - @TenantIgnore - void modifyColumnWidthForSuperTable(TdTableDO superTable); - - /** - * 修改超级表 - 为超级表添加标签 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * tag 标签信息 - */ - @TenantIgnore - void addTagForSuperTable(TdTableDO superTable); - - /** - * 修改超级表 - 为超级表删除标签 - * - * @param superTable 超级表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * tag 标签信息 - */ - @TenantIgnore - void dropTagForSuperTable(TdTableDO superTable); - - /** - * 创建子表 - 创建子表 - * SQL:CREATE TABLE [IF NOT EXISTS] tb_name USING stb_name TAGS (tag_value1, ...); - * - * @param table 表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * tableName 子表名称 - * tags TAG 字段 - */ - @TenantIgnore - void createTable(TdTableDO table); - - /** - * 创建子表 - 创建子表并指定标签的值 - * SQL:CREATE TABLE [IF NOT EXISTS] tb_name USING stb_name (tag_name1, ...) TAGS (tag_value1, ...); - * - * @param table 表信息 - * dataBaseName 数据库名称 - * superTableName 超级表名称 - * tableName 子表名称 - * tags TAG 字段 - */ - @TenantIgnore - void createTableWithTags(TdTableDO table); - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDMLMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDMLMapper.java deleted file mode 100644 index 12b2c232c..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/TdEngineDMLMapper.java +++ /dev/null @@ -1,103 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.tdengine; - -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TagsSelectDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; -import com.baomidou.dynamic.datasource.annotation.DS; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; -import java.util.Map; - -/** - * 专门处理 TD Engine 的 DML(数据操作语言)操作,处理所有的数据查询和写入操作,如插入数据、查询数据等 - */ -@Mapper -@DS("tdengine") -public interface TdEngineDMLMapper { - - /** - * 插入数据 - 指定列插入数据 - * - * @param table 数据 - * dataBaseName 数据库名 - * tableName 表名 - * columns 列 - */ - @TenantIgnore - void insertData(TdTableDO table); - - /** - * 根据时间戳查询数据 - * - * @param selectDO 查询条件 - * @return 查询结果列表 - */ - @TenantIgnore - List> selectByTimestamp(SelectDO selectDO); - - /** - * 根据时间戳获取数据条数 - * - * @param selectDO 查询条件 - * @return 数据条数 - */ - @TenantIgnore - Map selectCountByTimestamp(SelectDO selectDO); - - /** - * 获取最新数据 - * - * @param selectDO 查询条件 - * @return 最新数据 - */ - @TenantIgnore - Map selectOneLastData(SelectDO selectDO); - - /** - * 获取历史数据列表 - * - * @param selectVisualDO 查询条件 - * @return 历史数据列表 - */ - @TenantIgnore - List> selectHistoryDataList(SelectVisualDO selectVisualDO); - - /** - * 获取实时数据列表 - * - * @param selectVisualDO 查询条件 - * @return 实时数据列表 - */ - @TenantIgnore - List> selectRealtimeDataList(SelectVisualDO selectVisualDO); - - /** - * 获取聚合数据列表 - * - * @param selectVisualDO 查询条件 - * @return 聚合数据列表 - */ - @TenantIgnore - List> selectAggregateDataList(SelectVisualDO selectVisualDO); - - /** - * 根据标签获取最新数据列表 - * - * @param tagsSelectDO 查询条件 - * @return 最新数据列表 - */ - @TenantIgnore - List> selectLastDataListByTags(TagsSelectDO tagsSelectDO); - - /** - * 获取历史数据条数 - * - * @param selectVisualDO 查询条件 - * @return 数据条数 - */ - @TenantIgnore - Long selectHistoryCount(SelectVisualDO selectVisualDO); -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitRunner.java similarity index 74% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitRunner.java index 3e84ac11c..3517e1e58 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitRunner.java @@ -5,17 +5,17 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; -import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; /** * TDengine 表初始化的 Configuration * * @author alwayssuper */ -@Configuration -@Slf4j +@Component @RequiredArgsConstructor -public class TDengineTableInitConfiguration implements ApplicationRunner { +@Slf4j +public class TDengineTableInitRunner implements ApplicationRunner { private final IotDeviceLogService deviceLogService; @@ -26,7 +26,7 @@ public class TDengineTableInitConfiguration implements ApplicationRunner { deviceLogService.defineDeviceLog(); } catch (Exception ex) { // 初始化失败时打印错误日志并退出系统 - log.error("[TDengine] 初始化设备日志表结构失败,系统无法正常运行,即将退出", ex); + log.error("[run][TDengine初始化设备日志表结构失败,系统无法正常运行,即将退出]", ex); System.exit(1); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDDLMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDDLMapper.xml deleted file mode 100644 index 091b77f64..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDDLMapper.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - CREATE DATABASE IF NOT EXISTS ${dataBaseName} - - - - - CREATE STABLE IF NOT EXISTS ${dataBaseName}.${superTableName} - - ${item.fieldName} ${item.dataType} - - (${item.dataLength}) - - - TAGS - - ${item.fieldName} ${item.dataType} - - (${item.dataLength}) - - - - - - - - - - - - - ALTER STABLE ${dataBaseName}.${superTableName} ADD COLUMN ${column.fieldName} ${column.dataType} - - (${column.dataLength}) - - - - - - ALTER STABLE ${dataBaseName}.${superTableName} DROP COLUMN ${column.fieldName} - - - - - ALTER STABLE ${dataBaseName}.${superTableName} MODIFY COLUMN ${column.fieldName} ${column.dataType} - - (${column.dataLength}) - - - - - - ALTER STABLE ${dataBaseName}.${superTableName} ADD TAG ${tag.fieldName} ${tag.dataType} - - (${tag.dataLength}) - - - - - - ALTER STABLE ${dataBaseName}.${superTableName} DROP TAG ${tag.fieldName} - - - - - CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} - USING ${dataBaseName}.${superTableName} - TAGS - - #{item.fieldValue} - - - - - - CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} - USING ${dataBaseName}.${superTableName} - - #{item.fieldName} - - TAGS - - #{item.fieldValue} - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml deleted file mode 100644 index b4084374c..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdEngineDMLMapper.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - INSERT INTO ${dataBaseName}.${tableName} - - ${item.fieldName} - - VALUES - - #{item.fieldValue} - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml deleted file mode 100644 index 474bb7c54..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/tdengine/TdThinkModelMessageMapper.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - CREATE STABLE thing_model_message_${productKey}( - ts TIMESTAMP, - id NCHAR(64), - sys NCHAR(2048), - method NCHAR(255), - params NCHAR(2048), - device_name NCHAR(64) - )TAGS ( - device_key NCHAR(50) - ) - - - - - CREATE STABLE ${deviceKey} - USING thing_model_message_${productKey}( - ts, - id , - sys , - method , - params , - device_name - )TAGS( - #{device_key} - ) - - \ No newline at end of file From 8e80a53a8bb37fe40f9a1d1ee5f243ce0f7b1ed5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 27 Jan 2025 16:50:10 +0800 Subject: [PATCH 104/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E9=83=A8=E5=88=86=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20IotDevicePropertyMessageConsumer=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=BC=93=E5=AD=98=E7=9A=84=E8=AE=B0=E5=BD=95=EF=BC=88?= =?UTF-8?q?=E5=B7=AE=E8=AE=BE=E5=A4=87=E5=B1=9E=E6=80=A7=E7=9A=84=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=AE=B0=E5=BD=95=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceDataController.java | 8 +- .../dataobject/device/IotDeviceDataDO.java | 82 --------- .../device/IotDevicePropertyDO.java | 35 ++++ .../iot/dal/redis/RedisKeyConstants.java | 19 +- .../redis/device/DevicePropertyRedisDAO.java | 54 ++++++ .../device/DeviceReportTimeRedisDAO.java | 27 +++ .../redis/deviceData/DeviceDataRedisDAO.java | 43 ----- .../tdengine/IotDevicePropertyDataMapper.java | 1 + .../iot/emq/service/EmqxServiceImpl.java | 2 +- .../IotDevicePropertyMessageConsumer.java | 12 +- .../iot/service/device/IotDeviceService.java | 1 + .../service/device/IotDeviceServiceImpl.java | 2 - .../device/data/IotDevicePropertyService.java | 10 +- .../data/IotDevicePropertyServiceImpl.java | 163 ++++++++++-------- .../thingmodel/IotThingModelService.java | 1 + 15 files changed, 245 insertions(+), 215 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDevicePropertyDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 15366cf9c..8012ec2ec 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; @@ -28,18 +28,14 @@ public class IotDeviceDataController { @Resource private IotDevicePropertyService deviceDataService; - @Resource - private IotDeviceLogService iotDeviceLogDataService; - - @Resource // TODO @super:service 之间,不用空行;原因是,这样更简洁;空行,主要是为了“间隔”,提升可读性 private IotDeviceLogService deviceLogDataService; // TODO @浩浩:这里的 /latest-list,包括方法名。 @GetMapping("/latest") @Operation(summary = "获取设备属性最新数据") public CommonResult> getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { - List list = deviceDataService.getLatestDeviceProperties(deviceDataReqVO); + List list = deviceDataService.getLatestDeviceProperties(deviceDataReqVO); return success(BeanUtils.toBean(list, IotDeviceDataRespVO.class)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java deleted file mode 100644 index 63b732d20..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDataDO.java +++ /dev/null @@ -1,82 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.device; - -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; - -/** - * IoT 设备数据 DO - * - * @author haohao - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class IotDeviceDataDO { - - /** - * 设备编号 - *

- * 关联 {@link IotDeviceDO#getId()} - */ - private Long deviceId; - - /** - * 物模型编号 - *

- * 关联 {@link IotThingModelDO#getId()} - */ - private Long thingModelId; - - /** - * 产品标识 - *

- * 关联 {@link IotProductDO#getProductKey()} - */ - private String productKey; - - /** - * 设备名称 - *

- * 冗余 {@link IotDeviceDO#getDeviceName()} - */ - private String deviceName; - - /** - * 属性标识符 - *

- * 关联 {@link IotThingModelDO#getIdentifier()} - */ - private String identifier; - - /** - * 属性名称 - *

- * 关联 {@link IotThingModelDO#getName()} - */ - private String name; - - /** - * 数据类型 - *

- * 关联 {@link IotThingModelDO#getProperty()#getDataType()} - */ - private String dataType; - - /** - * 更新时间 - */ - private LocalDateTime updateTime; - - /** - * 最新值 - */ - private String value; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDevicePropertyDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDevicePropertyDO.java new file mode 100644 index 000000000..afb328894 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDevicePropertyDO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.device; + +import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * IoT 设备属性项 Redis DO + * + * @see cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants#DEVICE_PROPERTY + * @see DevicePropertyRedisDAO + * + * @author haohao + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotDevicePropertyDO { + + /** + * 属性值(最新) + */ + private Object value; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java index 25ea7a292..04858248f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.redis; - +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; /** * Iot Redis Key 枚举类 @@ -10,11 +10,20 @@ package cn.iocoder.yudao.module.iot.dal.redis; public interface RedisKeyConstants { /** - * 设备属性数据缓存 + * 设备属性数据缓存,采用 HASH 结构 *

- * KEY 格式:device_property_data:{deviceId} - * VALUE 数据类型:String 设备属性数据 + * KEY 格式:device_property:{deviceKey} + * HASH KEY:identifier 属性标识 + * VALUE 数据类型:String(JSON) {@link IotDevicePropertyDO} */ - String DEVICE_PROPERTY_DATA = "device_property_data:%s_%s_%s"; + String DEVICE_PROPERTY = "device_property:%s"; + + /** + * 设备的最后上报时间,采用 ZSET 结构 + * + * KEY 格式:{deviceKey} + * SCORE:上报时间 + */ + String DEVICE_REPORT_TIME = "device_report_time"; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java new file mode 100644 index 000000000..fa25b8472 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.dal.redis.device; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import java.util.Collections; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants.DEVICE_PROPERTY; + +/** + * {@link IotDevicePropertyDO} 的 Redis DAO + */ +@Repository +public class DevicePropertyRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public Map get(String deviceKey) { + String redisKey = formatKey(deviceKey); + Map entries = stringRedisTemplate.opsForHash().entries(redisKey); + if (CollUtil.isEmpty(entries)) { + return Collections.emptyMap(); + } + return convertMap(entries.values(), key -> (String) key, + value -> JsonUtils.parseObject((String) value, IotDevicePropertyDO.class)); + } + + public void set(String deviceKey, Map properties) { + if (CollUtil.isEmpty(properties)) { + return; + } + String redisKey = formatKey(deviceKey); + stringRedisTemplate.opsForHash().putAll(redisKey, convertMap(properties.entrySet(), + Map.Entry::getKey, + entry -> JsonUtils.toJsonString(entry.getValue()))); + } + + public void delete(String deviceKey) { + String redisKey = formatKey(deviceKey); + stringRedisTemplate.delete(redisKey); + } + + private static String formatKey(String deviceKey) { + return String.format(DEVICE_PROPERTY, deviceKey); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java new file mode 100644 index 000000000..35c99a06e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.dal.redis.device; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import java.time.LocalDateTime; + +/** + * 设备的最后上报时间的 Redis DAO + * + * @author 芋道源码 + */ +@Repository +public class DeviceReportTimeRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public void update(String deviceKey, LocalDateTime reportTime) { + stringRedisTemplate.opsForZSet().add(RedisKeyConstants.DEVICE_REPORT_TIME, deviceKey, + LocalDateTimeUtil.toEpochMilli(reportTime)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java deleted file mode 100644 index b1b69f8dc..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/deviceData/DeviceDataRedisDAO.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.redis.deviceData; - -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; -import jakarta.annotation.Resource; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.stereotype.Repository; - -import java.util.Collection; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import static cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants.DEVICE_PROPERTY_DATA; - -/** - * {@link IotDeviceDataDO} 的 Redis DAO - */ -@Repository -public class DeviceDataRedisDAO { - - @Resource - private StringRedisTemplate stringRedisTemplate; - - public IotDeviceDataDO get(String productKey, String deviceName, String identifier) { - String redisKey = formatKey(productKey, deviceName, identifier); - return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), IotDeviceDataDO.class); - } - - public void set(IotDeviceDataDO deviceData) { - String redisKey = formatKey(deviceData.getProductKey(), deviceData.getDeviceName(), deviceData.getIdentifier()); - stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(deviceData)); - } - - public void delete(String productKey, String deviceName, String identifier) { - String redisKey = formatKey(productKey, deviceName, identifier); - stringRedisTemplate.delete(redisKey); - } - - private static String formatKey(String productKey, String deviceName, String identifier) { - return String.format(DEVICE_PROPERTY_DATA, productKey, deviceName, identifier); - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java index 42b5e01eb..e8df639c2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java @@ -77,6 +77,7 @@ public interface IotDevicePropertyDataMapper { void alterProductPropertySTableDropField(@Param("productKey") String productKey, @Param("field") TDengineTableField field); + // TODO @芋艿:待实现 /** * 获取历史数据列表 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index ca9a6bac7..6d45b9be9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -39,7 +39,7 @@ public class EmqxServiceImpl implements EmqxService { // .deviceName(deviceName) // .properties(message) // TODO 芋艿:临时去掉,看看 .build(); - iotDeviceDataService.saveDeviceData(createDTO); +// iotDeviceDataService.saveDeviceProperty(createDTO); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java index 63b4c9a5e..3f7fe1089 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.iot.mq.consumer.device; +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import lombok.extern.slf4j.Slf4j; @@ -24,11 +27,14 @@ public class IotDevicePropertyMessageConsumer { @EventListener @Async public void onMessage(IotDeviceMessage message) { + if (ObjectUtil.notEqual(message.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType()) + || ObjectUtil.notEqual(message.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier())) { + return; + } log.info("[onMessage][消息内容({})]", message); - // 设备日志记录 - // TODO @芋艿:重新写下 -// deviceLogDataService.createDeviceLog(message); + // 保存设备属性 + deviceDataService.saveDeviceProperty(message); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index adf3304d0..f01460a1b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -113,6 +113,7 @@ public interface IotDeviceService { */ Long getDeviceCountByGroupId(Long groupId); + // TODO @芋艿:增加缓存 /** * 根据产品 key 和设备名称,获得设备信息 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 6a28b27f3..683570916 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -247,7 +246,6 @@ public class IotDeviceServiceImpl implements IotDeviceService { } @Override - @TenantIgnore public IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName) { return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java index 828f2fef5..b5fce2bc1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java @@ -1,10 +1,10 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import jakarta.validation.Valid; import java.util.List; @@ -27,9 +27,9 @@ public interface IotDevicePropertyService { /** * 保存设备数据 * - * @param createDTO 设备数据 + * @param message 设备消息 */ - void saveDeviceData(IotDevicePropertyReportReqDTO createDTO); + void saveDeviceProperty(IotDeviceMessage message); /** * 模拟设备 @@ -44,7 +44,7 @@ public interface IotDevicePropertyService { * @param deviceId 设备编号 * @return 设备属性最新数据 */ - List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceId); + List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceId); /** * 获得设备属性历史数据 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index 741ba70cb..61355e02d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -1,27 +1,26 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.DateUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; -import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; +import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; @@ -31,15 +30,13 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.time.ZoneId; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_CONTENT_JSON_PARSE_ERROR; /** @@ -77,7 +74,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { private IotProductService productService; @Resource - private DeviceDataRedisDAO deviceDataRedisDAO; + private DevicePropertyRedisDAO deviceDataRedisDAO; @Resource private IotDevicePropertyDataMapper devicePropertyDataMapper; @@ -126,13 +123,41 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } @Override - public void saveDeviceData(IotDevicePropertyReportReqDTO createDTO) { - // TODO 芋艿:这块需要实现 - // 1. 根据产品 key 和设备名称,获得设备信息 - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(createDTO.getProductKey(), createDTO.getDeviceName()); - // 2. 解析消息,保存数据 - JSONObject jsonObject = new JSONObject(createDTO.getProperties()); - log.info("[saveDeviceData][productKey({}) deviceName({}) data({})]", createDTO.getProductKey(), createDTO.getDeviceName(), jsonObject); + public void saveDeviceProperty(IotDeviceMessage message) { + if (!(message.getData() instanceof Map)) { + log.error("[saveDeviceProperty][消息内容({}) 的 data 类型不正确]", message); + return; + } + // 1. 获得设备信息 + IotDeviceDO device = TenantUtils.executeIgnore(() -> + deviceService.getDeviceByProductKeyAndDeviceName(message.getProductKey(), message.getDeviceName())); + if (device == null) { + log.error("[saveDeviceProperty][消息({}) 对应的设备不存在]", message); + return; + } + + // 2. 根据物模型,拼接合法的属性 + List thingModels = TenantUtils.executeIgnore(() -> + thingModelService.getThingModelListByProductId(device.getProductId())); + Map properties = new HashMap<>(); + ((Map) message.getData()).forEach((key, value) -> { + if (CollUtil.findOne(thingModels, thingModel -> thingModel.getIdentifier().equals(key)) == null) { + log.error("[saveDeviceProperty][消息({}) 的属性({}) 不存在]", message, key); + return; + } + properties.put((String) key, value); + }); + if (CollUtil.isEmpty(properties)) { + log.error("[saveDeviceProperty][消息({}) 没有合法的属性]", message); + return; + } + + // 3.1 保存属性【数据】 + // TODO 芋艿,未实现 + + // 3.2 保存属性【日志】 + deviceDataRedisDAO.set(message.getDeviceKey(), convertMap(properties.entrySet(), Map.Entry::getKey, + entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build())); } //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 @@ -163,62 +188,64 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } @Override - public List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { - List list = new ArrayList<>(); - // 1. 获取设备信息 - IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); - // 2. 获取设备属性最新数据 - List thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey()); - thingModelList = filterList(thingModelList, thingModel -> IotThingModelTypeEnum.PROPERTY.getType() - .equals(thingModel.getType())); - - // 3. 过滤标识符和属性名称 - if (deviceDataReqVO.getIdentifier() != null) { - thingModelList = filterList(thingModelList, thingModel -> thingModel.getIdentifier() - .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())); - } - if (deviceDataReqVO.getName() != null) { - thingModelList = filterList(thingModelList, thingModel -> thingModel.getName() - .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())); - } - // 4. 获取设备属性最新数据 - thingModelList.forEach(thingModel -> { - IotDeviceDataDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thingModel.getIdentifier()); - if (deviceData == null) { - deviceData = new IotDeviceDataDO(); - deviceData.setProductKey(device.getProductKey()); - deviceData.setDeviceName(device.getDeviceName()); - deviceData.setIdentifier(thingModel.getIdentifier()); - deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); - deviceData.setThingModelId(thingModel.getId()); - deviceData.setName(thingModel.getName()); - deviceData.setDataType(thingModel.getProperty().getDataType()); - } - list.add(deviceData); - }); - return list; + public List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { +// List list = new ArrayList<>(); +// // 1. 获取设备信息 +// IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); +// // 2. 获取设备属性最新数据 +// List thingModelList = thingModelService.getProductThingModelListByProductKey(device.getProductKey()); +// thingModelList = filterList(thingModelList, thingModel -> IotThingModelTypeEnum.PROPERTY.getType() +// .equals(thingModel.getType())); +// +// // 3. 过滤标识符和属性名称 +// if (deviceDataReqVO.getIdentifier() != null) { +// thingModelList = filterList(thingModelList, thingModel -> thingModel.getIdentifier() +// .toLowerCase().contains(deviceDataReqVO.getIdentifier().toLowerCase())); +// } +// if (deviceDataReqVO.getName() != null) { +// thingModelList = filterList(thingModelList, thingModel -> thingModel.getName() +// .toLowerCase().contains(deviceDataReqVO.getName().toLowerCase())); +// } +// // 4. 获取设备属性最新数据 +// thingModelList.forEach(thingModel -> { +// IotDevicePropertyDO deviceData = deviceDataRedisDAO.get(device.getProductKey(), device.getDeviceName(), thingModel.getIdentifier()); +// if (deviceData == null) { +// deviceData = new IotDevicePropertyDO(); +// deviceData.setProductKey(device.getProductKey()); +// deviceData.setDeviceName(device.getDeviceName()); +// deviceData.setIdentifier(thingModel.getIdentifier()); +// deviceData.setDeviceId(deviceDataReqVO.getDeviceId()); +// deviceData.setThingModelId(thingModel.getId()); +// deviceData.setName(thingModel.getName()); +// deviceData.setDataType(thingModel.getProperty().getDataType()); +// } +// list.add(deviceData); +// }); +// return list; + return null; // TODO 芋艿:晚点实现 } @Override public PageResult> getHistoryDeviceProperties(IotDeviceDataPageReqVO deviceDataReqVO) { - PageResult> pageResult = new PageResult<>(); - // 1. 获取设备信息 - IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); - // 2. 获取设备属性历史数据 - SelectVisualDO selectVisualDO = new SelectVisualDO(); - selectVisualDO.setDataBaseName(getDatabaseName()); - selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); - selectVisualDO.setDeviceKey(device.getDeviceKey()); - selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier()); - selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); - selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); - Map params = new HashMap<>(); - params.put("rows", deviceDataReqVO.getPageSize()); - params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); - selectVisualDO.setParams(params); - pageResult.setList(devicePropertyDataMapper.selectHistoryDataList(selectVisualDO)); - pageResult.setTotal(devicePropertyDataMapper.selectHistoryCount(selectVisualDO)); - return pageResult; +// PageResult> pageResult = new PageResult<>(); +// // 1. 获取设备信息 +// IotDeviceDO device = deviceService.getDevice(deviceDataReqVO.getDeviceId()); +// // 2. 获取设备属性历史数据 +// SelectVisualDO selectVisualDO = new SelectVisualDO(); +// selectVisualDO.setDataBaseName(getDatabaseName()); +// selectVisualDO.setTableName(getDeviceTableName(device.getProductKey(), device.getDeviceName())); +// selectVisualDO.setDeviceKey(device.getDeviceKey()); +// selectVisualDO.setFieldName(deviceDataReqVO.getIdentifier()); +// selectVisualDO.setStartTime(DateUtil.date(deviceDataReqVO.getTimes()[0].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); +// selectVisualDO.setEndTime(DateUtil.date(deviceDataReqVO.getTimes()[1].atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()).getTime()); +// Map params = new HashMap<>(); +// params.put("rows", deviceDataReqVO.getPageSize()); +// params.put("page", (deviceDataReqVO.getPageNo() - 1) * deviceDataReqVO.getPageSize()); +// selectVisualDO.setParams(params); +// pageResult.setList(devicePropertyDataMapper.selectHistoryDataList(selectVisualDO)); +// pageResult.setTotal(devicePropertyDataMapper.selectHistoryCount(selectVisualDO)); +// return pageResult; + return null; // TODO 芋艿:晚点实现 } private String getDatabaseName() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java index d68b3429e..71d47a53f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java @@ -46,6 +46,7 @@ public interface IotThingModelService { */ IotThingModelDO getThingModel(Long id); + // TODO @芋艿:增加缓存 /** * 获得产品物模型列表 * From 043d82e5b6e88c3533974a62911dd7dab796ff07 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 27 Jan 2025 17:10:59 +0800 Subject: [PATCH 105/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E5=AE=8C=E6=95=B4=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20saveDeviceProperty=20=E7=9A=84=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E6=97=A5=E5=BF=97=E7=9A=84=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tdengine/IotDevicePropertyDataMapper.java | 4 +++ .../data/IotDevicePropertyServiceImpl.java | 34 ++++++++----------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java index e8df639c2..11a3207d1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; @@ -77,6 +78,9 @@ public interface IotDevicePropertyDataMapper { void alterProductPropertySTableDropField(@Param("productKey") String productKey, @Param("field") TDengineTableField field); + void insert(@Param("device") IotDeviceDO device, + @Param("properties") Map properties); + // TODO @芋艿:待实现 /** * 获取历史数据列表 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index 61355e02d..acf42d7af 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; @@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; -import cn.iocoder.yudao.module.iot.enums.IotConstants; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; @@ -27,7 +26,6 @@ import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.ArrayList; @@ -63,9 +61,6 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { .put(IotDataSpecsDataTypeEnum.ARRAY.getDataType(), TDengineTableField.TYPE_NCHAR) // TODO 芋艿:怎么映射!!!! .build(); - @Value("${spring.datasource.dynamic.datasource.tdengine.url}") - private String url; - @Resource private IotDeviceService deviceService; @Resource @@ -123,22 +118,21 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } @Override + @TenantIgnore // TODO @芋艿:租户的缓存问题,需要考虑下。因为会存在一会又 tenantId,一会没有! public void saveDeviceProperty(IotDeviceMessage message) { if (!(message.getData() instanceof Map)) { log.error("[saveDeviceProperty][消息内容({}) 的 data 类型不正确]", message); return; } // 1. 获得设备信息 - IotDeviceDO device = TenantUtils.executeIgnore(() -> - deviceService.getDeviceByProductKeyAndDeviceName(message.getProductKey(), message.getDeviceName())); + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(message.getProductKey(), message.getDeviceName()); if (device == null) { log.error("[saveDeviceProperty][消息({}) 对应的设备不存在]", message); return; } // 2. 根据物模型,拼接合法的属性 - List thingModels = TenantUtils.executeIgnore(() -> - thingModelService.getThingModelListByProductId(device.getProductId())); + List thingModels = thingModelService.getThingModelListByProductId(device.getProductId()); Map properties = new HashMap<>(); ((Map) message.getData()).forEach((key, value) -> { if (CollUtil.findOne(thingModels, thingModel -> thingModel.getIdentifier().equals(key)) == null) { @@ -152,10 +146,10 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { return; } - // 3.1 保存属性【数据】 - // TODO 芋艿,未实现 + // 3.1 保存设备属性【数据】 + devicePropertyDataMapper.insert(device, properties); - // 3.2 保存属性【日志】 + // 3.2 保存设备属性【日志】 deviceDataRedisDAO.set(message.getDeviceKey(), convertMap(properties.entrySet(), Map.Entry::getKey, entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build())); } @@ -248,12 +242,12 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { return null; // TODO 芋艿:晚点实现 } - private String getDatabaseName() { - return StrUtil.subAfter(url, "/", true); - } - - private static String getDeviceTableName(String productKey, String deviceName) { - return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey, deviceName); - } +// private String getDatabaseName() { +// return StrUtil.subAfter(url, "/", true); +// } +// +// private static String getDeviceTableName(String productKey, String deviceName) { +// return String.format(IotConstants.DEVICE_TABLE_NAME_FORMAT, productKey, deviceName); +// } } \ No newline at end of file From 7745035fa4d43bced70a8ea96b35711ac624ea01 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 27 Jan 2025 21:32:33 +0800 Subject: [PATCH 106/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E6=97=A5=E5=BF=97=E8=A1=A8=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=20report=5Ftime=20=E4=B8=8A=E6=8A=A5=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tdengine/IotDevicePropertyDataMapper.java | 8 +++-- .../tdengine/core/TDengineTableField.java | 5 --- .../data/IotDevicePropertyServiceImpl.java | 5 +-- .../device/IotDevicePropertyDataMapper.xml | 32 +++++++++++-------- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java index 11a3207d1..ac212cac4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.SelectVisualDO; @@ -30,8 +31,8 @@ public interface IotDevicePropertyDataMapper { default void alterProductPropertySTable(String productKey, List oldFields, List newFields) { - oldFields.removeIf(field -> TDengineTableField.FIELD_TS.equals(field.getField()) - || TDengineTableField.FIELD_DEVICE_KEY.equals(field.getField())); + oldFields.removeIf(field -> StrUtil.equalsAny(field.getField(), + TDengineTableField.FIELD_TS, "device_key", "report_time")); List addFields = newFields.stream().filter( // 新增的字段 newField -> oldFields.stream().noneMatch(oldField -> oldField.getField().equals(newField.getField()))) .collect(Collectors.toList()); @@ -79,7 +80,8 @@ public interface IotDevicePropertyDataMapper { @Param("field") TDengineTableField field); void insert(@Param("device") IotDeviceDO device, - @Param("properties") Map properties); + @Param("properties") Map properties, + @Param("reportTime") Long reportTime); // TODO @芋艿:待实现 /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java index 427c68189..e3bbdd204 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java @@ -17,11 +17,6 @@ public class TDengineTableField { */ public static final String FIELD_TS = "ts"; - /** - * 字段名 - 我们系统定义的 device_key 字段,非 TDengine 默认字段 - */ - public static final String FIELD_DEVICE_KEY = "device_key"; - public static final String TYPE_TINYINT = "TINYINT"; public static final String TYPE_INT = "INT"; public static final String TYPE_FLOAT = "FLOAT"; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index acf42d7af..fba2fd6f3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; @@ -97,7 +98,6 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { log.info("[defineDevicePropertyData][productId({}) 没有需要定义的属性]", productId); return; } - newFields.add(0, new TDengineTableField(TDengineTableField.FIELD_TS, TDengineTableField.TYPE_TIMESTAMP)); devicePropertyDataMapper.createProductPropertySTable(product.getProductKey(), newFields); return; } @@ -147,7 +147,8 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } // 3.1 保存设备属性【数据】 - devicePropertyDataMapper.insert(device, properties); + devicePropertyDataMapper.insert(device, properties, + LocalDateTimeUtil.toEpochMilli(message.getReportTime())); // TODO @芋艿:后续要看看,查询的时候,能不能用 LocalDateTime // 3.2 保存设备属性【日志】 deviceDataRedisDAO.set(message.getDeviceKey(), convertMap(properties.entrySet(), Map.Entry::getKey, diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml index 3ac238d75..21d1ed16e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml @@ -9,13 +9,16 @@ - CREATE STABLE product_property_${productKey} - + CREATE STABLE product_property_${productKey} ( + ts TIMESTAMP, + report_time TIMESTAMP, + ${field.field} ${field.type} (${field.length}) + ) TAGS ( device_key NCHAR(50) ) @@ -42,19 +45,20 @@ DROP COLUMN ${field.field} - - INSERT INTO device_property_${deviceKey} - USING product_property_${productKey} - TAGS ('${deviceKey}') - (ts - - ,${item.fieldName} + + + INSERT INTO device_property_${device.deviceKey} + USING product_property_${device.productKey} + TAGS ('${device.deviceKey}') + (ts, report_time, + + ${key} - ) - VALUES - (NOW - - ,#{item.fieldValue} + ) + VALUES + (NOW, #{reportTime}, + + #{value} ) From a364153d4a9a34375151d8527a5ad54ed60f6c22 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 27 Jan 2025 22:23:31 +0800 Subject: [PATCH 107/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9Adevice=20=E5=92=8C=20thingmodel?= =?UTF-8?q?=20=E8=AF=BB=E5=8F=96=E5=A2=9E=E5=8A=A0=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mysql/thingmodel/IotThingModelMapper.java | 8 ++-- .../iot/dal/redis/RedisKeyConstants.java | 18 +++++++- .../iot/service/device/IotDeviceService.java | 7 +-- .../service/device/IotDeviceServiceImpl.java | 43 ++++++++++++++++++- .../data/IotDevicePropertyServiceImpl.java | 6 +-- .../IotDeviceUpstreamServiceImpl.java | 9 +--- .../thingmodel/IotThingModelService.java | 19 ++++---- .../thingmodel/IotThingModelServiceImpl.java | 37 ++++++++++++++-- 8 files changed, 115 insertions(+), 32 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java index 1258893c5..4c563c65e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java @@ -49,6 +49,10 @@ public interface IotThingModelMapper extends BaseMapperX { return selectList(IotThingModelDO::getProductId, productId); } + default List selectListByProductKey(String productKey) { + return selectList(IotThingModelDO::getProductKey, productKey); + } + default List selectListByProductIdAndType(Long productId, Integer type) { return selectList(IotThingModelDO::getProductId, productId, IotThingModelDO::getType, type); @@ -68,8 +72,4 @@ public interface IotThingModelMapper extends BaseMapperX { IotThingModelDO::getName, name); } - default List selectListByProductKey(String productKey) { - return selectList(IotThingModelDO::getProductKey, productKey); - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java index 04858248f..d7096b55d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -10,7 +10,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; public interface RedisKeyConstants { /** - * 设备属性数据缓存,采用 HASH 结构 + * 设备属性的数据缓存,采用 HASH 结构 *

* KEY 格式:device_property:{deviceKey} * HASH KEY:identifier 属性标识 @@ -26,4 +26,20 @@ public interface RedisKeyConstants { */ String DEVICE_REPORT_TIME = "device_report_time"; + /** + * 设备信息的数据缓存,使用 Spring Cache 操作 + * + * KEY 格式:device_${productKey}_${deviceKey} + * VALUE 数据类型:String(JSON) + */ + String DEVICE = "device"; + + /** + * 物模型的数据缓存,使用 Spring Cache 操作 + * + * KEY 格式:thing_model_${productKey} + * VALUE 数据类型:String 数组(JSON),即 {@link cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO} 列表 + */ + String THING_MODEL_LIST = "thing_model_list"; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index f01460a1b..3efc4054f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -113,15 +113,16 @@ public interface IotDeviceService { */ Long getDeviceCountByGroupId(Long groupId); - // TODO @芋艿:增加缓存 /** - * 根据产品 key 和设备名称,获得设备信息 + * 【缓存】根据产品 key 和设备名称,获得设备信息 + * + * 注意:该方法会忽略租户信息,所以调用时,需要确认会不会有跨租户访问的风险!!! * * @param productKey 产品 key * @param deviceName 设备名称 * @return 设备信息 */ - IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName); + IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache(String productKey, String deviceName); /** * 导入设备 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 683570916..786e8e0ef 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -4,22 +4,27 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; +import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -78,6 +83,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds()); // 2.1 转换 VO 为 DO + // TODO @芋艿:state 相关的参数。另外,到底叫 state,还是 status 好! IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class, o -> { o.setProductKey(product.getProductKey()).setDeviceType(product.getDeviceType()); // 生成并设置必要的字段 @@ -109,6 +115,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 2. 更新到数据库 IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); deviceMapper.updateById(updateObj); + + // 3. 清空对应缓存 + deleteDeviceCache(device); } @Override @@ -125,6 +134,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 3. 更新设备分组 deviceMapper.updateBatch(convertList(devices, device -> new IotDeviceDO() .setId(device.getId()).setGroupIds(updateReqVO.getGroupIds()))); + + // 4. 清空对应缓存 + deleteDeviceCache(devices); } @Override @@ -138,6 +150,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 2. 删除设备 deviceMapper.deleteById(id); + + // 3. 清空对应缓存 + deleteDeviceCache(device); } @Override @@ -160,6 +175,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 2. 删除设备 deviceMapper.deleteByIds(ids); + + // 3. 清空对应缓存 + deleteDeviceCache(devices); } /** @@ -213,6 +231,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { @Override public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) { + // TODO @芋艿:state 相关的参数。另外,到底叫 state,还是 status 好! + // TODO @芋艿:各种时间,需要 check 下,优化处理下! // 1. 校验存在 IotDeviceDO device = validateDeviceExists(updateReqVO.getId()); @@ -233,6 +253,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { } // 2.3 更新到数据库 deviceMapper.updateById(updateDevice); + + // 3. 清空对应缓存 + deleteDeviceCache(device); } @Override @@ -246,7 +269,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { } @Override - public IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName) { + @TenantIgnore + @Cacheable(value = RedisKeyConstants.DEVICE, key = "#productKey + '_' + #deviceName", unless = "#result == null") + public IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); } @@ -367,4 +392,20 @@ public class IotDeviceServiceImpl implements IotDeviceService { return respVO; } + private void deleteDeviceCache(IotDeviceDO device) { + // 保证在 @CacheEvict 之前,忽略租户 + TenantUtils.executeIgnore(() -> getSelf().deleteDeviceCache0(device)); + } + + private void deleteDeviceCache(List devices) { + devices.forEach(this::deleteDeviceCache); + } + + @CacheEvict(value = RedisKeyConstants.DEVICE, key = "#device.productKey + '_' + #device.deviceName") + public void deleteDeviceCache0(IotDeviceDO device) {} + + private IotDeviceServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index fba2fd6f3..3f4c90b24 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -118,21 +118,21 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } @Override - @TenantIgnore // TODO @芋艿:租户的缓存问题,需要考虑下。因为会存在一会又 tenantId,一会没有! + @TenantIgnore public void saveDeviceProperty(IotDeviceMessage message) { if (!(message.getData() instanceof Map)) { log.error("[saveDeviceProperty][消息内容({}) 的 data 类型不正确]", message); return; } // 1. 获得设备信息 - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceName(message.getProductKey(), message.getDeviceName()); + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(message.getProductKey(), message.getDeviceName()); if (device == null) { log.error("[saveDeviceProperty][消息({}) 对应的设备不存在]", message); return; } // 2. 根据物模型,拼接合法的属性 - List thingModels = thingModelService.getThingModelListByProductId(device.getProductId()); + List thingModels = thingModelService.getThingModelListByProductKeyFromCache(device.getProductKey()); Map properties = new HashMap<>(); ((Map) message.getData()).forEach((key, value) -> { if (CollUtil.findOne(thingModels, thingModel -> thingModel.getIdentifier().equals(key)) == null) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java index d930d0ad0..4a456406c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.service.device.upstream; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; @@ -47,7 +46,8 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { public void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { // 1.1 获得设备 log.info("[reportDevicePropertyData][上报设备属性数据: {}]", reportReqDTO); - IotDeviceDO device = getDevice(reportReqDTO); + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( + reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); if (device == null) { log.error("[reportDevicePropertyData][设备({}/{})不存在]", reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); @@ -71,11 +71,6 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { // TODO 芋艿:待实现 } - private IotDeviceDO getDevice(IotDeviceUpstreamAbstractReqDTO reqDTO) { - return TenantUtils.executeIgnore(() -> // 需要忽略租户,因为请求时,未带租户编号 - deviceService.getDeviceByProductKeyAndDeviceName(reqDTO.getProductKey(), reqDTO.getDeviceName())); - } - private void updateDeviceLastTime(IotDeviceDO deviceDO, IotDeviceUpstreamAbstractReqDTO reqDTO) { // TODO 芋艿:插件状态 // TODO 芋艿:操作时间 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java index 71d47a53f..cc81e5f02 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java @@ -46,7 +46,6 @@ public interface IotThingModelService { */ IotThingModelDO getThingModel(Long id); - // TODO @芋艿:增加缓存 /** * 获得产品物模型列表 * @@ -55,6 +54,16 @@ public interface IotThingModelService { */ List getThingModelListByProductId(Long productId); + /** + * 【缓存】获得产品物模型列表 + * + * 注意:该方法会忽略租户信息,所以调用时,需要确认会不会有跨租户访问的风险!!! + * + * @param productKey 产品标识 + * @return 产品物模型列表 + */ + List getThingModelListByProductKeyFromCache(String productKey); + /** * 获得产品物模型分页 * @@ -63,14 +72,6 @@ public interface IotThingModelService { */ PageResult getProductThingModelPage(IotThingModelPageReqVO pageReqVO); - /** - * 获得产品物模型列表 - * - * @param productKey 产品 Key - * @return 产品物模型列表 - */ - List getProductThingModelListByProductKey(String productKey); - /** * 获得产品物模型列表 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index f0ce947d5..5c9f5fd05 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -2,8 +2,11 @@ package cn.iocoder.yudao.module.iot.service.thingmodel; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelParam; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; @@ -14,11 +17,14 @@ import cn.iocoder.yudao.module.iot.convert.thingmodel.IotThingModelConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotThingModelMapper; +import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.*; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -69,6 +75,9 @@ public class IotThingModelServiceImpl implements IotThingModelService { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } // TODO @puhui999: 服务和事件的情况 method 怎么设置?在前端设置还是后端设置? + + // 7. 删除缓存 + deleteThingModelListCache(createReqVO.getProductKey()); return thingModel.getId(); } @@ -92,6 +101,9 @@ public class IotThingModelServiceImpl implements IotThingModelService { if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } + + // 6. 删除缓存 + deleteThingModelListCache(updateReqVO.getProductKey()); } @Override @@ -113,6 +125,9 @@ public class IotThingModelServiceImpl implements IotThingModelService { if (Objects.equals(thingModel.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey()); } + + // 4. 删除缓存 + deleteThingModelListCache(thingModel.getProductKey()); } @Override @@ -126,13 +141,15 @@ public class IotThingModelServiceImpl implements IotThingModelService { } @Override - public PageResult getProductThingModelPage(IotThingModelPageReqVO pageReqVO) { - return thingModelMapper.selectPage(pageReqVO); + @TenantIgnore + @Cacheable(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey") + public List getThingModelListByProductKeyFromCache(String productKey) { + return thingModelMapper.selectListByProductKey(productKey); } @Override - public List getProductThingModelListByProductKey(String productKey) { - return thingModelMapper.selectListByProductKey(productKey); + public PageResult getProductThingModelPage(IotThingModelPageReqVO pageReqVO) { + return thingModelMapper.selectPage(pageReqVO); } @Override @@ -333,4 +350,16 @@ public class IotThingModelServiceImpl implements IotThingModelService { .setDirection(direction.getDirection())); } + private void deleteThingModelListCache(String productKey) { + // 保证在 @CacheEvict 之前,忽略租户 + TenantUtils.executeIgnore(() -> getSelf().deleteThingModelListCache0(productKey)); + } + + @CacheEvict(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey") + public void deleteThingModelListCache0(String productKey) {} + + private IotThingModelServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + } From eb2d4fdbc06b6416cfd73bd138b2fecba927ae74 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 28 Jan 2025 03:58:24 +0800 Subject: [PATCH 108/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E5=90=8C=E6=AD=A5=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/plugin/IotPluginDeployTypeEnum.java | 8 ++++---- .../module/iot/enums/plugin/IotPluginStatusEnum.java | 8 ++++---- .../yudao/module/iot/enums/plugin/IotPluginTypeEnum.java | 8 ++++---- .../module/iot/enums/product/IotProductStatusEnum.java | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java index 11f8a6ef8..acbc99239 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.enums.plugin; -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.Getter; import java.util.Arrays; @@ -11,12 +11,12 @@ import java.util.Arrays; * @author haohao */ @Getter -public enum IotPluginDeployTypeEnum implements IntArrayValuable { +public enum IotPluginDeployTypeEnum implements ArrayValuable { JAR(0, "JAR 部署"), STANDALONE(1, "独立部署"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginDeployTypeEnum::getDeployType).toArray(); + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginDeployTypeEnum::getDeployType).toArray(Integer[]::new); /** * 部署方式 @@ -45,7 +45,7 @@ public enum IotPluginDeployTypeEnum implements IntArrayValuable { } @Override - public int[] array() { + public Integer[] array() { return ARRAYS; } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java index aee2fbe0f..9b187c5b6 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.enums.plugin; -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.Getter; import java.util.Arrays; @@ -11,12 +11,12 @@ import java.util.Arrays; * @author haohao */ @Getter -public enum IotPluginStatusEnum implements IntArrayValuable { +public enum IotPluginStatusEnum implements ArrayValuable { STOPPED(0, "停止"), RUNNING(1, "运行"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginStatusEnum::getStatus).toArray(); + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginStatusEnum::getStatus).toArray(Integer[]::new); /** * 状态 @@ -41,7 +41,7 @@ public enum IotPluginStatusEnum implements IntArrayValuable { } @Override - public int[] array() { + public Integer[] array() { return ARRAYS; } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java index 8b9cef2b4..0f81d5a8f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.enums.plugin; -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; @@ -13,12 +13,12 @@ import java.util.Arrays; */ @AllArgsConstructor @Getter -public enum IotPluginTypeEnum implements IntArrayValuable { +public enum IotPluginTypeEnum implements ArrayValuable { NORMAL(0, "普通插件"), DEVICE(1, "设备插件"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginTypeEnum::getType).toArray(); + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginTypeEnum::getType).toArray(Integer[]::new); /** * 类型 @@ -31,7 +31,7 @@ public enum IotPluginTypeEnum implements IntArrayValuable { private final String name; @Override - public int[] array() { + public Integer[] array() { return ARRAYS; } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java index 452290671..ee8be5c81 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java @@ -18,7 +18,7 @@ public enum IotProductStatusEnum implements ArrayValuable { UNPUBLISHED(0, "开发中"), PUBLISHED(1, "已发布"); - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProductStatusEnum::getType).toArray(Integer[]::new); + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProductStatusEnum::getStatus).toArray(Integer[]::new); /** * 类型 From 5fbfe49305425ced4fc318daa9f37b6bcfa67507 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 28 Jan 2025 04:56:03 +0800 Subject: [PATCH 109/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91Bpm=EF=BC=9A=E8=AE=BE=E5=A4=87=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E4=B8=8A=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/api/device/IotDeviceUpstreamApi.java | 4 +- .../module/iot/enums/ErrorCodeConstants.java | 1 - .../device/IotDeviceMessageTypeEnum.java | 12 ++++- .../api/device/IoTDeviceUpstreamApiImpl.java | 8 +-- .../admin/device/IotDeviceController.java | 8 +++ .../admin/device/IotDeviceDataController.java | 16 ++---- .../IotDeviceSimulationReportReqVO.java | 30 +++++++++++ .../IotDeviceDataSimulatorSaveReqVO.java | 44 ---------------- .../plugin/UnifiedConfiguration.java | 6 ++- .../iot/service/device/IotDeviceService.java | 14 +++--- .../service/device/IotDeviceServiceImpl.java | 37 ++++++++++++++ .../device/data/IotDevicePropertyService.java | 8 --- .../data/IotDevicePropertyServiceImpl.java | 32 ------------ .../upstream/IotDeviceUpstreamService.java | 4 +- .../IotDeviceUpstreamServiceImpl.java | 4 +- .../common/api/DeviceDataApiClient.java | 4 +- .../plugin/http/service/HttpVertxHandler.java | 2 +- .../src/main/resources/application-local.yaml | 50 ++++++++++++------- 18 files changed, 147 insertions(+), 137 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSimulationReportReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java index 996ff1f5a..a7c28b8cb 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java @@ -35,7 +35,7 @@ public interface IotDeviceUpstreamApi { * @param reportReqDTO 上报设备属性数据 DTO */ @PostMapping(PREFIX + "/report-property") - CommonResult reportDevicePropertyData(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO); + CommonResult reportDeviceProperty(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO); /** * 上报设备事件数据 @@ -43,6 +43,6 @@ public interface IotDeviceUpstreamApi { * @param reportReqDTO 设备事件 */ @PostMapping(PREFIX + "/report-event") - CommonResult reportDeviceEventData(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO); + CommonResult reportDeviceEvent(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 305aa6c7f..4539f1259 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -30,7 +30,6 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在"); ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备"); ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!"); - ErrorCode DEVICE_DATA_CONTENT_JSON_PARSE_ERROR = new ErrorCode(1_050_003_007, "导入设备数据格式错误!"); // ========== 产品分类 1-050-004-000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在"); diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java index b3f00e860..20140ead2 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java @@ -1,22 +1,32 @@ package cn.iocoder.yudao.module.iot.enums.device; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.Getter; import lombok.RequiredArgsConstructor; +import java.util.Arrays; + /** * IoT 设备消息类型枚举 */ @Getter @RequiredArgsConstructor -public enum IotDeviceMessageTypeEnum { +public enum IotDeviceMessageTypeEnum implements ArrayValuable { STATE("state"), // 设备状态 PROPERTY("property"), // 设备属性 EVENT("event"); // 设备事件 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new); + /** * 属性 */ private final String type; + @Override + public String[] array() { + return ARRAYS; + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java index 0e6df1480..3ee3ec6a4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java @@ -29,14 +29,14 @@ public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi { } @Override - public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { - deviceUpstreamService.reportDevicePropertyData(reportReqDTO); + public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { + deviceUpstreamService.reportDeviceProperty(reportReqDTO); return success(true); } @Override - public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { - deviceUpstreamService.reportDeviceEventData(reportReqDTO); + public CommonResult reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { + deviceUpstreamService.reportDeviceEvent(reportReqDTO); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index e0c214bc1..5080881ac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -159,4 +159,12 @@ public class IotDeviceController { ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list); } + @PostMapping("/simulation-report") + @Operation(summary = "模拟设备上报") + @PreAuthorize("@ss.hasPermission('iot:device:simulation-report')") + public CommonResult simulationReportDevice(@Valid @RequestBody IotDeviceSimulationReportReqVO simulatorReqVO) { + deviceService.simulationReportDevice(simulatorReqVO); + return success(true); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 8012ec2ec..6c2ea7a2d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import io.swagger.v3.oas.annotations.Operation; @@ -13,7 +13,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; @@ -47,16 +49,6 @@ public class IotDeviceDataController { return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); } - // TODO:功能权限 - @PostMapping("/simulator") - @Operation(summary = "模拟设备") - public CommonResult simulatorDevice(@Valid @RequestBody IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { - //TODO:先使用 IotDeviceDataSimulatorSaveReqVO 另外content里数据类型的效验前端也没做,后端应该要要效验一下,这块后续看看怎么安排 - // TODO @super:应该 deviceDataService 里面有个 simulatorDevice,然后里面去 insert 日志! - deviceDataService.simulatorSend(simulatorReqVO); - return success(true); - } - // TODO:功能权限 @GetMapping("/log/page") @Operation(summary = "获得设备日志分页") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSimulationReportReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSimulationReportReqVO.java new file mode 100644 index 000000000..aea4f9077 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSimulationReportReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 模拟设备上报 Request VO") // 属性上报、事件上报、状态变更等 +@Data +public class IotDeviceSimulationReportReqVO { + + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @NotNull(message = "设备编号不能为空") + private Long id; + + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property") + @NotEmpty(message = "消息类型不能为空") + @InEnum(IotDeviceMessageTypeEnum.class) + private String type; + + @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report") + @NotEmpty(message = "标识符不能为空") + private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类 + + @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED) + private Object data; // 例如说:属性上报的 properties、事件上报的 params + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java deleted file mode 100644 index efa608e57..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceDataSimulatorSaveReqVO.java +++ /dev/null @@ -1,44 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; - -// TODO super: SaveReqVO => ReqVO -@Schema(description = "管理后台 - IoT 模拟设备数据 Request VO") -@Data -public class IotDeviceDataSimulatorSaveReqVO { - - // TODO @super:感觉后端随机更合适? - @Schema(description = "消息 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "msg123") - private String id; - - // TODO @super:不用传递 productKey,因为 deviceKey 可以推导出来 - // TODO 讨论: 日志记录的时候要记录一下productKey,目前是前端已经有productKey了,所以前端传入,如果不传入的话,后端要根据deviceKey查询productKey,感觉直传是不是效率高一些 - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123") - @NotEmpty(message = "产品标识不能为空") - private String productKey; - - @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123") - @NotEmpty(message = "设备标识不能为空") - private String deviceKey; - - // TODO @super:type、subType,是不是不用传递,因为模拟只有属性??? - // TODO 讨论: 不只模拟属性 - @Schema(description = "消息/日志类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property") - @NotEmpty(message = "消息类型不能为空") - private String type; - - @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature") - @NotEmpty(message = "标识符不能为空") - private String subType; - - @Schema(description = "数据内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "{\"value\": 25.6}") - @NotEmpty(message = "数据内容不能为空") - private String content; - - // TODO @芋艿:需要讨论下,reportTime 到底以那个为准! - @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED) - private Long reportTime; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index e27d9b5fb..150051ce5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.nio.file.Paths; + // TODO @芋艿:需要 review 下 @Slf4j @Configuration @@ -19,8 +21,8 @@ public class UnifiedConfiguration { // @DependsOn("deviceDataApiImpl") public SpringPluginManager pluginManager() { log.info("[init][实例化 SpringPluginManager]"); -// SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { - SpringPluginManager springPluginManager = new SpringPluginManager() { + SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { +// SpringPluginManager springPluginManager = new SpringPluginManager() { @Override public void startPlugins() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 3efc4054f..b5d690e51 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -1,13 +1,8 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceUpdateGroupReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceImportRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceImportExcelVO; import jakarta.validation.Valid; import javax.annotation.Nullable; @@ -133,4 +128,11 @@ public interface IotDeviceService { */ IotDeviceImportRespVO importDevice(List importDevices, boolean updateSupport); + /** + * 模拟设备上报 + * + * @param reportReqVO 上报信息 + */ + void simulationReportDevice(IotDeviceSimulationReportReqVO reportReqVO); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 786e8e0ef..879908071 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -11,14 +11,17 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; +import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; import jakarta.validation.ConstraintViolationException; @@ -56,6 +59,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { @Resource @Lazy // 延迟加载,解决循环依赖 private IotDeviceGroupService deviceGroupService; + @Resource + @Lazy // 延迟加载,解决循环依赖 + private IotDeviceUpstreamService deviceUpstreamService; @Override public Long createDevice(IotDeviceSaveReqVO createReqVO) { @@ -84,6 +90,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 2.1 转换 VO 为 DO // TODO @芋艿:state 相关的参数。另外,到底叫 state,还是 status 好! + // TODO @芋艿:各种 mqtt 是不是可以简化! IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class, o -> { o.setProductKey(product.getProductKey()).setDeviceType(product.getDeviceType()); // 生成并设置必要的字段 @@ -392,6 +399,36 @@ public class IotDeviceServiceImpl implements IotDeviceService { return respVO; } + @Override + @SuppressWarnings("unchecked") + public void simulationReportDevice(IotDeviceSimulationReportReqVO reportReqVO) { + // 1. 校验存在 + IotDeviceDO device = validateDeviceExists(reportReqVO.getId()); + + // 2.1 情况一:属性上报 + String requestId = IdUtil.fastSimpleUUID(); + if (Objects.equals(reportReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) { + deviceUpstreamService.reportDeviceProperty(IotDevicePropertyReportReqDTO.builder() + .requestId(requestId).reportTime(LocalDateTime.now()) + .productKey(device.getProductKey()).deviceName(device.getDeviceName()) + .properties((Map) reportReqVO.getData()).build()); + return; + } + // 2.2 情况二:事件上报 + if (Objects.equals(reportReqVO.getType(), IotDeviceMessageTypeEnum.EVENT.getType())) { + // TODO 芋艿:待实现 + return; + } + // 2.3 情况三:状态变更 + if (Objects.equals(reportReqVO.getType(), IotDeviceMessageTypeEnum.STATE.getType())) { + // TODO 芋艿:待实现 + updateDeviceStatus(new IotDeviceStatusUpdateReqVO().setId(device.getId()) + .setStatus((Integer) reportReqVO.getData())); + return; + } + throw new IllegalArgumentException("未知的类型:" + reportReqVO.getType()); + } + private void deleteDeviceCache(IotDeviceDO device) { // 保证在 @CacheEvict 之前,忽略租户 TenantUtils.executeIgnore(() -> getSelf().deleteDeviceCache0(device)); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java index b5fce2bc1..fbbc292cf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import jakarta.validation.Valid; @@ -31,13 +30,6 @@ public interface IotDevicePropertyService { */ void saveDeviceProperty(IotDeviceMessage message); - /** - * 模拟设备 - * - * @param simulatorReqVO 设备数据 - */ - void simulatorSend(IotDeviceDataSimulatorSaveReqVO simulatorReqVO); - /** * 获得设备属性最新数据 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index 3f4c90b24..0aa438b13 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -4,12 +4,9 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; @@ -34,9 +31,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DATA_CONTENT_JSON_PARSE_ERROR; /** * IoT 设备【属性】数据 Service 实现类 @@ -155,33 +150,6 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build())); } - //TODO @芋艿:copy 了 saveDeviceData 的逻辑,后续看看这块怎么优化 - @Override - public void simulatorSend(IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { - // 1. 根据设备 key ,获得设备信息 - IotDeviceDO device = deviceService.getDeviceByDeviceKey(simulatorReqVO.getDeviceKey()); - - // 2. 解析 content 为 JSON 对象 - JSONObject contentJson; - try { - contentJson = JSONUtil.parseObj(simulatorReqVO.getContent()); - } catch (Exception e) { - throw exception(DEVICE_DATA_CONTENT_JSON_PARSE_ERROR); - } - - // TODO @芋艿:后续优化 - // 3. 构建物模型消息 -// IotDeviceMessage thingModelMessage = IotDeviceMessage.builder() -// .params(contentJson) // 将 content 作为 params -// .time(simulatorReqVO.getReportTime()) // 使用上报时间 -// .productKey(simulatorReqVO.getProductKey()) -// .deviceName(device.getDeviceName()) -// .build(); - - // 4. 发送模拟消息 -// simulateSendProducer.sendDeviceMessage(thingModelMessage); - } - @Override public List getLatestDeviceProperties(@Valid IotDeviceDataPageReqVO deviceDataReqVO) { // List list = new ArrayList<>(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java index 16d387d7b..12fd8a949 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java @@ -25,13 +25,13 @@ public interface IotDeviceUpstreamService { * * @param reportReqDTO 上报设备属性数据 DTO */ - void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO); + void reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO); /** * 上报设备事件数据 * * @param reportReqDTO 设备事件 */ - void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO); + void reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java index 4a456406c..adfb1f83f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java @@ -43,7 +43,7 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { } @Override - public void reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { + public void reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { // 1.1 获得设备 log.info("[reportDevicePropertyData][上报设备属性数据: {}]", reportReqDTO); IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( @@ -65,7 +65,7 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { } @Override - public void reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { + public void reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { log.info("[reportDeviceEventData][上报设备事件数据: {}]", reportReqDTO); // TODO 芋艿:待实现 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java index a10e9ec3d..ee68bf034 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java @@ -35,13 +35,13 @@ public class DeviceDataApiClient implements IotDeviceUpstreamApi { } @Override - public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { + public CommonResult reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { String url = deviceDataUrl + URL_PREFIX + "/report-event"; return doPost(url, reportReqDTO, "reportDeviceEventData"); } @Override - public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { + public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { String url = deviceDataUrl + URL_PREFIX + "/report-property"; return doPost(url, reportReqDTO, "reportDevicePropertyData"); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java index ec4431d2d..4ac85c220 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java @@ -49,7 +49,7 @@ public class HttpVertxHandler implements Handler { .properties((Map) requestBody.asJsonObject().getMap().get("properties")) .build(); - deviceDataApi.reportDevicePropertyData(reportReqDTO); + deviceDataApi.reportDeviceProperty(reportReqDTO); ctx.response() .setStatusCode(200) diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index d3fb42b06..bbb94772c 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -45,16 +45,16 @@ spring: primary: master datasource: master: - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 - # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 + url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 连接的示例 # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 - username: root - password: 123456 + username: ruoyi-vue-pro + password: ruoyi-@h2ju02hebp # username: sa # SQL Server 连接的示例 # password: Yudao@2024 # SQL Server 连接的示例 # username: SYSDBA # DM 连接的示例 @@ -63,17 +63,25 @@ spring: # password: Yudao@2024 # OpenGauss 连接的示例 slave: # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true + url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: ruoyi-vue-pro + password: ruoyi-@h2ju02hebp + tdengine: # IOT 数据库 + # lazy: true # 开启懒加载,保证启动速度 + url: jdbc:TAOS-RS://chaojiniu.top:6041/ruoyi_vue_pro + driver-class-name: com.taosdata.jdbc.rs.RestfulDriver username: root - password: 123456 + password: taosdata + druid: + validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: redis: host: 127.0.0.1 # 地址 port: 6379 # 端口 - database: 0 # 数据库索引 -# password: dev # 密码,建议生产环境开启 + database: 1 # 数据库索引 + # password: 123456 # 密码,建议生产环境开启 --- #################### 定时任务相关配置 #################### @@ -175,20 +183,22 @@ logging: cn.iocoder.yudao.module.crm.dal.mysql: debug cn.iocoder.yudao.module.erp.dal.mysql: debug cn.iocoder.yudao.module.iot.dal.mysql: debug + cn.iocoder.yudao.module.iot.dal.tdengine: DEBUG cn.iocoder.yudao.module.ai.dal.mysql: debug org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 + com.taosdata: DEBUG # TDengine 的日志级别 debug: false --- #################### 微信公众号、小程序相关配置 #################### wx: mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档 - # app-id: wx041349c6f39b268b # 测试号(牛希尧提供的) - # secret: 5abee519483bc9f8cb37ce280e814bd0 +# app-id: wx041349c6f39b268b # 测试号(牛希尧提供的) +# secret: 5abee519483bc9f8cb37ce280e814bd0 app-id: wx5b23ba7a5589ecbb # 测试号(自己的) secret: 2a7b3b20c537e52e74afd395eb85f61f - # app-id: wxa69ab825b163be19 # 测试号(Kongdy 提供的) - # secret: bd4f9fab889591b62aeac0d7b8d8b4a0 +# app-id: wxa69ab825b163be19 # 测试号(Kongdy 提供的) +# secret: bd4f9fab889591b62aeac0d7b8d8b4a0 # 存储配置,解决 AccessToken 的跨节点的共享 config-storage: type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 @@ -197,10 +207,10 @@ wx: miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 # appid: wx62056c0d5e8db250 # 测试号(牛希尧提供的) # secret: 333ae72f41552af1e998fe1f54e1584a - # appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 - # secret: 6f270509224a7ae1296bbf1c8cb97aed - # appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的) - # secret: 4a1a04e07f6a4a0751b39c3064a92c8b +# appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 +# secret: 6f270509224a7ae1296bbf1c8cb97aed +# appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的) +# secret: 4a1a04e07f6a4a0751b39c3064a92c8b appid: wx66186af0759f47c9 # 测试号(puhui 提供的) secret: 3218bcbd112cbc614c7264ceb20144ac config-storage: @@ -260,7 +270,7 @@ justauth: iot: emq: # 账号 - username: anhaohao + username: haohao # 密码 password: ahh@123456 # 主机地址 @@ -272,4 +282,8 @@ iot: # 保持连接 keepalive: 60 # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) - clearSession: true \ No newline at end of file + clearSession: true + +pf4j: +# pluginsDir: /tmp/ + pluginsDir: ../plugins \ No newline at end of file From 6071afeae863e0e867db19a6b1b6ead10439bac5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 28 Jan 2025 08:35:07 +0800 Subject: [PATCH 110/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91Bpm=EF=BC=9A=E8=AE=BE=E5=A4=87=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E7=9A=84=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceDataController.java | 16 ++------ .../admin/device/IotDeviceLogController.java | 38 +++++++++++++++++++ .../vo/deviceData/IotDeviceLogPageReqVO.java | 15 +------- ...ataMapper.java => IotDeviceLogMapper.java} | 8 ++-- ...pper.java => IotDevicePropertyMapper.java} | 2 +- .../device/data/IotDeviceLogServiceImpl.java | 20 +++++----- .../data/IotDevicePropertyServiceImpl.java | 12 +++--- ...gDataMapper.xml => IotDeviceLogMapper.xml} | 29 ++------------ ...Mapper.xml => IotDevicePropertyMapper.xml} | 2 +- 9 files changed, 69 insertions(+), 73 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/{IotDeviceLogDataMapper.java => IotDeviceLogMapper.java} (86%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/{IotDevicePropertyDataMapper.java => IotDevicePropertyMapper.java} (99%) rename yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/{IotDeviceLogDataMapper.xml => IotDeviceLogMapper.xml} (59%) rename yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/{IotDevicePropertyDataMapper.xml => IotDevicePropertyMapper.xml} (99%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java index 6c2ea7a2d..c362e0bf1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceDataController.java @@ -3,10 +3,10 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotTimeDataRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; -import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -30,8 +30,6 @@ public class IotDeviceDataController { @Resource private IotDevicePropertyService deviceDataService; - @Resource - private IotDeviceLogService deviceLogDataService; // TODO @浩浩:这里的 /latest-list,包括方法名。 @GetMapping("/latest") @@ -49,12 +47,4 @@ public class IotDeviceDataController { return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); } - // TODO:功能权限 - @GetMapping("/log/page") - @Operation(summary = "获得设备日志分页") - public CommonResult> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) { - PageResult pageResult = deviceLogDataService.getDeviceLogPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class)); - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java new file mode 100644 index 000000000..09a230151 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogRespVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 设备日志") +@RestController +@RequestMapping("/iot/device/log") +@Validated +public class IotDeviceLogController { + + @Resource + private IotDeviceLogService deviceLogService; + + // TODO:功能权限 + @GetMapping("/page") + @Operation(summary = "获得设备日志分页") + public CommonResult> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) { + PageResult pageResult = deviceLogService.getDeviceLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogPageReqVO.java index a882a6d86..0091c8197 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogPageReqVO.java @@ -4,11 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @Schema(description = "管理后台 - IoT 设备日志分页查询 Request VO") @Data @@ -18,16 +13,10 @@ public class IotDeviceLogPageReqVO extends PageParam { @NotEmpty(message = "设备标识不能为空") private String deviceKey; - // TODO @super:对应的枚举类 @Schema(description = "消息类型", example = "property") - private String type; + private String type; // 参见 IotDeviceMessageTypeEnum 枚举,精准匹配 @Schema(description = "标识符", example = "temperature") - // TODO @super:对应的枚举类 - private String subType; - - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; + private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举,模糊匹配 } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java similarity index 86% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java index cd9f387a7..81a6220b8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java @@ -4,18 +4,17 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDevi import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.metadata.IPage; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; -import java.util.List; - /** * 设备日志 {@link IotDeviceLogDO} Mapper 接口 */ @Mapper @TDengineDS @InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 -public interface IotDeviceLogDataMapper { +public interface IotDeviceLogMapper { /** * 创建设备日志超级表 @@ -44,7 +43,8 @@ public interface IotDeviceLogDataMapper { * @param reqVO 分页查询条件 * @return 设备日志列表 */ - List selectPage(@Param("reqVO") IotDeviceLogPageReqVO reqVO); + IPage selectPage(IPage page, + @Param("reqVO") IotDeviceLogPageReqVO reqVO); /** * 获得设备日志总数 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java similarity index 99% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java index ac212cac4..852adb256 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyDataMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java @@ -20,7 +20,7 @@ import java.util.stream.Collectors; @Mapper @TDengineDS @InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 -public interface IotDevicePropertyDataMapper { +public interface IotDevicePropertyMapper { List getProductPropertySTableFieldList(@Param("productKey") String productKey); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java index fa5398a79..64649c5d8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java @@ -7,15 +7,15 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; -import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper; +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.util.List; - /** * IoT 设备日志数据 Service 实现类 * @@ -27,17 +27,17 @@ import java.util.List; public class IotDeviceLogServiceImpl implements IotDeviceLogService { @Resource - private IotDeviceLogDataMapper deviceLogDataMapper; + private IotDeviceLogMapper deviceLogMapper; @Override public void defineDeviceLog() { - if (StrUtil.isNotEmpty(deviceLogDataMapper.showDeviceLogSTable())) { + if (StrUtil.isNotEmpty(deviceLogMapper.showDeviceLogSTable())) { log.info("[defineDeviceLog][设备日志超级表已存在,创建跳过]"); return; } log.info("[defineDeviceLog][设备日志超级表不存在,创建开始...]"); - deviceLogDataMapper.createDeviceLogSTable(); + deviceLogMapper.createDeviceLogSTable(); log.info("[defineDeviceLog][设备日志超级表不存在,创建成功]"); } @@ -46,15 +46,15 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { IotDeviceLogDO log = BeanUtils.toBean(message, IotDeviceLogDO.class) .setId(IdUtil.fastSimpleUUID()) .setContent(JsonUtils.toJsonString(message.getData())); - deviceLogDataMapper.insert(log); + deviceLogMapper.insert(log); } @Override public PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { // TODO @芋艿:增加一个表不存在的 try catch - List list = deviceLogDataMapper.selectPage(pageReqVO); - Long total = deviceLogDataMapper.selectCount(pageReqVO); - return new PageResult<>(list, total); + IPage page = deviceLogMapper.selectPage( + new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO); + return new PageResult<>(page.getRecords(), page.getTotal()); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index 0aa438b13..0b3a4f11b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO; -import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; +import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyMapper; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; @@ -68,7 +68,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { private DevicePropertyRedisDAO deviceDataRedisDAO; @Resource - private IotDevicePropertyDataMapper devicePropertyDataMapper; + private IotDevicePropertyMapper devicePropertyMapper; @Override public void defineDevicePropertyData(Long productId) { @@ -79,7 +79,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { // 1.2 解析 DB 里的字段 List oldFields = new ArrayList<>(); try { - oldFields.addAll(devicePropertyDataMapper.getProductPropertySTableFieldList(product.getProductKey())); + oldFields.addAll(devicePropertyMapper.getProductPropertySTableFieldList(product.getProductKey())); } catch (Exception e) { if (!e.getMessage().contains("Table does not exist")) { throw e; @@ -93,11 +93,11 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { log.info("[defineDevicePropertyData][productId({}) 没有需要定义的属性]", productId); return; } - devicePropertyDataMapper.createProductPropertySTable(product.getProductKey(), newFields); + devicePropertyMapper.createProductPropertySTable(product.getProductKey(), newFields); return; } // 2.2 情况二:如果是修改的时候,需要更新表 - devicePropertyDataMapper.alterProductPropertySTable(product.getProductKey(), oldFields, newFields); + devicePropertyMapper.alterProductPropertySTable(product.getProductKey(), oldFields, newFields); } private List buildTableFieldList(List thingModels) { @@ -142,7 +142,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } // 3.1 保存设备属性【数据】 - devicePropertyDataMapper.insert(device, properties, + devicePropertyMapper.insert(device, properties, LocalDateTimeUtil.toEpochMilli(message.getReportTime())); // TODO @芋艿:后续要看看,查询的时候,能不能用 LocalDateTime // 3.2 保存设备属性【日志】 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml similarity index 59% rename from yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml rename to yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml index bbc1fb718..2ff555da9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml @@ -2,7 +2,7 @@ - + CREATE STABLE IF NOT EXISTS device_log ( @@ -40,38 +40,17 @@ - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml similarity index 99% rename from yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml rename to yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml index 21d1ed16e..87f21b182 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyDataMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml @@ -2,7 +2,7 @@ - + DESCRIBE product_property_${productKey} - - + SELECT ${reqVO.identifier} AS `value`, report_time AS update_time + FROM device_property_${reqVO.deviceKey} + WHERE ${reqVO.identifier} IS NOT NULL ORDER BY ts DESC - LIMIT #{params.rows} OFFSET #{params.page} - - - - \ No newline at end of file From 0b16f1678cc02aa5310e5820219a9ce16ea79ecd Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 28 Jan 2025 12:04:59 +0800 Subject: [PATCH 113/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91Bpm=EF=BC=9A=E5=AE=8C=E5=96=84=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=B1=9E=E6=80=A7=E7=9A=84=E5=8E=86=E5=8F=B2=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceLogController.java | 3 +- .../device/IotDevicePropertyController.java | 34 +++++++-- .../IotDevicePropertyHistoryPageReqVO.java | 35 ++++++++++ .../vo/data/IotDevicePropertyPageReqVO.java | 25 ------- .../vo/data/IotDevicePropertyRespVO.java | 2 +- .../thingmodel/model/ThingModelProperty.java | 5 +- .../convert/device/IotDeviceDataConvert.java | 32 --------- .../module/iot/convert/package-info.java | 3 + .../dal/tdengine/IotDevicePropertyMapper.java | 4 +- .../device/data/IotDeviceLogServiceImpl.java | 14 ++-- .../device/data/IotDevicePropertyService.java | 6 +- .../data/IotDevicePropertyServiceImpl.java | 26 ++++--- .../module/iot/util/IotTdDatabaseUtils.java | 69 ------------------- .../mapper/device/IotDevicePropertyMapper.xml | 7 +- 14 files changed, 103 insertions(+), 162 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyPageReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java index 99960dfa4..81d1bff94 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java @@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -27,9 +28,9 @@ public class IotDeviceLogController { @Resource private IotDeviceLogService deviceLogService; - // TODO:功能权限 @GetMapping("/page") @Operation(summary = "获得设备日志分页") + @PreAuthorize("@ss.hasPermission('iot:device:log-query')") public CommonResult> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) { PageResult pageResult = deviceLogService.getDeviceLogPage(pageReqVO); return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class)); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java index 6cd5448fa..d8021d2e8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java @@ -3,10 +3,11 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; @@ -15,12 +16,16 @@ import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @@ -42,14 +47,22 @@ public class IotDevicePropertyController { @Resource private IotDeviceService deviceService; - // TODO @芋艿:权限 @GetMapping("/latest") @Operation(summary = "获取设备属性最新属性") - public CommonResult> getLatestDeviceProperties(@Valid IotDevicePropertyPageReqVO pageReqVO) { - Map properties = devicePropertyService.getLatestDeviceProperties(pageReqVO); + @Parameters({ + @Parameter(name = "deviceId", description = "设备编号", required = true), + @Parameter(name = "identifier", description = "标识符"), + @Parameter(name = "name", description = "名称") + }) + @PreAuthorize("@ss.hasPermission('iot:device:property-query')") + public CommonResult> getLatestDeviceProperties( + @RequestParam("deviceId") Long deviceId, + @RequestParam(value = "identifier", required = false) String identifier, + @RequestParam(value = "name", required = false) String name) { + Map properties = devicePropertyService.getLatestDeviceProperties(deviceId); // 拼接数据 - IotDeviceDO device = deviceService.getDevice(pageReqVO.getDeviceId()); + IotDeviceDO device = deviceService.getDevice(deviceId); Assert.notNull(device, "设备不存在"); List thingModels = thingModelService.getThingModelListByProductId(device.getProductId()); return success(convertList(properties.entrySet(), entry -> { @@ -58,6 +71,13 @@ public class IotDevicePropertyController { if (thingModel == null || thingModel.getProperty() == null) { return null; } + if (StrUtil.isNotEmpty(identifier) && !StrUtil.contains(thingModel.getIdentifier(), identifier)) { + return null; + } + if (StrUtil.isNotEmpty(name) && !StrUtil.contains(thingModel.getName(), name)) { + return null; + } + // 构建对象 IotDevicePropertyDO property = entry.getValue(); return BeanUtils.toBean(thingModel, IotDevicePropertyRespVO.class) .setDataType(thingModel.getProperty().getDataType()) @@ -66,11 +86,11 @@ public class IotDevicePropertyController { })); } - // TODO @芋艿:权限 @GetMapping("/history-page") @Operation(summary = "获取设备属性历史数据") + @PreAuthorize("@ss.hasPermission('iot:device:property-query')") public CommonResult> getHistoryDevicePropertyPage( - @Valid IotDevicePropertyPageReqVO pageReqVO) { + @Valid IotDevicePropertyHistoryPageReqVO pageReqVO) { Assert.notEmpty(pageReqVO.getIdentifier(), "标识符不能为空"); return success(devicePropertyService.getHistoryDevicePropertyPage(pageReqVO)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java new file mode 100644 index 000000000..0de45e4a7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 设备属性历史分页 Request VO") +@Data +public class IotDevicePropertyHistoryPageReqVO extends PageParam { + + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @NotNull(message = "设备编号不能为空") + private Long deviceId; + + @Schema(description = "设备 Key", hidden = true) + private String deviceKey; // 非前端传递,后端自己查询设置 + + @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "属性标识符不能为空") + private String identifier; + + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Size(min = 2, max = 2, message = "请选择时间范围") + private LocalDateTime[] times; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyPageReqVO.java deleted file mode 100644 index 9d391ddbc..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyPageReqVO.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -@Schema(description = "管理后台 - IoT 设备属性 Request VO") -@Data -public class IotDevicePropertyPageReqVO extends PageParam { - - @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") - @NotNull(message = "设备编号不能为空") - private Long deviceId; - - @Schema(description = "设备 Key", hidden = true) - private String deviceKey; // 非前端传递,后端自己查询设置 - - @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED) - private String identifier; - - @Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED) - private String name; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java index 93d33bf49..3a3fa4902 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java @@ -14,7 +14,7 @@ public class IotDevicePropertyRespVO { private Object value; @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - private Long updateTime; + private Long updateTime; // 由于从 TDengine 查询出来的是 Long 类型,所以这里也使用 Long 类型 // ========== 基于 ThingModel 查询 ========== diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index db7333df2..4c131d801 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -31,10 +31,7 @@ public class ThingModelProperty { */ private String accessMode; /** - * 是否是标准品类的必选服务。 - * - * - true:是 - * - false:否 + * 是否是标准品类的必选服务 */ private Boolean required; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java deleted file mode 100644 index d8f6e4704..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/device/IotDeviceDataConvert.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.iot.convert.device; - -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -// TODO 是否要删除? -@Mapper -public interface IotDeviceDataConvert { - - IotDeviceDataConvert INSTANCE = Mappers.getMapper(IotDeviceDataConvert.class); - -// default List convert(Map deviceData, IotDeviceDO device){ -// List list = new ArrayList<>(); -// deviceData.forEach((identifier, value) -> { -//// ThingModelProperty property = ThingModelService.INSTANCE.getProperty(device.getProductId(), identifier); -//// if (Objects.isNull(property)) { -//// return; -//// } -// IotDeviceDataRespVO vo = new IotDeviceDataRespVO(); -// vo.setDeviceId(device.getId()); -// vo.setProductKey(device.getProductKey()); -// vo.setDeviceName(device.getDeviceName()); -// vo.setIdentifier(identifier); -//// vo.setName(property.getName()); -//// vo.setDataType(property.getDataType().getType()); -// vo.setUpdateTime(device.getUpdateTime()); -// vo.setValue(value.toString()); -// list.add(vo); -// }); -// return list; -// } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java index c196c25c3..28131f090 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java @@ -1 +1,4 @@ +/** + * TODO 芋艿:占位 + */ package cn.iocoder.yudao.module.iot.convert; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java index cb39ef51d..8ca8bcecb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField; @@ -85,6 +85,6 @@ public interface IotDevicePropertyMapper { @Param("reportTime") Long reportTime); IPage selectPageByHistory(IPage page, - @Param("reqVO") IotDevicePropertyPageReqVO reqVO); + @Param("reqVO") IotDevicePropertyHistoryPageReqVO reqVO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java index bfa604d02..79bb0a52a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java @@ -51,10 +51,16 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { @Override public PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { - // TODO @芋艿:增加一个表不存在的 try catch - IPage page = deviceLogMapper.selectPage( - new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO); - return new PageResult<>(page.getRecords(), page.getTotal()); + try { + IPage page = deviceLogMapper.selectPage( + new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO); + return new PageResult<>(page.getRecords(), page.getTotal()); + } catch (Exception exception) { + if (exception.getMessage().contains("Table does not exist")) { + return PageResult.empty(); + } + throw exception; + } } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java index 7d856296e..0711230aa 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; @@ -36,7 +36,7 @@ public interface IotDevicePropertyService { * @param deviceId 设备编号 * @return 设备属性最新数据 */ - Map getLatestDeviceProperties(@Valid IotDevicePropertyPageReqVO deviceId); + Map getLatestDeviceProperties(Long deviceId); /** * 获得设备属性历史数据 @@ -44,6 +44,6 @@ public interface IotDevicePropertyService { * @param pageReqVO 分页请求 * @return 设备属性历史数据 */ - PageResult getHistoryDevicePropertyPage(@Valid IotDevicePropertyPageReqVO pageReqVO); + PageResult getHistoryDevicePropertyPage(@Valid IotDevicePropertyHistoryPageReqVO pageReqVO); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index d3df806d3..c4a3254c8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -6,7 +6,7 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -25,7 +25,6 @@ import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import jakarta.annotation.Resource; -import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -146,33 +145,38 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { // 3.1 保存设备属性【数据】 devicePropertyMapper.insert(device, properties, - LocalDateTimeUtil.toEpochMilli(message.getReportTime())); // TODO @芋艿:后续要看看,查询的时候,能不能用 LocalDateTime + LocalDateTimeUtil.toEpochMilli(message.getReportTime())); // 3.2 保存设备属性【日志】 deviceDataRedisDAO.set(message.getDeviceKey(), convertMap(properties.entrySet(), Map.Entry::getKey, entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build())); } - // TODO @芋艿:需要在优化下,根据 name 之类的过滤 @Override - public Map getLatestDeviceProperties(@Valid IotDevicePropertyPageReqVO pageReqVO) { + public Map getLatestDeviceProperties(Long deviceId) { // 获取设备信息 - IotDeviceDO device = deviceService.validateDeviceExists(pageReqVO.getDeviceId()); + IotDeviceDO device = deviceService.validateDeviceExists(deviceId); // 获得设备属性 return deviceDataRedisDAO.get(device.getDeviceKey()); } @Override - public PageResult getHistoryDevicePropertyPage(IotDevicePropertyPageReqVO pageReqVO) { + public PageResult getHistoryDevicePropertyPage(IotDevicePropertyHistoryPageReqVO pageReqVO) { // 获取设备信息 IotDeviceDO device = deviceService.validateDeviceExists(pageReqVO.getDeviceId()); pageReqVO.setDeviceKey(device.getDeviceKey()); - // TODO @芋艿:增加一个表不存在的 try catch - IPage page = devicePropertyMapper.selectPageByHistory( - new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO); - return new PageResult<>(page.getRecords(), page.getTotal()); + try { + IPage page = devicePropertyMapper.selectPageByHistory( + new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO); + return new PageResult<>(page.getRecords(), page.getTotal()); + } catch (Exception exception) { + if (exception.getMessage().contains("Table does not exist")) { + return PageResult.empty(); + } + throw exception; + } } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java deleted file mode 100644 index a409c8069..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/IotTdDatabaseUtils.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.iocoder.yudao.module.iot.util; - -import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.module.iot.enums.IotConstants; -import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; - -// TODO @芋艿:可能要思索下,有没更好的处理方式 -// TODO @芋艿:怎么改成无状态 -/** - * TD 数据库工具类 - * - * @author AlwaysSuper - */ -public class IotTdDatabaseUtils { - - /** - * 获取数据库名称 - */ - public static String getDatabaseName(String url) { -// TODO @alwayssuper:StrUtil.subAfter("/") - return StrUtil.subAfter(url, "/", true); - } - - /** - * 获取产品超级表表名 - * - * @param deviceType 设备类型 - * @param productKey 产品 Key - * @return 产品超级表表名 - */ - public static String getProductSuperTableName(Integer deviceType, String productKey) { - Assert.notNull(deviceType, "deviceType 不能为空"); - if (IotProductDeviceTypeEnum.GATEWAY_SUB.getType().equals(deviceType)) { - return String.format(IotConstants.GATEWAY_SUB_STABLE_NAME_FORMAT, productKey).toLowerCase(); - } - if (IotProductDeviceTypeEnum.GATEWAY.getType().equals(deviceType)) { - return String.format(IotConstants.GATEWAY_STABLE_NAME_FORMAT, productKey).toLowerCase(); - } - if (IotProductDeviceTypeEnum.DIRECT.getType().equals(deviceType)){ - return String.format(IotConstants.DEVICE_STABLE_NAME_FORMAT, productKey).toLowerCase(); - } - throw new IllegalArgumentException("deviceType 不正确"); - } - - /** - * 获取物模型日志超级表表名 - * - * @param productKey 产品 Key - * @return 物模型日志超级表表名 - * - */ - public static String getThingModelMessageSuperTableName(String productKey) { - return "thing_model_message_" + productKey.toLowerCase(); - } - - /** - * 获取物模型日志设备表名 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @return 物模型日志设备表名 - */ - public static String getThingModelMessageDeviceTableName(String productKey, String deviceName) { - return String.format(IotConstants.THING_MODEL_MESSAGE_TABLE_NAME_FORMAT, - productKey.toLowerCase(), deviceName.toLowerCase()); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml index 696b23a1b..7a3c3eb6f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml @@ -66,11 +66,12 @@ DESCRIBE product_property_${productKey} - From 76ab64a255c311a354060eb2580f57a37aa29b7f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 28 Jan 2025 22:24:28 +0800 Subject: [PATCH 114/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thingmodel/model/ThingModelEvent.java | 1 + .../thingmodel/model/ThingModelParam.java | 1 + .../thingmodel/model/ThingModelProperty.java | 1 + .../thingmodel/model/ThingModelRespVO.java | 50 ------------------- .../thingmodel/model/ThingModelService.java | 1 + .../thingmodel/vo/IotThingModelListReqVO.java | 11 ++-- .../thingmodel/vo/IotThingModelPageReqVO.java | 9 ++-- .../thingmodel/vo/IotThingModelRespVO.java | 1 + .../thingmodel/vo/IotThingModelSaveReqVO.java | 1 + .../thingmodel/IotThingModelService.java | 1 + .../thingmodel/IotThingModelServiceImpl.java | 48 +++++++++--------- 11 files changed, 42 insertions(+), 83 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelRespVO.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index 0ed5d29d1..0a5e0056f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -5,6 +5,7 @@ import lombok.Data; import java.util.List; +// TODO @puhui999:必要的参数校验 /** * 物模型中的事件 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java index 9cddf1d29..6215d1537 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java @@ -6,6 +6,7 @@ import lombok.Data; import java.util.List; +// TODO @puhui999:必要的参数校验 /** * IOT 产品物模型中的参数 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index 4c131d801..157a4c488 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -6,6 +6,7 @@ import lombok.Data; import java.util.List; +// TODO @puhui999:必要的参数校验 /** * 物模型中的属性 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelRespVO.java deleted file mode 100644 index 44fd24c0a..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelRespVO.java +++ /dev/null @@ -1,50 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; - -import lombok.*; - -import java.util.List; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@ToString -public class ThingModelRespVO { - - /** - * 产品编号 - */ - private Long id; - - /** - * 产品标识 - */ - private String productKey; - - /** - * 物模型 - */ - private Model model; - - /** - * 物模型 - */ - @Data - public static class Model { - - /** - * 属性列表 - */ - private List properties; - - /** - * 服务列表 - */ - private List services; - - /** - * 事件列表 - */ - private List events; - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index 6803c7103..067ca2ea1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -5,6 +5,7 @@ import lombok.Data; import java.util.List; +// TODO @puhui999:必要的参数校验 /** * 物模型中的服务 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java index dd77cfc5e..8f7f374dd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java @@ -6,10 +6,15 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; -@Schema(description = "管理后台 - IoT 产品物模型List Request VO") +// TODO @puhui999:部分字段,可以用 cursor 加上 example +@Schema(description = "管理后台 - IoT 产品物模型 List Request VO") @Data public class IotThingModelListReqVO { + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "产品编号不能为空") + private Long productId; + @Schema(description = "功能标识") private String identifier; @@ -20,8 +25,4 @@ public class IotThingModelListReqVO { @InEnum(IotThingModelTypeEnum.class) private Integer type; - @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "产品 ID 不能为空") - private Long productId; - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java index 314441fb6..404bc7cc2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java @@ -9,12 +9,17 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +// TODO @puhui999:部分字段,可以用 cursor 加上 example @Schema(description = "管理后台 - IoT 产品物模型分页 Request VO") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) public class IotThingModelPageReqVO extends PageParam { + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "产品编号不能为空") + private Long productId; + @Schema(description = "功能标识") private String identifier; @@ -25,8 +30,4 @@ public class IotThingModelPageReqVO extends PageParam { @InEnum(IotThingModelTypeEnum.class) private Integer type; - @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "产品ID不能为空") - private Long productId; - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java index 88c197bab..37a42edc9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java @@ -10,6 +10,7 @@ import lombok.Data; import java.time.LocalDateTime; +// TODO @puhui999:部分字段,可以用 cursor 加上 example @Schema(description = "管理后台 - IoT 产品物模型 Response VO") @Data @ExcelIgnoreUnannotated diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java index 0eb37231b..18b8f4042 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java @@ -10,6 +10,7 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; +// TODO @puhui999:部分字段,可以用 cursor 加上 example @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") @Data public class IotThingModelSaveReqVO { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java index cc81e5f02..92aa5978c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java @@ -79,4 +79,5 @@ public interface IotThingModelService { * @return 产品物模型列表 */ List getThingModelList(IotThingModelListReqVO reqVO); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index 5c9f5fd05..5c9773901 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.service.thingmodel; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -54,29 +55,26 @@ public class IotThingModelServiceImpl implements IotThingModelService { @Override @Transactional(rollbackFor = Exception.class) public Long createThingModel(IotThingModelSaveReqVO createReqVO) { - // 1. 校验功能标识符在同一产品下是否唯一 + // 1.1 校验功能标识符在同一产品下是否唯一 validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); - - // 2. 功能名称在同一产品下是否唯一 + // 1.2 功能名称在同一产品下是否唯一 validateNameUnique(createReqVO.getProductId(), createReqVO.getName()); - - // 3. 系统保留字段,不能用于标识符定义 + // 1.3 系统保留字段,不能用于标识符定义 validateNotDefaultEventAndService(createReqVO.getIdentifier()); - - // 4. 校验产品状态,发布状态下,不允许新增功能 + // 1.4 校验产品状态,发布状态下,不允许新增功能 validateProductStatus(createReqVO.getProductId()); - // 5. 插入数据库 + // 2. 插入数据库 IotThingModelDO thingModel = IotThingModelConvert.INSTANCE.convert(createReqVO); thingModelMapper.insert(thingModel); - // 6. 如果创建的是属性,需要更新默认的事件和服务 + // 3. 如果创建的是属性,需要更新默认的事件和服务 if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } // TODO @puhui999: 服务和事件的情况 method 怎么设置?在前端设置还是后端设置? - // 7. 删除缓存 + // 4. 删除缓存 deleteThingModelListCache(createReqVO.getProductKey()); return thingModel.getId(); } @@ -84,38 +82,35 @@ public class IotThingModelServiceImpl implements IotThingModelService { @Override @Transactional(rollbackFor = Exception.class) public void updateThingModel(IotThingModelSaveReqVO updateReqVO) { - // 1. 校验功能是否存在 + // 1.1 校验功能是否存在 validateProductThingModelMapperExists(updateReqVO.getId()); - - // 2. 校验功能标识符是否唯一 + // 1.2 校验功能标识符是否唯一 validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); - - // 3. 校验产品状态,发布状态下,不允许操作功能 + // 1.3 校验产品状态,发布状态下,不允许操作功能 validateProductStatus(updateReqVO.getProductId()); - // 4. 更新数据库 + // 2. 更新数据库 IotThingModelDO thingModel = IotThingModelConvert.INSTANCE.convert(updateReqVO); thingModelMapper.updateById(thingModel); - // 5. 如果更新的是属性,需要更新默认的事件和服务 + // 3. 如果更新的是属性,需要更新默认的事件和服务 if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } - // 6. 删除缓存 + // 4. 删除缓存 deleteThingModelListCache(updateReqVO.getProductKey()); } @Override @Transactional(rollbackFor = Exception.class) public void deleteThingModel(Long id) { - // 1. 校验功能是否存在 + // 1.1 校验功能是否存在 IotThingModelDO thingModel = thingModelMapper.selectById(id); if (thingModel == null) { throw exception(THING_MODEL_NOT_EXISTS); } - - // 3. 校验产品状态,发布状态下,不允许操作功能 + // 1.2 校验产品状态,发布状态下,不允许操作功能 validateProductStatus(thingModel.getProductId()); // 2. 删除功能 @@ -168,6 +163,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { } } + // TODO @puhui999:这个方法,和 validateIdentifierUnique 可以融合下 private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) { @@ -176,15 +172,16 @@ public class IotThingModelServiceImpl implements IotThingModelService { } private void validateProductStatus(Long createReqVO) { - IotProductDO product = productService.getProduct(createReqVO); + IotProductDO product = productService.validateProductExists(createReqVO); if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) { throw exception(PRODUCT_STATUS_NOT_ALLOW_THING_MODEL); } } + // TODO @芋艿:在 review 下 private void validateNotDefaultEventAndService(String identifier) { - // set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义 - if (CollUtil.containsAny(Arrays.asList("set", "get", "post", "property", "event", "time", "value"), Collections.singletonList(identifier))) { + // 系统保留字段,不能用于标识符定义 + if (StrUtil.equalsAny(identifier, "set", "get", "post", "property", "event", "time", "value")) { throw exception(THING_MODEL_IDENTIFIER_INVALID); } } @@ -205,6 +202,9 @@ public class IotThingModelServiceImpl implements IotThingModelService { /** * 创建默认的事件和服务 + * + * @param productId 产品编号 + * @param productKey 产品标识 */ public void createDefaultEventsAndServices(Long productId, String productKey) { // 1. 获取当前属性列表 From f14cc470aacfc3fcd087dfd19259d230a1d2e60c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 28 Jan 2025 23:16:30 +0800 Subject: [PATCH 115/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=91IoT=EF=BC=9A=E8=A7=A3=E5=86=B3=E7=89=A9?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E7=9A=84=20identifier=20=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E9=A9=BC=E5=B3=B0=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=8F=92=E5=85=A5=E5=92=8C=E6=9F=A5=E8=AF=A2=E7=9A=84?= =?UTF-8?q?=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/dal/tdengine/IotDevicePropertyMapper.java | 2 +- .../resources/mapper/device/IotDevicePropertyMapper.xml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java index 8ca8bcecb..f2d6af97e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java @@ -33,7 +33,7 @@ public interface IotDevicePropertyMapper { List oldFields, List newFields) { oldFields.removeIf(field -> StrUtil.equalsAny(field.getField(), - TDengineTableField.FIELD_TS, "device_key", "report_time")); + TDengineTableField.FIELD_TS, "report_time")); List addFields = newFields.stream().filter( // 新增的字段 newField -> oldFields.stream().noneMatch(oldField -> oldField.getField().equals(newField.getField()))) .collect(Collectors.toList()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml index 7a3c3eb6f..bdc40e833 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml @@ -51,7 +51,7 @@ TAGS ('${device.deviceKey}') (ts, report_time, - ${key} + ${@cn.hutool.core.util.StrUtil@toUnderlineCase(key)} ) VALUES @@ -67,9 +67,9 @@ - INSERT INTO device_log_${deviceKey} (ts, id, product_key, device_name, type, identifier, content, report_time) + INSERT INTO device_log_${deviceKey} (ts, id, product_key, device_name, type, identifier, content, code, report_time) USING device_log TAGS ('${deviceKey}') VALUES ( @@ -35,6 +36,7 @@ #{type}, #{identifier}, #{content}, + #{code}, #{reportTime} ) diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java index 3c6fee7a4..127332cc7 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java @@ -14,10 +14,28 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceSe */ public interface IotDeviceDownstreamHandler { + /** + * 调用设备服务 + * + * @param invokeReqDTO 调用设备服务的请求 + * @return 是否成功 + */ CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO); + /** + * 获取设备属性 + * + * @param getReqDTO 获取设备属性的请求 + * @return 是否成功 + */ CommonResult getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO); + /** + * 设置设备属性 + * + * @param setReqDTO 设置设备属性的请求 + * @return 是否成功 + */ CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java index 27e1ff8d7..22ae7012d 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java @@ -1,10 +1,18 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import io.vertx.core.json.JsonObject; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; @Slf4j @RequiredArgsConstructor @@ -15,9 +23,34 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler params = (Map) body.getMap().get("params"); + invokeReqDTO = ((IotDeviceServiceInvokeReqDTO) new IotDeviceServiceInvokeReqDTO() + .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName)) + .setIdentifier(identifier).setParams(params); + } catch (Exception e) { + log.error("[handle][解析参数失败]", e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + return; + } + + // 2. 调用下游处理器 + try { + CommonResult result = deviceDownstreamHandler.invokeDeviceService(invokeReqDTO); + IotPluginCommonUtils.writeJson(routingContext, result); + } catch (Exception e) { + log.error("[handle][请求参数({}) 服务调用异常]", invokeReqDTO, e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + } } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java index d44a4e02e..f93717386 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java @@ -3,6 +3,11 @@ package cn.iocoder.yudao.module.iot.plugin.common.util; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.system.SystemUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import io.vertx.core.http.HttpHeaders; +import io.vertx.ext.web.RoutingContext; +import org.springframework.http.MediaType; /** * IoT 插件的通用工具类 @@ -28,4 +33,12 @@ public class IotPluginCommonUtils { SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID(), IdUtil.fastSimpleUUID()); } + @SuppressWarnings("deprecation") + public static void writeJson(RoutingContext routingContext, CommonResult result) { + routingContext.response() + .setStatusCode(200) + .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .end(JsonUtils.toJsonString(result)); + } + } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java index 388ad8ac4..4e402f91f 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.http.downstream.IotDeviceDownstreamHandlerImpl; import cn.iocoder.yudao.module.iot.plugin.http.upstream.IotDeviceUpstreamServer; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -26,4 +28,9 @@ public class IotPluginHttpAutoConfiguration { return new IotDeviceUpstreamServer(port, deviceUpstreamApi); } + @Bean + public IotDeviceDownstreamHandler deviceDownstreamHandler() { + return new IotDeviceDownstreamHandlerImpl(); + } + } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java index 816a17253..b70052530 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java @@ -5,7 +5,8 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePr import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; -import org.springframework.stereotype.Component; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED; /** * HTTP 插件的 {@link IotDeviceDownstreamHandler} 实现类 @@ -15,28 +16,21 @@ import org.springframework.stereotype.Component; * * @author 芋道源码 */ -@Component // TODO @芋艿:后续统一处理 public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandler { @Override public CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO) { - // TODO @芋艿:待实现 - System.out.println(); - return null; + return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持调用设备服务"); } @Override public CommonResult getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO) { - // TODO @芋艿:待实现 - System.out.println(); - return null; + return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持获取设备属性"); } @Override public CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO) { - // TODO @芋艿:待实现 - System.out.println(); - return null; + return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性"); } } From 45b8172a617a15f5a7b34347ed1da208097a2339 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 31 Jan 2025 17:51:39 +0800 Subject: [PATCH 131/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=AE=9E=E7=8E=B0=20device=20?= =?UTF-8?q?=E4=B8=8B=E8=A1=8C=E5=B1=9E=E6=80=A7=E8=8E=B7=E5=8F=96=E3=80=81?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E7=9A=84=E4=B8=8B=E8=A1=8C=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceController.http | 30 +++++++- .../IotDeviceDownstreamServiceImpl.java | 73 +++++++++++++++++-- .../downstream/IotDeviceDownstreamServer.java | 10 ++- .../IotDevicePropertyGetVertxHandler.java | 61 ++++++++++++++++ .../IotDevicePropertySetVertxHandler.java | 61 ++++++++++++++++ .../IotDeviceServiceInvokeVertxHandler.java | 17 +++-- 6 files changed, 237 insertions(+), 15 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http index 9518f10aa..34df37e93 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http @@ -1,4 +1,4 @@ -### 请求 /iot/device/simulation-downstream 接口 => 成功 +### 请求 /iot/device/simulation-downstream 接口(服务调用) => 成功 POST {{baseUrl}}/iot/device/simulation-downstream Content-Type: application/json tenant-id: {{adminTenentId}} @@ -11,4 +11,32 @@ Authorization: Bearer {{token}} "data": { "xx": "yy" } +} + +### 请求 /iot/device/simulation-downstream 接口(属性设置) => 成功 +POST {{baseUrl}}/iot/device/simulation-downstream +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "id": 25, + "type": "property", + "identifier": "set", + "data": { + "xx": "yy" + } +} + +### 请求 /iot/device/simulation-downstream 接口(属性获取) => 成功 +POST {{baseUrl}}/iot/device/simulation-downstream +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "id": 25, + "type": "property", + "identifier": "get", + "data": ["xx", "yy"] } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java index 4fa7e45a9..7f341f57c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java @@ -6,6 +6,8 @@ import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceDownstreamAbstractReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationDownstreamReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -24,6 +26,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.client.RestTemplate; import java.time.LocalDateTime; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -91,11 +94,12 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic */ @SuppressWarnings("unchecked") private void invokeDeviceService(IotDeviceSimulationDownstreamReqVO downstreamReqVO, - IotDeviceDO device, IotDeviceDO parentDevice) { + IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数校验 if (!(downstreamReqVO.getData() instanceof Map)) { throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型"); } + // TODO @super:【可优化】过滤掉不合法的服务 // 2. 发送请求 String url = String.format( "sys/%s/%s/thing/service/%s", @@ -125,16 +129,73 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic * @param device 设备 * @param parentDevice 父设备 */ + @SuppressWarnings("unchecked") private void setDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO, - IotDeviceDO device, IotDeviceDO parentDevice) { - // TODO 1. 请求 + IotDeviceDO device, IotDeviceDO parentDevice) { + // 1. 参数校验 + if (!(downstreamReqVO.getData() instanceof Map)) { + throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型"); + } + // TODO @super:【可优化】过滤掉不合法的属性 - // TODO 2. 发送消息 + // 2. 发送请求 + String url = String.format( "sys/%s/%s/thing/service/property/set", + getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); + IotDevicePropertySetReqDTO reqDTO = new IotDevicePropertySetReqDTO() + .setProperties((Map) downstreamReqVO.getData()); + CommonResult result = requestPlugin(url, reqDTO, device); + + // 3. 发送设备消息 + IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) + .setType(IotDeviceMessageTypeEnum.PROPERTY.getType()) + .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()) + .setData(reqDTO.getProperties()); + sendDeviceMessage(message, device, result.getCode()); + + // 4. 如果不成功,抛出异常,提示用户 + if (result.isError()) { + log.error("[setDeviceProperty][设备({})属性设置失败,请求参数:({}),响应结果:({})]", + device.getDeviceKey(), reqDTO, result); + throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); + } } + /** + * 获取设备属性 + * + * @param downstreamReqVO 下行请求 + * @param device 设备 + * @param parentDevice 父设备 + */ + @SuppressWarnings("unchecked") private void getDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO, - IotDeviceDO device, IotDeviceDO parentDevice) { - // TODO 芋艿:这里需要获取设备属性 + IotDeviceDO device, IotDeviceDO parentDevice) { + // 1. 参数校验 + if (!(downstreamReqVO.getData() instanceof List)) { + throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 List 类型"); + } + // TODO @super:【可优化】过滤掉不合法的属性 + + // 2. 发送请求 + String url = String.format( "sys/%s/%s/thing/service/property/get", + getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); + IotDevicePropertyGetReqDTO reqDTO = new IotDevicePropertyGetReqDTO() + .setIdentifiers((List) downstreamReqVO.getData()); + CommonResult result = requestPlugin(url, reqDTO, device); + + // 3. 发送设备消息 + IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) + .setType(IotDeviceMessageTypeEnum.PROPERTY.getType()) + .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()) + .setData(reqDTO.getIdentifiers()); + sendDeviceMessage(message, device, result.getCode()); + + // 4. 如果不成功,抛出异常,提示用户 + if (result.isError()) { + log.error("[getDeviceProperty][设备({})属性获取失败,请求参数:({}),响应结果:({})]", + device.getDeviceKey(), reqDTO, result); + throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); + } } /** diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java index b87a2fc9d..4c45e972e 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertyGetVertxHandler; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertySetVertxHandler; import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceServiceInvokeVertxHandler; import io.vertx.core.Vertx; import io.vertx.core.http.HttpServer; @@ -24,8 +26,12 @@ public class IotDeviceDownstreamServer { // 创建 Router 实例 Router router = Router.router(vertx); router.route().handler(BodyHandler.create()); // 处理 Body - router.post(IotDeviceServiceInvokeVertxHandler.PATH).handler( - new IotDeviceServiceInvokeVertxHandler(deviceDownstreamHandler)); // 处理 Service Invoke + router.post(IotDeviceServiceInvokeVertxHandler.PATH) + .handler(new IotDeviceServiceInvokeVertxHandler(deviceDownstreamHandler)); + router.post(IotDevicePropertySetVertxHandler.PATH) + .handler(new IotDevicePropertySetVertxHandler(deviceDownstreamHandler)); + router.post(IotDevicePropertyGetVertxHandler.PATH) + .handler(new IotDevicePropertyGetVertxHandler(deviceDownstreamHandler)); // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java new file mode 100644 index 000000000..5f9906fdc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; + +/** + * IOT 设备服务获取 Vertx Handler + * + * 芋道源码 + */ +@Slf4j +@RequiredArgsConstructor +public class IotDevicePropertyGetVertxHandler implements Handler { + + public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/get"; + + private final IotDeviceDownstreamHandler deviceDownstreamHandler; + + @Override + @SuppressWarnings("unchecked") + public void handle(RoutingContext routingContext) { + // 1. 解析参数 + IotDevicePropertyGetReqDTO reqDTO; + try { + String productKey = routingContext.pathParam("productKey"); + String deviceName = routingContext.pathParam("deviceName"); + JsonObject body = routingContext.body().asJsonObject(); + String requestId = body.getString("requestId"); + List identifiers = (List) body.getMap().get("identifiers"); + reqDTO = ((IotDevicePropertyGetReqDTO) new IotDevicePropertyGetReqDTO() + .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName)) + .setIdentifiers(identifiers); + } catch (Exception e) { + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + return; + } + + // 2. 调用处理器 + try { + CommonResult result = deviceDownstreamHandler.getDeviceProperty(reqDTO); + IotPluginCommonUtils.writeJson(routingContext, result); + } catch (Exception e) { + log.error("[handle][请求参数({}) 属性获取异常]", reqDTO, e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java new file mode 100644 index 000000000..c8a60c770 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; + +/** + * IOT 设备服务设置 Vertx Handler + * + * 芋道源码 + */ +@Slf4j +@RequiredArgsConstructor +public class IotDevicePropertySetVertxHandler implements Handler { + + public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/set"; + + private final IotDeviceDownstreamHandler deviceDownstreamHandler; + + @Override + @SuppressWarnings("unchecked") + public void handle(RoutingContext routingContext) { + // 1. 解析参数 + IotDevicePropertySetReqDTO reqDTO; + try { + String productKey = routingContext.pathParam("productKey"); + String deviceName = routingContext.pathParam("deviceName"); + JsonObject body = routingContext.body().asJsonObject(); + String requestId = body.getString("requestId"); + Map properties = (Map) body.getMap().get("properties"); + reqDTO = ((IotDevicePropertySetReqDTO) new IotDevicePropertySetReqDTO() + .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName)) + .setProperties(properties); + } catch (Exception e) { + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + return; + } + + // 2. 调用处理器 + try { + CommonResult result = deviceDownstreamHandler.setDeviceProperty(reqDTO); + IotPluginCommonUtils.writeJson(routingContext, result); + } catch (Exception e) { + log.error("[handle][请求参数({}) 属性设置异常]", reqDTO, e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java index 22ae7012d..421fe7484 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java @@ -14,6 +14,11 @@ import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; +/** + * IOT 设备服务调用 Vertx Handler + * + * 芋道源码 + */ @Slf4j @RequiredArgsConstructor public class IotDeviceServiceInvokeVertxHandler implements Handler { @@ -26,7 +31,7 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler params = (Map) body.getMap().get("params"); - invokeReqDTO = ((IotDeviceServiceInvokeReqDTO) new IotDeviceServiceInvokeReqDTO() + reqDTO = ((IotDeviceServiceInvokeReqDTO) new IotDeviceServiceInvokeReqDTO() .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName)) .setIdentifier(identifier).setParams(params); } catch (Exception e) { - log.error("[handle][解析参数失败]", e); + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); return; } - // 2. 调用下游处理器 + // 2. 调用处理器 try { - CommonResult result = deviceDownstreamHandler.invokeDeviceService(invokeReqDTO); + CommonResult result = deviceDownstreamHandler.invokeDeviceService(reqDTO); IotPluginCommonUtils.writeJson(routingContext, result); } catch (Exception e) { - log.error("[handle][请求参数({}) 服务调用异常]", invokeReqDTO, e); + log.error("[handle][请求参数({}) 服务调用异常]", reqDTO, e); IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); } } From 7f0de1e34e102d06e182b8f47af7334ac45cca07 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 31 Jan 2025 18:04:55 +0800 Subject: [PATCH 132/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9Aserver=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E4=B8=8A=E8=A1=8C=E7=9A=84=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=88=E4=B8=8D=E5=8C=85=E6=8B=AC=20http=20=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E9=83=A8=E5=88=86=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../control/IotDeviceUpstreamServiceImpl.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index ca0263e7e..6188d0b5d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -67,7 +67,10 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { } // 2.2 情况二:事件上报 if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.EVENT.getType())) { - // TODO 芋艿:待实现 + reportDeviceEvent(((IotDeviceEventReportReqDTO) + new IotDeviceEventReportReqDTO().setRequestId(requestId).setReportTime(LocalDateTime.now()) + .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) + .setIdentifier(simulatorReqVO.getIdentifier()).setParams((Map) simulatorReqVO.getData())); return; } // 2.3 情况三:状态变更 @@ -120,7 +123,7 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { @Override public void reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { // 1.1 获得设备 - log.info("[reportDevicePropertyData][上报设备属性数据: {}]", reportReqDTO); + log.info("[reportDevicePropertyData][上报设备属性: {}]", reportReqDTO); IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); if (device == null) { @@ -141,9 +144,24 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { @Override public void reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { - log.info("[reportDeviceEventData][上报设备事件数据: {}]", reportReqDTO); + // 1.1 获得设备 + log.info("[reportDeviceEventData][上报设备事件: {}]", reportReqDTO); + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( + reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); + if (device == null) { + log.error("[reportDeviceEventData][设备({}/{})不存在]", + reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); + return; + } + // 1.2 记录设备的最后时间 + updateDeviceLastTime(device, reportReqDTO); - // TODO 芋艿:待实现 + // 2. 发送设备消息 + IotDeviceMessage message = BeanUtils.toBean(reportReqDTO, IotDeviceMessage.class) + .setType(IotDeviceMessageTypeEnum.EVENT.getType()) + .setIdentifier(reportReqDTO.getIdentifier()) + .setData(reportReqDTO.getParams()); + sendDeviceMessage(message, device); } private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) { From 2512f2dde8a0df4fd8f3f4d87bfcc65eaaed69cf Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 31 Jan 2025 19:05:42 +0800 Subject: [PATCH 133/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E4=BC=98=E5=8C=96=20http=20?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=20IotDevicePropertyReportVertxHandler=20?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotDevicePropertyGetReqDTO.java | 1 + .../upstream/IotDeviceUpstreamClient.java | 42 ++++----- .../upstream/IotDeviceUpstreamServer.java | 2 +- .../IotDevicePropertyReportVertxHandler.java | 85 +++++++------------ 4 files changed, 51 insertions(+), 79 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java index 061de5745..b72d88d97 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java @@ -5,6 +5,7 @@ import lombok.Data; import java.util.List; +// TODO @芋艿:从 server => plugin => device 是否有必要?从阿里云 iot 来看,没有这个功能?! /** * IoT 设备【属性】获取 Request DTO * diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java index 8310bad5a..c71606f62 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java @@ -6,10 +6,11 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEven import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.client.RestTemplate; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; /** * 设备数据 Upstream 上行客户端 @@ -18,60 +19,51 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; * * @author haohao */ +@RequiredArgsConstructor @Slf4j public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi { public static final String URL_PREFIX = "/rpc-api/iot/device/upstream"; private final RestTemplate restTemplate; + + // TODO @芋艿:改个名字 private final String deviceDataUrl; - // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 - // TODO @haohao:可以用 lombok 简化 - public IotDeviceUpstreamClient(RestTemplate restTemplate, String deviceDataUrl) { - this.restTemplate = restTemplate; - this.deviceDataUrl = deviceDataUrl; - } - - // TODO @haohao:返回结果,不用 CommonResult 哈。 @Override public CommonResult updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) { String url = deviceDataUrl + URL_PREFIX + "/update-state"; - return doPost(url, updateReqDTO, "updateDeviceState"); + return doPost(url, updateReqDTO); } @Override public CommonResult reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { String url = deviceDataUrl + URL_PREFIX + "/report-event"; - return doPost(url, reportReqDTO, "reportDeviceEventData"); + return doPost(url, reportReqDTO); } @Override public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { String url = deviceDataUrl + URL_PREFIX + "/report-property"; - return doPost(url, reportReqDTO, "reportDevicePropertyData"); + return doPost(url, reportReqDTO); } @Override public CommonResult heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) { String url = deviceDataUrl + URL_PREFIX + "/heartbeat-plugin-instance"; - return doPost(url, heartbeatReqDTO, "heartbeatPluginInstance"); + return doPost(url, heartbeatReqDTO); } - // TODO @haohao:未来可能有 get 类型哈 - /** - * 将与远程服务交互的通用逻辑抽取成一个私有方法 - */ - private CommonResult doPost(String url, T requestBody, String actionName) { - log.info("[{}] Sending request to URL: {}", actionName, url); + @SuppressWarnings("unchecked") + private CommonResult doPost(String url, T requestBody) { try { - // 这里指定返回类型为 CommonResult,根据后台服务返回的实际结构做调整 - restTemplate.postForObject(url, requestBody, CommonResult.class); - // TODO @haohao:check 结果,是否成功 - return success(true); + CommonResult result = restTemplate.postForObject(url, requestBody, + (Class>) (Class) CommonResult.class); + log.info("[doPost][url({}) requestBody({}) result({})]", url, requestBody, result); + return result; } catch (Exception e) { - log.error("[{}] Error sending request to URL: {}", actionName, url, e); - return CommonResult.error(400, "Request error: " + e.getMessage()); + log.error("[doPost][url({}) requestBody({}) 发生异常]", url, requestBody, e); + return CommonResult.error(INTERNAL_SERVER_ERROR); } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java index e6f4dbb27..87e6a6f85 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java @@ -31,7 +31,7 @@ public class IotDeviceUpstreamServer { Router router = Router.router(vertx); router.route().handler(BodyHandler.create()); // 处理 Body router.post(IotDevicePropertyReportVertxHandler.PATH) - .handler(new IotDevicePropertyReportVertxHandler(deviceUpstreamApi)); // 处理设备属性上报 + .handler(new IotDevicePropertyReportVertxHandler(deviceUpstreamApi)); // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java index 6bf600b14..c75a3a0d5 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java @@ -1,15 +1,15 @@ package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; import cn.hutool.core.util.IdUtil; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; -import io.vertx.ext.web.RequestBody; +import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -17,8 +17,13 @@ import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; import java.util.Map; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; + /** * IoT 设备属性上报的 Vert.x Handler + * + * @author haohao */ @RequiredArgsConstructor @Slf4j @@ -29,69 +34,43 @@ public class IotDevicePropertyReportVertxHandler implements Handler properties = (Map) body.getMap().get("properties"); + reportReqDTO = ((IotDevicePropertyReportReqDTO) + new IotDevicePropertyReportReqDTO().setRequestId(id) + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) + .setProductKey(productKey).setDeviceName(deviceName)) + .setProperties(properties); } catch (Exception e) { - log.error("[HttpVertxHandler] 请求数据解析失败", e); - ctx.response().setStatusCode(400) - .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(createResponseJson(400, null, null, - "请求数据不是合法的 JSON 格式: " + e.getMessage(), - "thing.event.property.post", "1.0").toString()); + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); return; } - String id = jsonData.getStr("id"); - try { - // 设备上线 + // 2. 设备上线 deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) - .setProductKey(productKey).setDeviceName(deviceName)) + .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName())) .setState(IotDeviceStateEnum.ONLINE.getState())); - // 属性上报 - deviceUpstreamApi.reportDeviceProperty(((IotDevicePropertyReportReqDTO) - new IotDevicePropertyReportReqDTO().setRequestId(IdUtil.fastSimpleUUID()) - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) - .setProductKey(productKey).setDeviceName(deviceName)) - .setProperties((Map) requestBody.asJsonObject().getMap().get("properties"))); - - ctx.response() - .setStatusCode(200) - .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(createResponseJson(200, new JSONObject(), id, "success", - "thing.event.property.post", "1.0").toString()); + // 3.1 属性上报 + CommonResult result = deviceUpstreamApi.reportDeviceProperty(reportReqDTO); + // 3.2 返回结果 + IotPluginCommonUtils.writeJson(routingContext, result); } catch (Exception e) { - log.error("[HttpVertxHandler] 上报属性数据失败", e); - ctx.response() - .setStatusCode(500) - .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(createResponseJson(500, new JSONObject(), id, - "The format of result is error!", - "thing.event.property.post", "1.0").toString()); + log.error("[handle][请求参数({}) 属性获取异常]", reportReqDTO, e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); } } - // TODO @芋艿:抽一个 IotPluginCommonResult 出来?等 mqtt、websocket 出来后,再考虑优化! - private JSONObject createResponseJson(int code, JSONObject data, String id, - String message, String method, String version) { - JSONObject res = new JSONObject(); - res.set("code", code); - res.set("data", data != null ? data : new JSONObject()); - res.set("id", id); - res.set("message", message); - res.set("method", method); - res.set("version", version); - return res; - } - } From a74459e94e10894ca09fe5e025eb7b78694cacf7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 31 Jan 2025 21:16:01 +0800 Subject: [PATCH 134/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E5=AE=9E=E7=8E=B0=20IotDeviceEve?= =?UTF-8?q?ntReportVertxHandler=20=E4=BA=8B=E4=BB=B6=E4=B8=8A=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../control/IotDeviceDownstreamService.java | 2 +- .../IotDeviceDownstreamServiceImpl.java | 2 +- .../control/IotDeviceUpstreamService.java | 2 +- .../control/IotDeviceUpstreamServiceImpl.java | 10 +-- .../upstream/IotDeviceUpstreamServer.java | 3 + .../IotDeviceEventReportVertxHandler.java | 75 +++++++++++++++++++ .../IotDevicePropertyReportVertxHandler.java | 6 +- 7 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java index a3079552d..6a27f84b1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceS import jakarta.validation.Valid; /** - * 设备下行 Service 接口 + * IoT 设备下行 Service 接口 * * 目的:服务端 -> 插件 -> 设备 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java index 7f341f57c..789e78efd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java @@ -35,7 +35,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DOWNSTREAM_FAILED; /** - * 设备下行 Service 实现类 + * IoT 设备下行 Service 实现类 * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java index 592fa7d1c..ef8f0dd24 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceS import jakarta.validation.Valid; /** - * 设备上行 Service 接口 + * IoT 设备上行 Service 接口 * * 目的:设备 -> 插件 -> 服务端 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index 6188d0b5d..b2aa6222a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -31,7 +31,7 @@ import java.util.Map; import java.util.Objects; /** - * 设备上行 Service 实现类 + * IoT 设备上行 Service 实现类 * * @author 芋道源码 */ @@ -123,11 +123,11 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { @Override public void reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { // 1.1 获得设备 - log.info("[reportDevicePropertyData][上报设备属性: {}]", reportReqDTO); + log.info("[reportDeviceProperty][上报设备属性: {}]", reportReqDTO); IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); if (device == null) { - log.error("[reportDevicePropertyData][设备({}/{})不存在]", + log.error("[reportDeviceProperty][设备({}/{})不存在]", reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); return; } @@ -145,11 +145,11 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { @Override public void reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { // 1.1 获得设备 - log.info("[reportDeviceEventData][上报设备事件: {}]", reportReqDTO); + log.info("[reportDeviceEvent][上报设备事件: {}]", reportReqDTO); IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); if (device == null) { - log.error("[reportDeviceEventData][设备({}/{})不存在]", + log.error("[reportDeviceEvent][设备({}/{})不存在]", reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); return; } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java index 87e6a6f85..0e4cebfe8 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.upstream; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.plugin.http.upstream.router.IotDeviceEventReportVertxHandler; import cn.iocoder.yudao.module.iot.plugin.http.upstream.router.IotDevicePropertyReportVertxHandler; import io.vertx.core.Vertx; import io.vertx.core.http.HttpServer; @@ -32,6 +33,8 @@ public class IotDeviceUpstreamServer { router.route().handler(BodyHandler.create()); // 处理 Body router.post(IotDevicePropertyReportVertxHandler.PATH) .handler(new IotDevicePropertyReportVertxHandler(deviceUpstreamApi)); + router.post(IotDeviceEventReportVertxHandler.PATH) + .handler(new IotDeviceEventReportVertxHandler(deviceUpstreamApi)); // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java new file mode 100644 index 000000000..4e0a2ef44 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; + +/** + * IoT 设备设备上报的 Vert.x Handler + */ +@RequiredArgsConstructor +@Slf4j +public class IotDeviceEventReportVertxHandler implements Handler { + + public static final String PATH = "/sys/:productKey/:deviceName/thing/event/:identifier/post"; + + private final IotDeviceUpstreamApi deviceUpstreamApi; + + @Override + @SuppressWarnings("unchecked") + public void handle(RoutingContext routingContext) { + // 1. 解析参数 + IotDeviceEventReportReqDTO reportReqDTO; + try { + String productKey = routingContext.pathParam("productKey"); + String deviceName = routingContext.pathParam("deviceName"); + String identifier = routingContext.pathParam("identifier"); + JsonObject body = routingContext.body().asJsonObject(); + String id = ObjUtil.defaultIfBlank(body.getString("id"), IdUtil.fastSimpleUUID()); + Map params = (Map) body.getMap().get("params"); + reportReqDTO = ((IotDeviceEventReportReqDTO) + new IotDeviceEventReportReqDTO().setRequestId(id) + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) + .setProductKey(productKey).setDeviceName(deviceName)) + .setIdentifier(identifier).setParams(params); + } catch (Exception e) { + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + return; + } + + try { + // 2. 设备上线 + deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) + new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) + .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName())) + .setState(IotDeviceStateEnum.ONLINE.getState())); + + // 3.1 属性上报 + CommonResult result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO); + // 3.2 返回结果 + IotPluginCommonUtils.writeJson(routingContext, result); + } catch (Exception e) { + log.error("[handle][请求参数({}) 时间上报异常]", reportReqDTO, e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java index c75a3a0d5..c22a6fe99 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java @@ -55,6 +55,10 @@ public class IotDevicePropertyReportVertxHandler implements Handler Date: Fri, 31 Jan 2025 21:51:06 +0800 Subject: [PATCH 135/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E4=BC=98=E5=8C=96=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=20common=20=E5=92=8C=20http=20=E7=9A=84=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 23 +++++---- .../yudao-spring-boot-starter-mybatis/pom.xml | 4 -- yudao-module-iot/yudao-module-iot-api/pom.xml | 7 --- yudao-module-iot/yudao-module-iot-biz/pom.xml | 15 +++--- .../mapper/plugininfo/PluginInfoMapper.xml | 12 ----- .../plugininstance/PluginInstanceMapper.xml | 12 ----- .../yudao-module-iot-plugin-common/pom.xml | 7 +++ .../IotPluginCommonAutoConfiguration.java | 40 +++++----------- .../config/IotPluginCommonProperties.java | 48 +++++++++++++++++++ .../downstream/IotDeviceDownstreamServer.java | 8 +++- .../IotPluginInstanceHeartbeatJob.java | 12 +++-- .../upstream/IotDeviceUpstreamClient.java | 14 +++--- .../IotPluginHttpAutoConfiguration.java | 15 ++---- .../http/config/IotPluginHttpProperties.java | 17 +++++++ .../upstream/IotDeviceUpstreamServer.java | 9 ++-- .../src/main/resources/application.yml | 16 +++---- 16 files changed, 142 insertions(+), 117 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininfo/PluginInfoMapper.xml delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonProperties.java rename yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/{heartbeta => heartbeat}/IotPluginInstanceHeartbeatJob.java (84%) create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpProperties.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index e7035871f..05d9aa2b9 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -600,39 +600,42 @@ - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - ${mqtt.version} - - org.pf4j pf4j-spring ${pf4j-spring.version} + + + org.slf4j + slf4j-log4j12 + + - + io.vertx vertx-core ${vertx.version} - io.vertx vertx-web ${vertx.version} - io.vertx vertx-mqtt ${vertx.version} + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + ${mqtt.version} + diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml index 2a14c88b8..1f3c9144b 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -63,10 +63,6 @@ opengauss-jdbc true - - com.taosdata.jdbc - taos-jdbcdriver - com.alibaba diff --git a/yudao-module-iot/yudao-module-iot-api/pom.xml b/yudao-module-iot/yudao-module-iot-api/pom.xml index ab492729c..4a31c9bf5 100644 --- a/yudao-module-iot/yudao-module-iot-api/pom.xml +++ b/yudao-module-iot/yudao-module-iot-api/pom.xml @@ -40,13 +40,6 @@ org.pf4j pf4j-spring - - - - org.slf4j - slf4j-log4j12 - - diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 1ac3f915a..cc3141939 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -52,6 +52,11 @@ yudao-spring-boot-starter-redis + + com.taosdata.jdbc + taos-jdbcdriver + + cn.iocoder.boot @@ -64,12 +69,13 @@ yudao-spring-boot-starter-excel - + io.vertx vertx-web + org.eclipse.paho org.eclipse.paho.client.mqttv3 @@ -78,13 +84,6 @@ org.pf4j pf4j-spring - - - - org.slf4j - slf4j-log4j12 - - diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininfo/PluginInfoMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininfo/PluginInfoMapper.xml deleted file mode 100644 index f24f7e14c..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininfo/PluginInfoMapper.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml deleted file mode 100644 index df38e85eb..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml index ccf010f24..1e5a69bfa 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml @@ -40,6 +40,13 @@ io.vertx vertx-web + + + + org.springframework.boot + spring-boot-starter-validation + true + diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java index 0e5c73b09..7e3d669f2 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java @@ -3,59 +3,43 @@ package cn.iocoder.yudao.module.iot.plugin.common.config; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamServer; -import cn.iocoder.yudao.module.iot.plugin.common.heartbeta.IotPluginInstanceHeartbeatJob; +import cn.iocoder.yudao.module.iot.plugin.common.heartbeat.IotPluginInstanceHeartbeatJob; import cn.iocoder.yudao.module.iot.plugin.common.upstream.IotDeviceUpstreamClient; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.client.RestTemplate; -import java.time.Duration; - /** * IoT 插件的通用自动配置类 * * @author haohao */ @AutoConfiguration +@EnableConfigurationProperties(IotPluginCommonProperties.class) @EnableScheduling // 开启定时任务,因为 IotPluginInstanceHeartbeatJob 是一个定时任务 public class IotPluginCommonAutoConfiguration { - // TODO @haohao:这个要不搞个配置类哈 - @Value("${iot.device-data.url}") - private String deviceDataUrl; - - /** - * 创建 RestTemplate 实例 - * - * @return RestTemplate 实例 - */ @Bean - public RestTemplate restTemplate() { - // 如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 + public RestTemplate restTemplate(IotPluginCommonProperties properties) { return new RestTemplateBuilder() - .connectTimeout(Duration.ofMillis(5000)) // 设置连接超时时间 - .readTimeout(Duration.ofMillis(5000)) // 设置读取超时时间 + .connectTimeout(properties.getUpstreamConnectTimeout()) + .readTimeout(properties.getUpstreamReadTimeout()) .build(); } - /** - * 创建 DeviceDataApi 实例 - * - * @param restTemplate RestTemplate 实例 - * @return DeviceDataApi 实例 - */ @Bean - public IotDeviceUpstreamApi deviceDataApi(RestTemplate restTemplate) { - return new IotDeviceUpstreamClient(restTemplate, deviceDataUrl); + public IotDeviceUpstreamApi deviceUpstreamApi(IotPluginCommonProperties properties, + RestTemplate restTemplate) { + return new IotDeviceUpstreamClient(properties, restTemplate); } @Bean(initMethod = "start", destroyMethod = "stop") - @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") - public IotDeviceDownstreamServer deviceDownstreamServer(IotDeviceDownstreamHandler deviceDownstreamHandler) { - return new IotDeviceDownstreamServer(deviceDownstreamHandler); + public IotDeviceDownstreamServer deviceDownstreamServer(IotPluginCommonProperties properties, + IotDeviceDownstreamHandler deviceDownstreamHandler) { + return new IotDeviceDownstreamServer(properties, deviceDownstreamHandler); } @Bean(initMethod = "init", destroyMethod = "stop") diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonProperties.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonProperties.java new file mode 100644 index 000000000..556786507 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonProperties.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.iot.plugin.common.config; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import java.time.Duration; + +@ConfigurationProperties(prefix = "yudao.iot.plugin.common") +@Validated +@Data +public class IotPluginCommonProperties { + + /** + * 上行连接超时的默认值 + */ + public static final Duration UPSTREAM_CONNECT_TIMEOUT_DEFAULT = Duration.ofSeconds(30); + /** + * 上行读取超时的默认值 + */ + public static final Duration UPSTREAM_READ_TIMEOUT_DEFAULT = Duration.ofSeconds(30); + + /** + * 下行端口 - 随机 + */ + public static final Integer DOWNSTREAM_PORT_RANDOM = 0; + + /** + * 上行 URL + */ + @NotEmpty(message = "上行 URL 不能为空") + private String upstreamUrl; + /** + * 上行连接超时 + */ + private Duration upstreamConnectTimeout = UPSTREAM_CONNECT_TIMEOUT_DEFAULT; + /** + * 上行读取超时 + */ + private Duration upstreamReadTimeout = UPSTREAM_READ_TIMEOUT_DEFAULT; + + /** + * 下行端口 + */ + private Integer downstreamPort = DOWNSTREAM_PORT_RANDOM; + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java index 4c45e972e..797d36d45 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream; +import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertyGetVertxHandler; import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertySetVertxHandler; import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceServiceInvokeVertxHandler; @@ -19,8 +20,11 @@ public class IotDeviceDownstreamServer { private final Vertx vertx; private final HttpServer server; + private final IotPluginCommonProperties properties; - public IotDeviceDownstreamServer(IotDeviceDownstreamHandler deviceDownstreamHandler) { + public IotDeviceDownstreamServer(IotPluginCommonProperties properties, + IotDeviceDownstreamHandler deviceDownstreamHandler) { + this.properties = properties; // 创建 Vertx 实例 this.vertx = Vertx.vertx(); // 创建 Router 实例 @@ -41,7 +45,7 @@ public class IotDeviceDownstreamServer { */ public void start() { log.info("[start][开始启动]"); - server.listen(0) // 通过 0 自动选择端口 + server.listen(properties.getDownstreamPort()) .toCompletionStage() .toCompletableFuture() .join(); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeta/IotPluginInstanceHeartbeatJob.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeat/IotPluginInstanceHeartbeatJob.java similarity index 84% rename from yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeta/IotPluginInstanceHeartbeatJob.java rename to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeat/IotPluginInstanceHeartbeatJob.java index fe0244bc9..238d34f98 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeta/IotPluginInstanceHeartbeatJob.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeat/IotPluginInstanceHeartbeatJob.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.plugin.common.heartbeta; +package cn.iocoder.yudao.module.iot.plugin.common.heartbeat; import cn.hutool.system.SystemUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInst import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamServer; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import java.util.concurrent.TimeUnit; @@ -17,6 +18,7 @@ import java.util.concurrent.TimeUnit; * 用于定时发送心跳给服务端 */ @RequiredArgsConstructor +@Slf4j public class IotPluginInstanceHeartbeatJob { private final IotDeviceUpstreamApi deviceUpstreamApi; @@ -24,22 +26,22 @@ public class IotPluginInstanceHeartbeatJob { public void init() { CommonResult result = deviceUpstreamApi.heartbeatPluginInstance(buildPluginInstanceHeartbeatReqDTO(true)); - // TODO @芋艿:结果的处理 + log.info("[init][上线结果:{})]", result); } public void stop() { CommonResult result = deviceUpstreamApi.heartbeatPluginInstance(buildPluginInstanceHeartbeatReqDTO(false)); - // TODO @芋艿:结果的处理 + log.info("[stop][下线结果:{})]", result); } @Scheduled(initialDelay = 3, fixedRate = 3, timeUnit = TimeUnit.MINUTES) // 3 分钟执行一次 public void execute() { CommonResult result = deviceUpstreamApi.heartbeatPluginInstance(buildPluginInstanceHeartbeatReqDTO(true)); - // TODO @芋艿:结果的处理 + log.info("[execute][心跳结果:{})]", result); } private IotPluginInstanceHeartbeatReqDTO buildPluginInstanceHeartbeatReqDTO(Boolean online) { - // TODO @芋艿:pluginKey 的获取??? + // TODO @haohao:pluginKey 的获取??? return new IotPluginInstanceHeartbeatReqDTO() .setPluginKey("yudao-module-iot-plugin-http").setProcessId(IotPluginCommonUtils.getProcessId()) .setHostIp(SystemUtil.getHostInfo().getAddress()).setDownstreamPort(deviceDownstreamServer.getPort()) diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java index c71606f62..f3934cb0d 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEven import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; +import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.client.RestTemplate; @@ -25,32 +26,31 @@ public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi { public static final String URL_PREFIX = "/rpc-api/iot/device/upstream"; - private final RestTemplate restTemplate; + private final IotPluginCommonProperties properties; - // TODO @芋艿:改个名字 - private final String deviceDataUrl; + private final RestTemplate restTemplate; @Override public CommonResult updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) { - String url = deviceDataUrl + URL_PREFIX + "/update-state"; + String url = properties.getUpstreamUrl() + URL_PREFIX + "/update-state"; return doPost(url, updateReqDTO); } @Override public CommonResult reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { - String url = deviceDataUrl + URL_PREFIX + "/report-event"; + String url = properties.getUpstreamUrl() + URL_PREFIX + "/report-event"; return doPost(url, reportReqDTO); } @Override public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { - String url = deviceDataUrl + URL_PREFIX + "/report-property"; + String url = properties.getUpstreamUrl() + URL_PREFIX + "/report-property"; return doPost(url, reportReqDTO); } @Override public CommonResult heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) { - String url = deviceDataUrl + URL_PREFIX + "/heartbeat-plugin-instance"; + String url = properties.getUpstreamUrl() + URL_PREFIX + "/heartbeat-plugin-instance"; return doPost(url, heartbeatReqDTO); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java index 4e402f91f..63e55f58f 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; import cn.iocoder.yudao.module.iot.plugin.http.downstream.IotDeviceDownstreamHandlerImpl; import cn.iocoder.yudao.module.iot.plugin.http.upstream.IotDeviceUpstreamServer; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -14,18 +14,13 @@ import org.springframework.context.annotation.Configuration; * @author haohao */ @Configuration +@EnableConfigurationProperties(IotPluginHttpProperties.class) public class IotPluginHttpAutoConfiguration { - // TODO @haohao:这个要不要搞个配置类,更容易维护; - /** - * 可在 application.yml 中配置,默认端口 8092 - */ - @Value("${plugin.http.server.port:8092}") - private Integer port; - @Bean(initMethod = "start", destroyMethod = "stop") - public IotDeviceUpstreamServer deviceUpstreamServer(IotDeviceUpstreamApi deviceUpstreamApi) { - return new IotDeviceUpstreamServer(port, deviceUpstreamApi); + public IotDeviceUpstreamServer deviceUpstreamServer(IotDeviceUpstreamApi deviceUpstreamApi, + IotPluginHttpProperties properties) { + return new IotDeviceUpstreamServer(properties, deviceUpstreamApi); } @Bean diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpProperties.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpProperties.java new file mode 100644 index 000000000..49dca8126 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpProperties.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.iot.plugin.http.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +@ConfigurationProperties(prefix = "yudao.iot.plugin.http") +@Validated +@Data +public class IotPluginHttpProperties { + + /** + * HTTP 服务端口 + */ + private Integer serverPort; + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java index 0e4cebfe8..42da951a2 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.upstream; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.plugin.http.config.IotPluginHttpProperties; import cn.iocoder.yudao.module.iot.plugin.http.upstream.router.IotDeviceEventReportVertxHandler; import cn.iocoder.yudao.module.iot.plugin.http.upstream.router.IotDevicePropertyReportVertxHandler; import io.vertx.core.Vertx; @@ -21,11 +22,11 @@ public class IotDeviceUpstreamServer { private final Vertx vertx; private final HttpServer server; - private final Integer port; + private final IotPluginHttpProperties properties; - public IotDeviceUpstreamServer(Integer port, + public IotDeviceUpstreamServer(IotPluginHttpProperties properties, IotDeviceUpstreamApi deviceUpstreamApi) { - this.port = port; + this.properties = properties; // 创建 Vertx 实例 this.vertx = Vertx.vertx(); // 创建 Router 实例 @@ -44,7 +45,7 @@ public class IotDeviceUpstreamServer { */ public void start() { log.info("[start][开始启动]"); - server.listen(port) + server.listen(properties.getServerPort()) .toCompletionStage() .toCompletableFuture() .join(); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml index f7f89e3e6..4afeb4f26 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml @@ -2,11 +2,11 @@ spring: application: name: yudao-module-iot-plugin-http -iot: - device-data: - url: http://127.0.0.1:48080 - -plugin: - http: - server: - port: 8092 \ No newline at end of file +yudao: + iot: + plugin: + common: + upstream-url: http://127.0.0.1:48080 + downstream-port: 8093 + http: + server-port: 8092 From 47c281d933ffe3ace90ba73e66dcfc1863b33fb8 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 31 Jan 2025 22:47:04 +0800 Subject: [PATCH 136/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E5=8E=BB=E9=99=A4=20Simulation?= =?UTF-8?q?=20=E5=85=B3=E9=94=AE=E5=AD=97=EF=BC=8C=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=9B=B4=E6=B8=85=E6=99=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceController.java | 26 +++++++++---------- ...qVO.java => IotDeviceDownstreamReqVO.java} | 4 +-- ...ReqVO.java => IotDeviceUpstreamReqVO.java} | 4 +-- .../dal/dataobject/device/IotDeviceDO.java | 7 +++++ .../control/IotDeviceDownstreamService.java | 6 ++--- .../IotDeviceDownstreamServiceImpl.java | 10 +++---- .../control/IotDeviceUpstreamService.java | 6 ++--- .../control/IotDeviceUpstreamServiceImpl.java | 4 +-- 8 files changed, 36 insertions(+), 31 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/{IotDeviceSimulationDownstreamReqVO.java => IotDeviceDownstreamReqVO.java} (87%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/{IotDeviceSimulationUpstreamReqVO.java => IotDeviceUpstreamReqVO.java} (87%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 6d73e0a45..24d426381 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -6,9 +6,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationDownstreamReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationUpstreamReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService; @@ -159,21 +159,19 @@ public class IotDeviceController { ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list); } - @PostMapping("/simulation-upstream") - @Operation(summary = "模拟设备上行") - @PreAuthorize("@ss.hasPermission('iot:device:simulation')") - public CommonResult simulationDeviceUpstream( - @Valid @RequestBody IotDeviceSimulationUpstreamReqVO upstreamReqVO) { - deviceUpstreamService.simulationDeviceUpstream(upstreamReqVO); + @PostMapping("/upstream") + @Operation(summary = "设备上行", description = "可用于设备模拟") + @PreAuthorize("@ss.hasPermission('iot:device:upstream')") + public CommonResult upstreamDevice(@Valid @RequestBody IotDeviceUpstreamReqVO upstreamReqVO) { + deviceUpstreamService.upstreamDevice(upstreamReqVO); return success(true); } - @PostMapping("/simulation-downstream") - @Operation(summary = "模拟设备下行") - @PreAuthorize("@ss.hasPermission('iot:device:simulation')") - public CommonResult simulationDownstreamDevice( - @Valid @RequestBody IotDeviceSimulationDownstreamReqVO downstreamReqVO) { - deviceDownstreamService.simulationDeviceDownstream(downstreamReqVO); + @PostMapping("/downstream") + @Operation(summary = "设备下行", description = "可用于设备模拟") + @PreAuthorize("@ss.hasPermission('iot:device:downstream')") + public CommonResult downstreamDevice(@Valid @RequestBody IotDeviceDownstreamReqVO downstreamReqVO) { + deviceDownstreamService.downstreamDevice(downstreamReqVO); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceSimulationDownstreamReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java similarity index 87% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceSimulationDownstreamReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java index 3d8c85551..eefaeffeb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceSimulationDownstreamReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java @@ -7,9 +7,9 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; -@Schema(description = "管理后台 - IoT 模拟设备下行 Request VO") // 服务调用、属性设置、属性获取等 +@Schema(description = "管理后台 - IoT 设备下行 Request VO") // 服务调用、属性设置、属性获取等 @Data -public class IotDeviceSimulationDownstreamReqVO { +public class IotDeviceDownstreamReqVO { @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") @NotNull(message = "设备编号不能为空") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceSimulationUpstreamReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java similarity index 87% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceSimulationUpstreamReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java index 43fc5bfa2..778d75bba 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceSimulationUpstreamReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java @@ -7,9 +7,9 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; -@Schema(description = "管理后台 - IoT 模拟设备上行 Request VO") // 属性上报、事件上报、状态变更等 +@Schema(description = "管理后台 - IoT 设备上行 Request VO") // 属性上报、事件上报、状态变更等 @Data -public class IotDeviceSimulationUpstreamReqVO { +public class IotDeviceUpstreamReqVO { @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") @NotNull(message = "设备编号不能为空") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index defb0c2f0..c146f8248 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -160,4 +160,11 @@ public class IotDeviceDO extends BaseDO { */ private String address; + /** + * 设备配置 + * + * JSON 格式,可下发给 device 进行自定义配置 + */ + private String config; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java index 6a27f84b1..433b15320 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.service.device.control; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationDownstreamReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; import jakarta.validation.Valid; /** @@ -13,10 +13,10 @@ import jakarta.validation.Valid; public interface IotDeviceDownstreamService { /** - * 模拟设备下行 + * 设备下行,可用于设备模拟 * * @param downstreamReqVO 设备下行请求 VO */ - void simulationDeviceDownstream(@Valid IotDeviceSimulationDownstreamReqVO downstreamReqVO); + void downstreamDevice(@Valid IotDeviceDownstreamReqVO downstreamReqVO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java index 789e78efd..4225e7b4c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java @@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceDo import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationDownstreamReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; @@ -56,7 +56,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic private IotDeviceProducer deviceProducer; @Override - public void simulationDeviceDownstream(IotDeviceSimulationDownstreamReqVO downstreamReqVO) { + public void downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) { // 校验设备是否存在 IotDeviceDO device = deviceService.validateDeviceExists(downstreamReqVO.getId()); // TODO 芋艿:父设备的处理 @@ -93,7 +93,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic * @param parentDevice 父设备 */ @SuppressWarnings("unchecked") - private void invokeDeviceService(IotDeviceSimulationDownstreamReqVO downstreamReqVO, + private void invokeDeviceService(IotDeviceDownstreamReqVO downstreamReqVO, IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数校验 if (!(downstreamReqVO.getData() instanceof Map)) { @@ -130,7 +130,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic * @param parentDevice 父设备 */ @SuppressWarnings("unchecked") - private void setDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO, + private void setDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数校验 if (!(downstreamReqVO.getData() instanceof Map)) { @@ -168,7 +168,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic * @param parentDevice 父设备 */ @SuppressWarnings("unchecked") - private void getDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO, + private void getDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数校验 if (!(downstreamReqVO.getData() instanceof List)) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java index ef8f0dd24..8bc0ffd69 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service.device.control; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationUpstreamReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; import jakarta.validation.Valid; /** @@ -16,11 +16,11 @@ import jakarta.validation.Valid; public interface IotDeviceUpstreamService { /** - * 模拟设备上行 + * 设备上行,可用于设备模拟 * * @param simulatorReqVO 设备上行请求 VO */ - void simulationDeviceUpstream(@Valid IotDeviceSimulationUpstreamReqVO simulatorReqVO); + void upstreamDevice(@Valid IotDeviceUpstreamReqVO simulatorReqVO); /** * 更新设备状态 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index b2aa6222a..9a1276ef4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEven import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceUpstreamAbstractReqDTO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationUpstreamReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; @@ -52,7 +52,7 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { @Override @SuppressWarnings("unchecked") - public void simulationDeviceUpstream(IotDeviceSimulationUpstreamReqVO simulatorReqVO) { + public void upstreamDevice(IotDeviceUpstreamReqVO simulatorReqVO) { // 1. 校验存在 IotDeviceDO device = deviceService.validateDeviceExists(simulatorReqVO.getId()); From f46a2fb011282f33b6e61224a1334e6bc04151e1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 31 Jan 2025 23:14:09 +0800 Subject: [PATCH 137/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20device=20?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E4=B8=8B=E5=8F=91=EF=BC=88=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=EF=BC=89=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../downstream/IotDeviceConfigSetReqDTO.java | 22 +++++++ .../IotDeviceMessageIdentifierEnum.java | 8 ++- .../device/IotDeviceMessageTypeEnum.java | 3 +- .../admin/device/IotDeviceController.http | 24 ++++++-- .../IotDeviceDownstreamServiceImpl.java | 59 +++++++++++++++--- .../IotDeviceDownstreamHandler.java | 9 +++ .../downstream/IotDeviceDownstreamServer.java | 3 + .../IotDeviceConfigSetVertxHandler.java | 61 +++++++++++++++++++ .../IotDeviceDownstreamHandlerImpl.java | 6 ++ 9 files changed, 175 insertions(+), 20 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceConfigSetReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceConfigSetReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceConfigSetReqDTO.java new file mode 100644 index 000000000..9624b671e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceConfigSetReqDTO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.Map; + +/** + * IoT 设备【配置】设置 Request DTO + * + * @author 芋道源码 + */ +@Data +public class IotDeviceConfigSetReqDTO extends IotDeviceDownstreamAbstractReqDTO { + + /** + * 配置 + */ + @NotNull(message = "配置不能为空") + private Map config; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java index 03bd7abec..c1a31d59b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java @@ -10,19 +10,21 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public enum IotDeviceMessageIdentifierEnum { - PROPERTY_GET("get"), // 下行 + PROPERTY_GET("get"), // 下行 TODO 芋艿:【讨论】貌似这个“上行”更合理?device 主动拉取配置。和 IotDevicePropertyGetReqDTO 一样的配置 PROPERTY_SET("set"), // 下行 PROPERTY_REPORT("report"), // 上行 STATE_ONLINE("online"), // 上行 STATE_OFFLINE("offline"), // 上行 - SERVICE_REPLY_SUFFIX("_reply"); // TODO 上行 or 下行 + CONFIG_GET("get"), // 上行 TODO 芋艿:【讨论】暂时没有上行的场景 + CONFIG_SET("set"), // 下行 + SERVICE_REPLY_SUFFIX("_reply"); // 芋艿:TODO 芋艿:【讨论】上行 or 下行 /** * 标志符 */ private final String identifier; -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java index 473b542ec..45b7596ce 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java @@ -16,7 +16,8 @@ public enum IotDeviceMessageTypeEnum implements ArrayValuable { STATE("state"), // 设备状态 PROPERTY("property"), // 设备属性 EVENT("event"), // 设备事件 - SERVICE("service"); // 设备服务 + SERVICE("service"), // 设备服务 + CONFIG("config"); // 设备配置 public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http index 34df37e93..042ad7e7f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http @@ -1,5 +1,5 @@ -### 请求 /iot/device/simulation-downstream 接口(服务调用) => 成功 -POST {{baseUrl}}/iot/device/simulation-downstream +### 请求 /iot/device/downstream 接口(服务调用) => 成功 +POST {{baseUrl}}/iot/device/downstream Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -13,8 +13,8 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/device/simulation-downstream 接口(属性设置) => 成功 -POST {{baseUrl}}/iot/device/simulation-downstream +### 请求 /iot/device/downstream 接口(属性设置) => 成功 +POST {{baseUrl}}/iot/device/downstream Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -28,8 +28,8 @@ Authorization: Bearer {{token}} } } -### 请求 /iot/device/simulation-downstream 接口(属性获取) => 成功 -POST {{baseUrl}}/iot/device/simulation-downstream +### 请求 /iot/device/downstream 接口(属性获取) => 成功 +POST {{baseUrl}}/iot/device/downstream Content-Type: application/json tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} @@ -39,4 +39,16 @@ Authorization: Bearer {{token}} "type": "property", "identifier": "get", "data": ["xx", "yy"] +} + +### 请求 /iot/device/downstream 接口(配置设置) => 成功 +POST {{baseUrl}}/iot/device/downstream +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "id": 25, + "type": "config", + "identifier": "set" } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java index 4225e7b4c..6db8a76ab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java @@ -5,10 +5,8 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceDownstreamAbstractReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; @@ -68,21 +66,27 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic return; } // 属性相关 - if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) + if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) { // 属性设置 if (Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())) { setDeviceProperty(downstreamReqVO, device, parentDevice); return; } - // 属性设置 - if (Objects.equals(downstreamReqVO.getIdentifier(), - IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) { - getDeviceProperty(downstreamReqVO, device, parentDevice); + // 属性设置 + if (Objects.equals(downstreamReqVO.getIdentifier(), + IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) { + getDeviceProperty(downstreamReqVO, device, parentDevice); + return; + } + } + // 配置下发 + if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.CONFIG.getType()) + && Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) { + setDeviceConfig(downstreamReqVO, device, parentDevice); return; } // TODO 芋艿:ota 升级 - // TODO 芋艿:配置下发 } /** @@ -198,6 +202,41 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic } } + /** + * 设置设备配置 + * + * @param downstreamReqVO 下行请求 + * @param device 设备 + * @param parentDevice 父设备 + */ + @SuppressWarnings({"unchecked", "unused"}) + private void setDeviceConfig(IotDeviceDownstreamReqVO downstreamReqVO, + IotDeviceDO device, IotDeviceDO parentDevice) { + // 1. 参数转换,无需校验 + Map config = JsonUtils.parseObject(device.getConfig(), Map.class); + + // 2. 发送请求 + String url = String.format( "sys/%s/%s/thing/service/config/set", + getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); + IotDeviceConfigSetReqDTO reqDTO = new IotDeviceConfigSetReqDTO() + .setConfig(config); + CommonResult result = requestPlugin(url, reqDTO, device); + + // 3. 发送设备消息 + IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) + .setType(IotDeviceMessageTypeEnum.CONFIG.getType()) + .setIdentifier(IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier()) + .setData(reqDTO.getConfig()); + sendDeviceMessage(message, device, result.getCode()); + + // 4. 如果不成功,抛出异常,提示用户 + if (result.isError()) { + log.error("[setDeviceConfig][设备({})配置下发失败,请求参数:({}),响应结果:({})]", + device.getDeviceKey(), reqDTO, result); + throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); + } + } + /** * 请求插件 * diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java index 127332cc7..62d72785d 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; @@ -38,4 +39,12 @@ public interface IotDeviceDownstreamHandler { */ CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO); + /** + * 设置设备配置 + * + * @param setReqDTO 设置设备配置的请求 + * @return 是否成功 + */ + CommonResult setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO); + } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java index 797d36d45..6b08dba00 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream; import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceConfigSetVertxHandler; import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertyGetVertxHandler; import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertySetVertxHandler; import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceServiceInvokeVertxHandler; @@ -36,6 +37,8 @@ public class IotDeviceDownstreamServer { .handler(new IotDevicePropertySetVertxHandler(deviceDownstreamHandler)); router.post(IotDevicePropertyGetVertxHandler.PATH) .handler(new IotDevicePropertyGetVertxHandler(deviceDownstreamHandler)); + router.post(IotDeviceConfigSetVertxHandler.PATH) + .handler(new IotDeviceConfigSetVertxHandler(deviceDownstreamHandler)); // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java new file mode 100644 index 000000000..337db248f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; + +/** + * IOT 设备配置设置 Vertx Handler + * + * 芋道源码 + */ +@Slf4j +@RequiredArgsConstructor +public class IotDeviceConfigSetVertxHandler implements Handler { + + public static final String PATH = "/sys/:productKey/:deviceName/thing/service/config/set"; + + private final IotDeviceDownstreamHandler deviceDownstreamHandler; + + @Override + @SuppressWarnings("unchecked") + public void handle(RoutingContext routingContext) { + // 1. 解析参数 + IotDeviceConfigSetReqDTO reqDTO; + try { + String productKey = routingContext.pathParam("productKey"); + String deviceName = routingContext.pathParam("deviceName"); + JsonObject body = routingContext.body().asJsonObject(); + String requestId = body.getString("requestId"); + Map config = (Map) body.getMap().get("config"); + reqDTO = ((IotDeviceConfigSetReqDTO) new IotDeviceConfigSetReqDTO() + .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName)) + .setConfig(config); + } catch (Exception e) { + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + return; + } + + // 2. 调用处理器 + try { + CommonResult result = deviceDownstreamHandler.setDeviceConfig(reqDTO); + IotPluginCommonUtils.writeJson(routingContext, result); + } catch (Exception e) { + log.error("[handle][请求参数({}) 配置设置异常]", reqDTO, e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java index b70052530..3c86ad6d2 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.downstream; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; @@ -33,4 +34,9 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性"); } + @Override + public CommonResult setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO) { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性"); + } + } From 06749a18fcd8a1b5e81a7b0352eb1c5b4efef2b4 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Feb 2025 20:35:41 +0800 Subject: [PATCH 138/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=E8=A7=84?= =?UTF-8?q?=E5=88=99=E5=BC=95=E6=93=8E=E7=9A=84=20IotRuleSceneDO=20?= =?UTF-8?q?=E5=9C=BA=E6=99=AF=E8=81=94=E5=8A=A8=E7=9A=84=E5=AE=9E=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotDeviceMessageIdentifierEnum.java | 1 + .../dal/dataobject/rule/IotRuleSceneDO.java | 236 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java index c1a31d59b..8f6270c7b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java @@ -20,6 +20,7 @@ public enum IotDeviceMessageIdentifierEnum { CONFIG_GET("get"), // 上行 TODO 芋艿:【讨论】暂时没有上行的场景 CONFIG_SET("set"), // 下行 + SERVICE_INVOKE("${identifier}"), // 下行 SERVICE_REPLY_SUFFIX("_reply"); // 芋艿:TODO 芋艿:【讨论】上行 or 下行 /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java new file mode 100644 index 000000000..91b62bca6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -0,0 +1,236 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.rule; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; +import java.util.Map; + +/** + * IoT 场景联动 DO + * + * @author 芋道源码 + */ +@TableName("iot_rule_scene") +@KeySequence("iot_rule_scene_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotRuleSceneDO extends BaseDO { + + /** + * 场景编号 + */ + @TableId + private Long id; + /** + * 场景名称 + */ + private String name; + /** + * 场景描述 + */ + private String description; + /** + * 场景状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + + /** + * 触发器数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List triggers; + + /** + * 执行器数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List actuators; + + /** + * 触发器 + */ + @Data + public static class Trigger { + + /** + * 触发类型 + * + * TODO @芋艿:device、job + */ + private Integer type; + + /** + * 产品标识 + * + * 关联 {@link IotProductDO#getProductKey()} + */ + private String productKey; + /** + * 设备名称数组 + * + * 关联 {@link IotDeviceDO#getDeviceName()} + */ + private List deviceNames; + + /** + * 触发条件数组 + * + * TODO @芋艿:注释说明 + */ + private List conditions; + + /** + * CRON 表达式 + * + * TODO @芋艿:注释说明 + */ + private String cronExpression; + + } + + /** + * 触发条件 + */ + @Data + public static class TriggerCondition { + + /** + * 消息类型 + * + * 枚举 {@link IotDeviceMessageTypeEnum} + */ + private String type; + /** + * 消息标识符 + * + * 枚举 {@link IotDeviceMessageIdentifierEnum} + */ + private String identifier; + + /** + * 参数数组 + */ + private List parameters; + + } + + /** + * 触发条件参数 + */ + @Data + public static class TriggerConditionParameter { + + /** + * 标识符(属性、事件、服务) + * + * 关联 {@link IotThingModelDO#getIdentifier()} + */ + private String identifier; + + /** + * 操作符 + * + * TODO 芋艿:枚举 + */ + private String operator; + + /** + * 值 + */ + private String value; + + } + + /** + * 执行器 + */ + @Data + public static class Actuator { + + /** + * 执行类型 + * + * TODO @芋艿:control、alert、webhook(待定) + */ + private Integer type; + + /** + * 产品标识 + * + * 关联 {@link IotProductDO#getProductKey()} + */ + private String productKey; + /** + * 设备名称数组 + * + * 关联 {@link IotDeviceDO#getDeviceName()} + */ + private List deviceNames; + + /** + * 控制数组 + * + * TODO 芋艿:类型的情况下 + */ + private List controls; + + /** + * 数据桥接编号 + * + * TODO 芋艿:暂定! + * TODO 芋艿:关联 + */ + private Long bridgeId; + + } + + /** + * 执行器控制 + */ + @Data + public static class ActuatorControl { + + /** + * 消息类型 + * + * 枚举 {@link IotDeviceMessageTypeEnum#PROPERTY}、{@link IotDeviceMessageTypeEnum#SERVICE} + */ + private Integer type; + /** + * 消息标识符 + * + * 枚举 {@link IotDeviceMessageIdentifierEnum} + * + * 1. 属性设置:对应 {@link IotDeviceMessageIdentifierEnum#PROPERTY_SET} + * 2. 服务调用:对应 {@link IotDeviceMessageIdentifierEnum#SERVICE_INVOKE} + */ + private String identifier; + + /** + * 具体数据 + * + * 1. 属性设置:在 {@link #type} 是 {@link IotDeviceMessageTypeEnum#PROPERTY} 时,对应 properties + * 2. 服务调用:在 {@link #type} 是 {@link IotDeviceMessageTypeEnum#SERVICE} 时,对应 params + */ + private Map data; + + } + +} From a4be3bb84d0a24169f085a643edbd24eedb35aa5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 2 Feb 2025 19:44:38 +0800 Subject: [PATCH 139/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20IotRuleScene?= =?UTF-8?q?MessageHandler=20=E5=A4=84=E7=90=86=E8=A7=84=E5=88=99=E5=9C=BA?= =?UTF-8?q?=E6=99=AF=EF=BC=8C=E5=B0=9D=E8=AF=95=E5=9F=BA=E4=BA=8E=20Spring?= =?UTF-8?q?=20El=20=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=AE=9E=E7=8E=B0=E5=88=9D?= =?UTF-8?q?=E6=AD=A5=E8=AE=A1=E7=AE=97=EF=BC=88=E9=83=A8=E5=88=86=E5=9C=BA?= =?UTF-8?q?=E6=99=AF=EF=BC=89=20trigger=20=E6=9D=A1=E4=BB=B6=E5=8C=B9?= =?UTF-8?q?=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...TriggerConditionParameterOperatorEnum.java | 51 +++++ .../rule/IotRuleSceneTriggerTypeEnum.java | 30 +++ .../dal/dataobject/rule/IotRuleSceneDO.java | 12 +- .../dal/mysql/rule/IotRuleSceneMapper.java | 10 + .../rule/IotRuleSceneMessageHandler.java | 30 +++ .../iot/service/rule/IotRuleSceneService.java | 31 +++ .../service/rule/IotRuleSceneServiceImpl.java | 212 ++++++++++++++++++ 7 files changed, 372 insertions(+), 4 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java new file mode 100644 index 000000000..f1a78cf31 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * Iot 场景触发条件参数的操作符枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayValuable { + + EQUALS("=", "%s == %s"), + NOT_EQUALS("!=", "%s != %s"), + + GREATER_THAN(">", "%s > %s"), + GREATER_THAN_OR_EQUALS(">=", "%s >= %s"), + + LESS_THAN("<", "%s < %s"), + LESS_THAN_OR_EQUALS("<=", "%s <= %s"), + + IN("in", "%s in { %s }"), + NOT_IN("not in", "%s not in { %s }"), + + BETWEEN("between", "(%s >= %s) && (%s <= %s)"), + NOT_BETWEEN("not between", "!(%s between %s and %s)"), + + LIKE("like", "%s like %s"), // 字符串匹配 + NOT_NULL("not null", ""); // 非空 + + private final String operator; + private final String springExpression; + + public static final String[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerConditionParameterOperatorEnum::getOperator).toArray(String[]::new); + + public static IotRuleSceneTriggerConditionParameterOperatorEnum operatorOf(String operator) { + return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values()); + } + + @Override + public String[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java new file mode 100644 index 000000000..509b9a603 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * Iot 场景流转的触发类型枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotRuleSceneTriggerTypeEnum implements ArrayValuable { + + DEVICE(1), // 设备触发 + TIMER(2); // 定时触发 + + private final Integer type; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerTypeEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index 91b62bca6..aa6c31425 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -17,7 +18,7 @@ import java.util.List; import java.util.Map; /** - * IoT 场景联动 DO + * IoT 规则场景(场景联动) DO * * @author 芋道源码 */ @@ -72,7 +73,7 @@ public class IotRuleSceneDO extends BaseDO { /** * 触发类型 * - * TODO @芋艿:device、job + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum} */ private Integer type; @@ -147,12 +148,15 @@ public class IotRuleSceneDO extends BaseDO { /** * 操作符 * - * TODO 芋艿:枚举 + * 枚举 {@link IotRuleSceneTriggerConditionParameterOperatorEnum} */ private String operator; /** - * 值 + * 比较值 + * + * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 + * 例如说,{@link IotRuleSceneTriggerConditionParameterOperatorEnum#IN}、{@link IotRuleSceneTriggerConditionParameterOperatorEnum#BETWEEN} */ private String value; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java new file mode 100644 index 000000000..e5e069a0c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.rule; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface IotRuleSceneMapper extends BaseMapperX { + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java new file mode 100644 index 000000000..bdd148ec0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.rule; + +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +/** + * 针对 {@link IotDeviceMessage} 的消费者,处理规则场景 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class IotRuleSceneMessageHandler { + + @Resource + private IotRuleSceneService ruleSceneService; + + @EventListener + @Async + public void onMessage(IotDeviceMessage message) { + log.info("[onMessage][消息内容({})]", message); + ruleSceneService.executeRuleScene(message); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java new file mode 100644 index 000000000..d1ebfd4f1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.iot.service.rule; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; + +import java.util.List; + +/** + * IoT 规则场景 Service 接口 + * + * @author 芋道源码 + */ +public interface IotRuleSceneService { + + /** + * 【缓存】获得指定设备的场景列表 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 场景列表 + */ + List getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName); + + /** + * 执行规则场景 + * + * @param message 消息 + */ + void executeRuleScene(IotDeviceMessage message); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java new file mode 100644 index 000000000..0d8d0cddd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java @@ -0,0 +1,212 @@ +package cn.iocoder.yudao.module.iot.service.rule; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.text.CharPool; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; + +/** + * IoT 规则场景 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class IotRuleSceneServiceImpl implements IotRuleSceneService { + + @Resource + private IotRuleSceneMapper ruleSceneMapper; + + // TODO 芋艿,缓存待实现 + @Override + @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 + public List getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { + if (true) { + IotRuleSceneDO ruleScene01 = new IotRuleSceneDO(); + ruleScene01.setTriggers(CollUtil.newArrayList()); + IotRuleSceneDO.Trigger trigger01 = new IotRuleSceneDO.Trigger(); + trigger01.setType(IotRuleSceneTriggerTypeEnum.DEVICE.getType()); + trigger01.setConditions(CollUtil.newArrayList()); + IotRuleSceneDO.TriggerCondition condition01 = new IotRuleSceneDO.TriggerCondition(); + condition01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); + condition01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier()); + condition01.setParameters(CollUtil.newArrayList()); + IotRuleSceneDO.TriggerConditionParameter parameter011 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter011.setIdentifier("width"); + parameter011.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator()); + parameter011.setValue("1"); + condition01.getParameters().add(parameter011); + IotRuleSceneDO.TriggerConditionParameter parameter012 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter012.setIdentifier("width"); + parameter012.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS.getOperator()); + parameter012.setValue("2"); + condition01.getParameters().add(parameter012); + IotRuleSceneDO.TriggerConditionParameter parameter013 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter013.setIdentifier("width"); + parameter013.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN.getOperator()); + parameter013.setValue("0"); + condition01.getParameters().add(parameter013); + IotRuleSceneDO.TriggerConditionParameter parameter014 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter014.setIdentifier("width"); + parameter014.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator()); + parameter014.setValue("0"); + condition01.getParameters().add(parameter014); + IotRuleSceneDO.TriggerConditionParameter parameter015 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter015.setIdentifier("width"); + parameter015.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN.getOperator()); + parameter015.setValue("2"); + condition01.getParameters().add(parameter015); + IotRuleSceneDO.TriggerConditionParameter parameter016 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter016.setIdentifier("width"); + parameter016.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS.getOperator()); + parameter016.setValue("2"); + condition01.getParameters().add(parameter016); + IotRuleSceneDO.TriggerConditionParameter parameter017 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter017.setIdentifier("width"); + parameter017.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.IN.getOperator()); + parameter017.setValue("1,2,3"); + condition01.getParameters().add(parameter017); + IotRuleSceneDO.TriggerConditionParameter parameter018 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter018.setIdentifier("width"); + parameter018.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_IN.getOperator()); + parameter018.setValue("0,2,3"); + condition01.getParameters().add(parameter018); + IotRuleSceneDO.TriggerConditionParameter parameter019 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter019.setIdentifier("width"); + parameter019.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN.getOperator()); + parameter019.setValue("1,3"); + condition01.getParameters().add(parameter019); + IotRuleSceneDO.TriggerConditionParameter parameter020 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter020.setIdentifier("width"); + parameter020.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN.getOperator()); + parameter020.setValue("2,3"); + condition01.getParameters().add(parameter020); + trigger01.getConditions().add(condition01); + ruleScene01.getTriggers().add(trigger01); + + return ListUtil.toList(ruleScene01); + } + + List list = ruleSceneMapper.selectList(); + // TODO @芋艿:需要考虑开启状态 + return filterList(list, ruleScene -> { + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { + if (ObjUtil.notEqual(trigger.getProductKey(), productKey)) { + continue; + } + if (CollUtil.isEmpty(trigger.getDeviceNames()) // 无设备名称限制 + || trigger.getDeviceNames().contains(deviceName)) { // 包含设备名称 + return true; + } + } + return false; + }); + } + + @Override + public void executeRuleScene(IotDeviceMessage message) { + // 1. 获得设备匹配的规则场景 + List ruleScenes = getMatchedRuleSceneList(message); + if (CollUtil.isEmpty(ruleScenes)) { + return; + } + } + + /** + * 获得匹配的规则场景列表 + * + * @param message 设备消息 + * @return 规则场景列表 + */ + @SuppressWarnings("unchecked") + private List getMatchedRuleSceneList(IotDeviceMessage message) { + // 1. 匹配设备 + // TODO @芋艿:可能需要 getSelf(); 缓存 + List ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache( + message.getProductKey(), message.getDeviceName()); + if (CollUtil.isEmpty(ruleScenes)) { + return ruleScenes; + } + + // 2. 匹配 trigger 触发器的条件 + return filterList(ruleScenes, ruleScene -> { + for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { + // 非设备触发,不匹配 + if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) { + return false; + } + // TODO 芋艿:产品、设备的匹配,要不要这里在做一次???貌似和 1. 部分重复了 + // 条件为空,说明没有匹配的条件,因此不匹配 + if (CollUtil.isEmpty(trigger.getConditions())) { + return false; + } + IotRuleSceneDO.TriggerCondition found = CollUtil.findOne(trigger.getConditions(), condition -> { + if (ObjUtil.notEqual(message.getType(), condition.getType()) + || ObjUtil.notEqual(message.getIdentifier(), condition.getIdentifier())) { + return false; + } + // TODO @芋艿:设备上线,需要测试下。 + for (IotRuleSceneDO.TriggerConditionParameter parameter : condition.getParameters()) { + // 计算是否匹配 + IotRuleSceneTriggerConditionParameterOperatorEnum operator = + IotRuleSceneTriggerConditionParameterOperatorEnum.operatorOf(parameter.getOperator()); + if (operator == null) { + log.error("[getMatchedRuleSceneList][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", + ruleScene.getId(), trigger, parameter.getOperator()); + return false; + } + Object messageValue = ((Map) message.getData()).get(parameter.getIdentifier()); + if (messageValue == null) { + return false; + } + String springExpression; + if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN, + IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN)) { + String[] parameterValues = StrUtil.splitToArray(parameter.getValue(), CharPool.COMMA); + springExpression = String.format(operator.getSpringExpression(), messageValue, parameterValues[0], + messageValue, parameterValues[1]); + } else { + springExpression = String.format(operator.getSpringExpression(), messageValue, parameter.getValue()); + } + // TODO @芋艿:【需优化】需要考虑 struct、时间等参数的比较 + try { + System.out.println(SpringExpressionUtils.parseExpression(springExpression)); + } catch (Exception e) { + log.error("[getMatchedRuleSceneList][消息({}) 规则场景编号({}) 的触发器({}) 的匹配表达式({}) 计算异常]", + message, ruleScene.getId(), trigger, springExpression, e); + } + } + return true; + }); + if (found == null) { + return false; + } + log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger); + return true; + } + return false; + }); + } + +} From 910bb6ca3c06eeae4d97b665ca61991722013bb0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 2 Feb 2025 22:08:34 +0800 Subject: [PATCH 140/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=AE=8C=E5=96=84=20IotRuleScene?= =?UTF-8?q?ServiceImpl=20=E7=9A=84=E8=A7=84=E5=88=99=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=EF=BC=8CisTriggerConditionParameterMatched?= =?UTF-8?q?=20=E5=87=BD=E6=95=B0=E6=9C=89=E7=82=B9=E9=95=BF=EF=BC=8C=3D=20?= =?UTF-8?q?=3D=20=E6=8D=89=E6=91=B8=E5=92=8B=E4=BC=98=E5=8C=96=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/number/NumberUtils.java | 14 ++ .../util/spring/SpringExpressionUtils.java | 14 ++ ...TriggerConditionParameterOperatorEnum.java | 37 +++-- .../service/rule/IotRuleSceneServiceImpl.java | 138 +++++++++++++----- 4 files changed, 153 insertions(+), 50 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java index c928e2fcf..c2787f46f 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.framework.common.util.number; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import java.math.BigDecimal; +import java.util.List; /** * 数字的工具类,补全 {@link cn.hutool.core.util.NumberUtil} 的功能 @@ -20,6 +22,18 @@ public class NumberUtils { return StrUtil.isNotEmpty(str) ? Integer.valueOf(str) : null; } + public static boolean isAllNumber(List values) { + if (CollUtil.isEmpty(values)) { + return false; + } + for (String value : values) { + if (!NumberUtil.isNumber(value)) { + return false; + } + } + return true; + } + /** * 通过经纬度获取地球上两点之间的距离 * diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java index 069e89db3..abb1cece8 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java @@ -97,12 +97,26 @@ public class SpringExpressionUtils { * @return 执行界面 */ public static Object parseExpression(String expressionString) { + return parseExpression(expressionString, null); + } + + /** + * 从 Bean 工厂,解析 EL 表达式的结果 + * + * @param expressionString EL 表达式 + * @param variables 变量 + * @return 执行界面 + */ + public static Object parseExpression(String expressionString, Map variables) { if (StrUtil.isBlank(expressionString)) { return null; } Expression expression = EXPRESSION_PARSER.parseExpression(expressionString); StandardEvaluationContext context = new StandardEvaluationContext(); context.setBeanResolver(new BeanFactoryResolver(SpringUtil.getApplicationContext())); + if (MapUtil.isNotEmpty(variables)) { + context.setVariables(variables); + } return expression.getValue(context); } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java index f1a78cf31..1aac8c237 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java @@ -16,29 +16,42 @@ import java.util.Arrays; @Getter public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayValuable { - EQUALS("=", "%s == %s"), - NOT_EQUALS("!=", "%s != %s"), + EQUALS("=", "#source == #value"), + NOT_EQUALS("!=", "!(#source == #value)"), - GREATER_THAN(">", "%s > %s"), - GREATER_THAN_OR_EQUALS(">=", "%s >= %s"), + GREATER_THAN(">", "#source > #value"), + GREATER_THAN_OR_EQUALS(">=", "#source >= #value"), - LESS_THAN("<", "%s < %s"), - LESS_THAN_OR_EQUALS("<=", "%s <= %s"), + LESS_THAN("<", "#source < #value"), + LESS_THAN_OR_EQUALS("<=", "#source <= #value"), - IN("in", "%s in { %s }"), - NOT_IN("not in", "%s not in { %s }"), + IN("in", "#values.contains(#source)"), + NOT_IN("not in", "!(#values.contains(#source))"), - BETWEEN("between", "(%s >= %s) && (%s <= %s)"), - NOT_BETWEEN("not between", "!(%s between %s and %s)"), + BETWEEN("between", "(#source >= #values.get(0)) && (#source <= #values.get(1))"), + NOT_BETWEEN("not between", "(#source < #values.get(0)) || (#source > #values.get(1))"), - LIKE("like", "%s like %s"), // 字符串匹配 - NOT_NULL("not null", ""); // 非空 + LIKE("like", "#source.contains(#value)"), // 字符串匹配 + NOT_NULL("not null", "#source != null && #source.length() > 0"); // 非空 private final String operator; private final String springExpression; public static final String[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerConditionParameterOperatorEnum::getOperator).toArray(String[]::new); + /** + * Spring 表达式 - 原始值 + */ + public static final String SPRING_EXPRESSION_SOURCE = "source"; + /** + * Spring 表达式 - 目标值 + */ + public static final String SPRING_EXPRESSION_VALUE = "value"; + /** + * Spring 表达式 - 目标值数组 + */ + public static final String SPRING_EXPRESSION_VALUE_List = "values"; + public static IotRuleSceneTriggerConditionParameterOperatorEnum operatorOf(String operator) { return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values()); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java index 0d8d0cddd..90f893ef2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java @@ -2,9 +2,12 @@ package cn.iocoder.yudao.module.iot.service.rule; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.text.CharPool; +import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; @@ -20,9 +23,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.HashMap; import java.util.List; import java.util.Map; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; /** @@ -48,10 +53,16 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { IotRuleSceneDO.Trigger trigger01 = new IotRuleSceneDO.Trigger(); trigger01.setType(IotRuleSceneTriggerTypeEnum.DEVICE.getType()); trigger01.setConditions(CollUtil.newArrayList()); + // 属性 IotRuleSceneDO.TriggerCondition condition01 = new IotRuleSceneDO.TriggerCondition(); condition01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); condition01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier()); condition01.setParameters(CollUtil.newArrayList()); +// IotRuleSceneDO.TriggerConditionParameter parameter010 = new IotRuleSceneDO.TriggerConditionParameter(); +// parameter010.setIdentifier("width"); +// parameter010.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator()); +// parameter010.setValue("abc"); +// condition01.getParameters().add(parameter010); IotRuleSceneDO.TriggerConditionParameter parameter011 = new IotRuleSceneDO.TriggerConditionParameter(); parameter011.setIdentifier("width"); parameter011.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator()); @@ -103,8 +114,23 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { parameter020.setValue("2,3"); condition01.getParameters().add(parameter020); trigger01.getConditions().add(condition01); + // 状态 + IotRuleSceneDO.TriggerCondition condition02 = new IotRuleSceneDO.TriggerCondition(); + condition02.setType(IotDeviceMessageTypeEnum.STATE.getType()); + condition02.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier()); + condition02.setParameters(CollUtil.newArrayList()); + trigger01.getConditions().add(condition02); + // TODO 芋艿:事件 + IotRuleSceneDO.TriggerCondition condition03 = new IotRuleSceneDO.TriggerCondition(); + condition03.setType(IotDeviceMessageTypeEnum.EVENT.getType()); + condition03.setIdentifier("xxx"); + condition03.setParameters(CollUtil.newArrayList()); + IotRuleSceneDO.TriggerConditionParameter parameter030 = new IotRuleSceneDO.TriggerConditionParameter(); + parameter030.setIdentifier("width"); + parameter030.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator()); + parameter030.setValue("1"); + trigger01.getConditions().add(condition03); ruleScene01.getTriggers().add(trigger01); - return ListUtil.toList(ruleScene01); } @@ -139,7 +165,6 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { * @param message 设备消息 * @return 规则场景列表 */ - @SuppressWarnings("unchecked") private List getMatchedRuleSceneList(IotDeviceMessage message) { // 1. 匹配设备 // TODO @芋艿:可能需要 getSelf(); 缓存 @@ -152,54 +177,27 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { // 2. 匹配 trigger 触发器的条件 return filterList(ruleScenes, ruleScene -> { for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { - // 非设备触发,不匹配 + // 2.1 非设备触发,不匹配 if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) { return false; } // TODO 芋艿:产品、设备的匹配,要不要这里在做一次???貌似和 1. 部分重复了 - // 条件为空,说明没有匹配的条件,因此不匹配 + // 2.2 条件为空,说明没有匹配的条件,因此不匹配 if (CollUtil.isEmpty(trigger.getConditions())) { return false; } - IotRuleSceneDO.TriggerCondition found = CollUtil.findOne(trigger.getConditions(), condition -> { + // 2.3 多个条件,只需要满足一个即可 + IotRuleSceneDO.TriggerCondition matchedCondition = CollUtil.findOne(trigger.getConditions(), condition -> { if (ObjUtil.notEqual(message.getType(), condition.getType()) || ObjUtil.notEqual(message.getIdentifier(), condition.getIdentifier())) { return false; } - // TODO @芋艿:设备上线,需要测试下。 - for (IotRuleSceneDO.TriggerConditionParameter parameter : condition.getParameters()) { - // 计算是否匹配 - IotRuleSceneTriggerConditionParameterOperatorEnum operator = - IotRuleSceneTriggerConditionParameterOperatorEnum.operatorOf(parameter.getOperator()); - if (operator == null) { - log.error("[getMatchedRuleSceneList][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", - ruleScene.getId(), trigger, parameter.getOperator()); - return false; - } - Object messageValue = ((Map) message.getData()).get(parameter.getIdentifier()); - if (messageValue == null) { - return false; - } - String springExpression; - if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN, - IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN)) { - String[] parameterValues = StrUtil.splitToArray(parameter.getValue(), CharPool.COMMA); - springExpression = String.format(operator.getSpringExpression(), messageValue, parameterValues[0], - messageValue, parameterValues[1]); - } else { - springExpression = String.format(operator.getSpringExpression(), messageValue, parameter.getValue()); - } - // TODO @芋艿:【需优化】需要考虑 struct、时间等参数的比较 - try { - System.out.println(SpringExpressionUtils.parseExpression(springExpression)); - } catch (Exception e) { - log.error("[getMatchedRuleSceneList][消息({}) 规则场景编号({}) 的触发器({}) 的匹配表达式({}) 计算异常]", - message, ruleScene.getId(), trigger, springExpression, e); - } - } - return true; + // 多个条件参数,必须全部满足。所以,下面的逻辑就是找到一个不满足的条件参数 + IotRuleSceneDO.TriggerConditionParameter notMatchedParameter = CollUtil.findOne(condition.getParameters(), + parameter -> !isTriggerConditionParameterMatched(message, parameter, ruleScene, trigger)); + return notMatchedParameter == null; }); - if (found == null) { + if (matchedCondition == null) { return false; } log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger); @@ -209,4 +207,68 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { }); } + // TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。 + /** + * 判断触发器的条件参数是否匹配 + * + * @param message 设备消息 + * @param parameter 触发器条件参数 + * @param ruleScene 规则场景(用于日志,无其它作用) + * @param trigger 触发器(用于日志,无其它作用) + * @return 是否匹配 + */ + @SuppressWarnings({"unchecked", "DataFlowIssue"}) + private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter, + IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) { + // 计算是否匹配 + IotRuleSceneTriggerConditionParameterOperatorEnum operator = + IotRuleSceneTriggerConditionParameterOperatorEnum.operatorOf(parameter.getOperator()); + if (operator == null) { + log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", + ruleScene.getId(), trigger, parameter.getOperator()); + return false; + } + // TODO @芋艿:目前只支持方便转换成 string 的类型,如果是 struct、list 这种,需要考虑下 + String messageValue = MapUtil.getStr((Map) message.getData(), parameter.getIdentifier()); + if (messageValue == null) { + return false; + } + Map springExpressionVariables = new HashMap<>(); + try { + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue); + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE, parameter.getValue()); + if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.IN, + IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_IN)) { + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List, + StrUtil.split(parameter.getValue(), CharPool.COMMA)); + } else if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN, + IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN)) { + List parameterValues = StrUtil.splitTrim(parameter.getValue(), CharPool.COMMA); + if (NumberUtil.isNumber(messageValue) && NumberUtils.isAllNumber(parameterValues)) { // 特殊:解决数字的比较 + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, + NumberUtil.parseDouble(messageValue)); + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List, + convertList(parameterValues, NumberUtil::parseDouble)); + } else { + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List, parameterValues); + } + } else if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN, + IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS, + IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN, + IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS)) { + if (NumberUtil.isNumber(messageValue) && NumberUtil.isNumber(parameter.getValue())) { // 特殊:解决数字的比较 + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, + NumberUtil.parseDouble(messageValue)); + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE, + NumberUtil.parseDouble(parameter.getValue())); + } + } + return (Boolean) SpringExpressionUtils.parseExpression(operator.getSpringExpression(), springExpressionVariables); + } catch (Exception e) { + log.error("[isTriggerConditionParameterMatched][消息({}) 规则场景编号({}) 的触发器({}) 的匹配表达式({}/{}) 计算异常]", + message, ruleScene.getId(), trigger, operator, springExpressionVariables, e); + return false; + } + } + } From 4f84182dabd8baafe750036dc4b7eefb45491e2e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 2 Feb 2025 22:21:53 +0800 Subject: [PATCH 141/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E7=AE=80=E5=8C=96=20isTriggerCon?= =?UTF-8?q?ditionParameterMatched=20=E6=96=B9=E6=B3=95=EF=BC=8C=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E6=B3=A8=E9=87=8A=EF=BC=8C=E6=8F=90=E5=8D=87=E5=8F=AF?= =?UTF-8?q?=E8=AF=BB=E6=80=A7=EF=BC=88=E8=99=BD=E7=84=B6=E5=A4=9A=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E8=AE=A1=E7=AE=97=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/rule/IotRuleSceneServiceImpl.java | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java index 90f893ef2..3e120c648 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java @@ -220,7 +220,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @SuppressWarnings({"unchecked", "DataFlowIssue"}) private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter, IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) { - // 计算是否匹配 + // 1.1 校验操作符是否合法 IotRuleSceneTriggerConditionParameterOperatorEnum operator = IotRuleSceneTriggerConditionParameterOperatorEnum.operatorOf(parameter.getOperator()); if (operator == null) { @@ -228,41 +228,36 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { ruleScene.getId(), trigger, parameter.getOperator()); return false; } - // TODO @芋艿:目前只支持方便转换成 string 的类型,如果是 struct、list 这种,需要考虑下 + // 1.2 校验消息是否包含对应的值 String messageValue = MapUtil.getStr((Map) message.getData(), parameter.getIdentifier()); if (messageValue == null) { return false; } + + // 2.1 构建 Spring 表达式的变量 Map springExpressionVariables = new HashMap<>(); try { springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue); springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE, parameter.getValue()); - if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.IN, - IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_IN)) { - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List, - StrUtil.split(parameter.getValue(), CharPool.COMMA)); - } else if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN, - IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN)) { - List parameterValues = StrUtil.splitTrim(parameter.getValue(), CharPool.COMMA); - if (NumberUtil.isNumber(messageValue) && NumberUtils.isAllNumber(parameterValues)) { // 特殊:解决数字的比较 - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, - NumberUtil.parseDouble(messageValue)); - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List, - convertList(parameterValues, NumberUtil::parseDouble)); - } else { - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List, parameterValues); - } - } else if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN, + List parameterValues = StrUtil.splitTrim(parameter.getValue(), CharPool.COMMA); + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List, parameterValues); + // 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题! + if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN, + IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN, + IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN, IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS, IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN, - IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS)) { - if (NumberUtil.isNumber(messageValue) && NumberUtil.isNumber(parameter.getValue())) { // 特殊:解决数字的比较 - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, - NumberUtil.parseDouble(messageValue)); - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE, - NumberUtil.parseDouble(parameter.getValue())); - } + IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS) + && NumberUtil.isNumber(messageValue) + && NumberUtils.isAllNumber(parameterValues)) { + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, + NumberUtil.parseDouble(messageValue)); + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE, + NumberUtil.parseDouble(parameter.getValue())); + springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_List, + convertList(parameterValues, NumberUtil::parseDouble)); } + // 2.2 计算 Spring 表达式 return (Boolean) SpringExpressionUtils.parseExpression(operator.getSpringExpression(), springExpressionVariables); } catch (Exception e) { log.error("[isTriggerConditionParameterMatched][消息({}) 规则场景编号({}) 的触发器({}) 的匹配表达式({}/{}) 计算异常]", From 48cfcdadc13a642f28859912c7e808f0f9d80302 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 3 Feb 2025 12:05:13 +0800 Subject: [PATCH 142/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E5=AE=9E=E7=8E=B0=E8=A7=84?= =?UTF-8?q?=E5=88=99=20IotRuleSceneDeviceControlAction=20=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rule/IotRuleSceneActionTypeEnum.java | 31 +++++++ .../dal/dataobject/device/IotDeviceDO.java | 3 +- .../dal/dataobject/rule/IotRuleSceneDO.java | 79 +++++++++--------- .../iot/dal/redis/RedisKeyConstants.java | 14 ++-- .../rule/IotRuleSceneMessageHandler.java | 2 +- .../iot/mq/consumer/rule/package-info.java | 4 - .../iot/mq/message/IotDeviceMessage.java | 5 ++ .../service/device/IotDeviceServiceImpl.java | 13 ++- .../control/IotDeviceDownstreamService.java | 4 +- .../IotDeviceDownstreamServiceImpl.java | 40 ++++++---- .../control/IotDeviceUpstreamServiceImpl.java | 38 ++++----- .../iot/service/rule/IotRuleSceneService.java | 7 +- .../service/rule/IotRuleSceneServiceImpl.java | 80 ++++++++++++++++--- .../rule/action/IotRuleSceneAction.java | 29 +++++++ .../IotRuleSceneDeviceControlAction.java | 56 +++++++++++++ .../thingmodel/IotThingModelServiceImpl.java | 14 ++-- .../src/main/resources/application.yaml | 2 + 17 files changed, 306 insertions(+), 115 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java new file mode 100644 index 000000000..2dfb92f63 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * Iot 规则场景的触发类型枚举 + * + * 设备触发,定时触发 + */ +@RequiredArgsConstructor +@Getter +public enum IotRuleSceneActionTypeEnum implements ArrayValuable { + + DEVICE_CONTROL(1), // 设备执行 + ALERT(2), // 告警执行 + DATA_BRIDGE(3); // 桥接执行 + + private final Integer type; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneActionTypeEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index c146f8248..351e00185 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.type.LongSetTypeHandler; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; import com.baomidou.mybatisplus.annotation.KeySequence; @@ -27,7 +28,7 @@ import java.util.Set; @Builder @NoArgsConstructor @AllArgsConstructor -public class IotDeviceDO extends BaseDO { +public class IotDeviceDO extends TenantBaseDO { /** * 设备 ID,主键,自增 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index aa6c31425..88df1946e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -1,12 +1,14 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -30,7 +32,7 @@ import java.util.Map; @Builder @NoArgsConstructor @AllArgsConstructor -public class IotRuleSceneDO extends BaseDO { +public class IotRuleSceneDO extends TenantBaseDO { /** * 场景编号 @@ -56,24 +58,26 @@ public class IotRuleSceneDO extends BaseDO { * 触发器数组 */ @TableField(typeHandler = JacksonTypeHandler.class) - private List triggers; + private List triggers; + + // TODO @芋艿:需要调研下 https://help.aliyun.com/zh/iot/user-guide/scene-orchestration-1?spm=a2c4g.11186623.help-menu-30520.d_2_4_5_0.45413908fxCSVa /** * 执行器数组 */ @TableField(typeHandler = JacksonTypeHandler.class) - private List actuators; + private List actions; /** - * 触发器 + * 触发器配置 */ @Data - public static class Trigger { + public static class TriggerConfig { /** * 触发类型 * - * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum} + * 枚举 {@link IotRuleSceneTriggerTypeEnum} */ private Integer type; @@ -93,14 +97,15 @@ public class IotRuleSceneDO extends BaseDO { /** * 触发条件数组 * - * TODO @芋艿:注释说明 + * 当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 时,必填 + * 条件与条件之间,是“或”的关系 */ private List conditions; /** * CRON 表达式 * - * TODO @芋艿:注释说明 + * 当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#TIMER} 时,必填 */ private String cronExpression; @@ -127,6 +132,8 @@ public class IotRuleSceneDO extends BaseDO { /** * 参数数组 + * + * 参数与参数之间,是“或”的关系 */ private List parameters; @@ -163,18 +170,41 @@ public class IotRuleSceneDO extends BaseDO { } /** - * 执行器 + * 执行器配置 */ @Data - public static class Actuator { + public static class ActionConfig { /** * 执行类型 * - * TODO @芋艿:control、alert、webhook(待定) + * 枚举 {@link IotRuleSceneActionTypeEnum} */ private Integer type; + /** + * 设备控制 + * + * 当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DEVICE_CONTROL} 时,必填 + */ + private ActionDeviceControl deviceControl; + + /** + * 数据桥接编号 + * + * 当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE} 时,必填 + * TODO 芋艿:关联 + */ + private Long dataBridgeId; + + } + + /** + * 执行设备控制 + */ + @Data + public static class ActionDeviceControl { + /** * 产品标识 * @@ -188,35 +218,12 @@ public class IotRuleSceneDO extends BaseDO { */ private List deviceNames; - /** - * 控制数组 - * - * TODO 芋艿:类型的情况下 - */ - private List controls; - - /** - * 数据桥接编号 - * - * TODO 芋艿:暂定! - * TODO 芋艿:关联 - */ - private Long bridgeId; - - } - - /** - * 执行器控制 - */ - @Data - public static class ActuatorControl { - /** * 消息类型 * * 枚举 {@link IotDeviceMessageTypeEnum#PROPERTY}、{@link IotDeviceMessageTypeEnum#SERVICE} */ - private Integer type; + private String type; /** * 消息标识符 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java index 8145ff757..bd4d258f7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -17,7 +17,7 @@ public interface RedisKeyConstants { * HASH KEY:identifier 属性标识 * VALUE 数据类型:String(JSON) {@link IotDevicePropertyDO} */ - String DEVICE_PROPERTY = "device_property:%s"; + String DEVICE_PROPERTY = "iot:device_property:%s"; /** * 设备的最后上报时间,采用 ZSET 结构 @@ -25,23 +25,23 @@ public interface RedisKeyConstants { * KEY 格式:{deviceKey} * SCORE:上报时间 */ - String DEVICE_REPORT_TIMES = "device_report_times"; + String DEVICE_REPORT_TIMES = "iot:device_report_times"; /** - * 设备信息的数据缓存,使用 Spring Cache 操作 + * 设备信息的数据缓存,使用 Spring Cache 操作(忽略租户) * * KEY 格式:device_${productKey}_${deviceKey} * VALUE 数据类型:String(JSON) */ - String DEVICE = "device"; + String DEVICE = "iot:device"; /** - * 物模型的数据缓存,使用 Spring Cache 操作 + * 物模型的数据缓存,使用 Spring Cache 操作(忽略租户) * * KEY 格式:thing_model_${productKey} * VALUE 数据类型:String 数组(JSON),即 {@link cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO} 列表 */ - String THING_MODEL_LIST = "thing_model_list"; + String THING_MODEL_LIST = "iot:thing_model_list"; /** * 设备插件的插件进程编号的映射,采用 HASH 结构 @@ -50,6 +50,6 @@ public interface RedisKeyConstants { * HASH KEY:${deviceKey} * VALUE:插件进程编号,对应 {@link IotPluginInstanceDO#getProcessId()} 字段 */ - String DEVICE_PLUGIN_INSTANCE_PROCESS_IDS = "device_plugin_instance_process_ids"; + String DEVICE_PLUGIN_INSTANCE_PROCESS_IDS = "iot:device_plugin_instance_process_ids"; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java index bdd148ec0..e6ea3e22d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java @@ -24,7 +24,7 @@ public class IotRuleSceneMessageHandler { @Async public void onMessage(IotDeviceMessage message) { log.info("[onMessage][消息内容({})]", message); - ruleSceneService.executeRuleScene(message); + ruleSceneService.executeRuleSceneByDevice(message); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java deleted file mode 100644 index 392044317..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * TODO 芋艿:未来实现一个 IotRuleMessageConsumer - */ -package cn.iocoder.yudao.module.iot.mq.consumer.rule; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java index baf45fbab..e4766755d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java @@ -67,4 +67,9 @@ public class IotDeviceMessage { */ private LocalDateTime reportTime; + /** + * 租户编号 + */ + private Long tenantId; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 0b36b37bc..2680f47d1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/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.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -261,13 +262,9 @@ public class IotDeviceServiceImpl implements IotDeviceService { } @Override - public IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { - // 保证在 @CacheEvict 之前,忽略租户 - return TenantUtils.executeIgnore(() -> getSelf().getDeviceByProductKeyAndDeviceNameFromCache0(productKey, deviceName)); - } - @Cacheable(value = RedisKeyConstants.DEVICE, key = "#productKey + '_' + #deviceName", unless = "#result == null") - public IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache0(String productKey, String deviceName) { + @TenantIgnore // 忽略租户信息,跨租户 productKey + deviceName 是唯一的 + public IotDeviceDO getDeviceByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { return deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); } @@ -389,8 +386,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { } private void deleteDeviceCache(IotDeviceDO device) { - // 保证在 @CacheEvict 之前,忽略租户 - TenantUtils.executeIgnore(() -> getSelf().deleteDeviceCache0(device)); + // 保证 Spring AOP 触发 + getSelf().deleteDeviceCache0(device); } private void deleteDeviceCache(List devices) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java index 433b15320..f09604dea 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.service.device.control; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import jakarta.validation.Valid; /** @@ -16,7 +17,8 @@ public interface IotDeviceDownstreamService { * 设备下行,可用于设备模拟 * * @param downstreamReqVO 设备下行请求 VO + * @return 下发消息 */ - void downstreamDevice(@Valid IotDeviceDownstreamReqVO downstreamReqVO); + IotDeviceMessage downstreamDevice(@Valid IotDeviceDownstreamReqVO downstreamReqVO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java index 6db8a76ab..006636c23 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java @@ -54,7 +54,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic private IotDeviceProducer deviceProducer; @Override - public void downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) { + public IotDeviceMessage downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) { // 校验设备是否存在 IotDeviceDO device = deviceService.validateDeviceExists(downstreamReqVO.getId()); // TODO 芋艿:父设备的处理 @@ -62,31 +62,28 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic // 服务调用 if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.SERVICE.getType())) { - invokeDeviceService(downstreamReqVO, device, parentDevice); - return; + return invokeDeviceService(downstreamReqVO, device, parentDevice); } // 属性相关 if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) { // 属性设置 if (Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())) { - setDeviceProperty(downstreamReqVO, device, parentDevice); - return; + return setDeviceProperty(downstreamReqVO, device, parentDevice); } // 属性设置 if (Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) { - getDeviceProperty(downstreamReqVO, device, parentDevice); - return; + return getDeviceProperty(downstreamReqVO, device, parentDevice); } } // 配置下发 if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.CONFIG.getType()) && Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) { - setDeviceConfig(downstreamReqVO, device, parentDevice); - return; + return setDeviceConfig(downstreamReqVO, device, parentDevice); } // TODO 芋艿:ota 升级 + return null; } /** @@ -95,9 +92,10 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic * @param downstreamReqVO 下行请求 * @param device 设备 * @param parentDevice 父设备 + * @return 下发消息 */ @SuppressWarnings("unchecked") - private void invokeDeviceService(IotDeviceDownstreamReqVO downstreamReqVO, + private IotDeviceMessage invokeDeviceService(IotDeviceDownstreamReqVO downstreamReqVO, IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数校验 if (!(downstreamReqVO.getData() instanceof Map)) { @@ -124,6 +122,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic device.getDeviceKey(), reqDTO, result); throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); } + return message; } /** @@ -132,10 +131,11 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic * @param downstreamReqVO 下行请求 * @param device 设备 * @param parentDevice 父设备 + * @return 下发消息 */ @SuppressWarnings("unchecked") - private void setDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, - IotDeviceDO device, IotDeviceDO parentDevice) { + private IotDeviceMessage setDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, + IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数校验 if (!(downstreamReqVO.getData() instanceof Map)) { throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型"); @@ -162,6 +162,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic device.getDeviceKey(), reqDTO, result); throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); } + return message; } /** @@ -170,10 +171,11 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic * @param downstreamReqVO 下行请求 * @param device 设备 * @param parentDevice 父设备 + * @return 下发消息 */ @SuppressWarnings("unchecked") - private void getDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, - IotDeviceDO device, IotDeviceDO parentDevice) { + private IotDeviceMessage getDeviceProperty(IotDeviceDownstreamReqVO downstreamReqVO, + IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数校验 if (!(downstreamReqVO.getData() instanceof List)) { throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 List 类型"); @@ -200,6 +202,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic device.getDeviceKey(), reqDTO, result); throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); } + return message; } /** @@ -208,10 +211,11 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic * @param downstreamReqVO 下行请求 * @param device 设备 * @param parentDevice 父设备 + * @return 下发消息 */ @SuppressWarnings({"unchecked", "unused"}) - private void setDeviceConfig(IotDeviceDownstreamReqVO downstreamReqVO, - IotDeviceDO device, IotDeviceDO parentDevice) { + private IotDeviceMessage setDeviceConfig(IotDeviceDownstreamReqVO downstreamReqVO, + IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数转换,无需校验 Map config = JsonUtils.parseObject(device.getConfig(), Map.class); @@ -235,6 +239,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic device.getDeviceKey(), reqDTO, result); throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); } + return message; } /** @@ -275,7 +280,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device, Integer code) { // 1. 完善消息 message.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName()) - .setDeviceKey(device.getDeviceKey()); + .setDeviceKey(device.getDeviceKey()) + .setTenantId(device.getTenantId()); Assert.notNull(message.getRequestId(), "requestId 不能为空"); if (message.getReportTime() == null) { message.setReportTime(LocalDateTime.now()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index 9a1276ef4..1cbf3cd2a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -98,26 +98,27 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { updateReqDTO.getProductKey(), updateReqDTO.getDeviceName()); return; } - // 1.2 记录设备的最后时间 - updateDeviceLastTime(device, updateReqDTO); - // 1.3 当前状态一致,不处理 - if (Objects.equals(device.getState(), updateReqDTO.getState())) { - return; - } + TenantUtils.execute(device.getTenantId(), () -> { + // 1.2 记录设备的最后时间 + updateDeviceLastTime(device, updateReqDTO); + // 1.3 当前状态一致,不处理 + if (Objects.equals(device.getState(), updateReqDTO.getState())) { + return; + } - // 2. 更新设备状态 - TenantUtils.executeIgnore(() -> - deviceService.updateDeviceState(device.getId(), updateReqDTO.getState())); + // 2. 更新设备状态 + deviceService.updateDeviceState(device.getId(), updateReqDTO.getState()); - // 3. TODO 芋艿:子设备的关联 + // 3. TODO 芋艿:子设备的关联 - // 4. 发送设备消息 - IotDeviceMessage message = BeanUtils.toBean(updateReqDTO, IotDeviceMessage.class) - .setType(IotDeviceMessageTypeEnum.STATE.getType()) - .setIdentifier(ObjUtil.equals(updateReqDTO.getState(), IotDeviceStateEnum.ONLINE.getState()) - ? IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier() - : IotDeviceMessageIdentifierEnum.STATE_OFFLINE.getIdentifier()); - sendDeviceMessage(message, device); + // 4. 发送设备消息 + IotDeviceMessage message = BeanUtils.toBean(updateReqDTO, IotDeviceMessage.class) + .setType(IotDeviceMessageTypeEnum.STATE.getType()) + .setIdentifier(ObjUtil.equals(updateReqDTO.getState(), IotDeviceStateEnum.ONLINE.getState()) + ? IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier() + : IotDeviceMessageIdentifierEnum.STATE_OFFLINE.getIdentifier()); + sendDeviceMessage(message, device); + }); } @Override @@ -174,7 +175,8 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { // 1. 完善消息 - message.setDeviceKey(device.getDeviceKey()); + message.setDeviceKey(device.getDeviceKey()) + .setTenantId(device.getTenantId()); if (StrUtil.isEmpty(message.getRequestId())) { message.setRequestId(IdUtil.fastSimpleUUID()); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java index d1ebfd4f1..afe67c03a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.service.rule; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import java.util.List; @@ -22,10 +23,12 @@ public interface IotRuleSceneService { List getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName); /** - * 执行规则场景 + * 基于 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 场景,执行规则场景 * * @param message 消息 */ - void executeRuleScene(IotDeviceMessage message); + void executeRuleSceneByDevice(IotDeviceMessage message); + + // TODO @芋艿:基于 timer 场景,执行规则场景 } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java index 3e120c648..e58821ea7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java @@ -11,13 +11,16 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.service.rule.action.IotRuleSceneAction; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -43,6 +46,9 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @Resource private IotRuleSceneMapper ruleSceneMapper; + @Resource + private List ruleSceneActions; + // TODO 芋艿,缓存待实现 @Override @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 @@ -50,7 +56,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { if (true) { IotRuleSceneDO ruleScene01 = new IotRuleSceneDO(); ruleScene01.setTriggers(CollUtil.newArrayList()); - IotRuleSceneDO.Trigger trigger01 = new IotRuleSceneDO.Trigger(); + IotRuleSceneDO.TriggerConfig trigger01 = new IotRuleSceneDO.TriggerConfig(); trigger01.setType(IotRuleSceneTriggerTypeEnum.DEVICE.getType()); trigger01.setConditions(CollUtil.newArrayList()); // 属性 @@ -120,7 +126,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { condition02.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier()); condition02.setParameters(CollUtil.newArrayList()); trigger01.getConditions().add(condition02); - // TODO 芋艿:事件 + // 事件 IotRuleSceneDO.TriggerCondition condition03 = new IotRuleSceneDO.TriggerCondition(); condition03.setType(IotDeviceMessageTypeEnum.EVENT.getType()); condition03.setIdentifier("xxx"); @@ -131,13 +137,28 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { parameter030.setValue("1"); trigger01.getConditions().add(condition03); ruleScene01.getTriggers().add(trigger01); + // 动作 + ruleScene01.setActions(CollUtil.newArrayList()); + IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig(); + action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType()); + IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl(); + actionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT"); + actionDeviceControl01.setDeviceNames(ListUtil.of("small")); + actionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); + actionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()); + actionDeviceControl01.setData(MapUtil.builder() + .put("power", 1) + .put("color", "red") + .build()); + action01.setDeviceControl(actionDeviceControl01); + ruleScene01.getActions().add(action01); return ListUtil.toList(ruleScene01); } List list = ruleSceneMapper.selectList(); // TODO @芋艿:需要考虑开启状态 return filterList(list, ruleScene -> { - for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { + for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) { if (ObjUtil.notEqual(trigger.getProductKey(), productKey)) { continue; } @@ -151,12 +172,17 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { } @Override - public void executeRuleScene(IotDeviceMessage message) { - // 1. 获得设备匹配的规则场景 - List ruleScenes = getMatchedRuleSceneList(message); - if (CollUtil.isEmpty(ruleScenes)) { - return; - } + public void executeRuleSceneByDevice(IotDeviceMessage message) { + TenantUtils.execute(message.getTenantId(), () -> { + // 1. 获得设备匹配的规则场景 + List ruleScenes = getMatchedRuleSceneList(message); + if (CollUtil.isEmpty(ruleScenes)) { + return; + } + + // 2. 执行规则场景 + executeRuleSceneAction(message, ruleScenes); + }); } /** @@ -176,7 +202,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { // 2. 匹配 trigger 触发器的条件 return filterList(ruleScenes, ruleScene -> { - for (IotRuleSceneDO.Trigger trigger : ruleScene.getTriggers()) { + for (IotRuleSceneDO.TriggerConfig trigger : ruleScene.getTriggers()) { // 2.1 非设备触发,不匹配 if (ObjUtil.notEqual(trigger.getType(), IotRuleSceneTriggerTypeEnum.DEVICE.getType())) { return false; @@ -219,7 +245,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { */ @SuppressWarnings({"unchecked", "DataFlowIssue"}) private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter, - IotRuleSceneDO ruleScene, IotRuleSceneDO.Trigger trigger) { + IotRuleSceneDO ruleScene, IotRuleSceneDO.TriggerConfig trigger) { // 1.1 校验操作符是否合法 IotRuleSceneTriggerConditionParameterOperatorEnum operator = IotRuleSceneTriggerConditionParameterOperatorEnum.operatorOf(parameter.getOperator()); @@ -266,4 +292,36 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { } } + /** + * 执行规则场景的动作 + * + * @param message 设备消息 + * @param ruleScenes 规则场景列表 + */ + private void executeRuleSceneAction(IotDeviceMessage message, List ruleScenes) { + // 1. 遍历规则场景 + ruleScenes.forEach(ruleScene -> { + // 2. 遍历规则场景的动作 + ruleScene.getActions().forEach(actionConfig -> { + // 3.1 获取对应的动作 Action 数组 + List actions = filterList(ruleSceneActions, + action -> action.getType().getType().equals(actionConfig.getType())); + if (CollUtil.isEmpty(actions)) { + return; + } + // 3.2 执行动作 + actions.forEach(action -> { + try { + action.execute(message, actionConfig); + log.info("[executeRuleSceneAction][消息({}) 规则场景编号({}) 的执行动作({}) 成功]", + message, ruleScene.getId(), actionConfig); + } catch (Exception e) { + log.error("[executeRuleSceneAction][消息({}) 规则场景编号({}) 的执行动作({}) 执行异常]", + message, ruleScene.getId(), actionConfig, e); + } + }); + }); + }); + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java new file mode 100644 index 000000000..04020c176 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.service.rule.action; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; + +/** + * IOT 规则场景的场景执行器接口 + * + * @author 芋道源码 + */ +public interface IotRuleSceneAction { + + /** + * 执行场景 + * + * @param message 消息 + * @param config 配置 + */ + void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config); + + /** + * 获得类型 + * + * @return 类型 + */ + IotRuleSceneActionTypeEnum getType(); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java new file mode 100644 index 000000000..d8fd76b5e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.iot.service.rule.action; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * IoT 设备控制的 {@link IotRuleSceneAction} 实现类 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class IotRuleSceneDeviceControlAction implements IotRuleSceneAction { + + @Resource + private IotDeviceDownstreamService deviceDownstreamService; + @Resource + private IotDeviceService deviceService; + + @Override + public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { + IotRuleSceneDO.ActionDeviceControl control = config.getDeviceControl(); + Assert.notNull(control, "设备控制配置不能为空"); + // 遍历每个设备,下发消息 + control.getDeviceNames().forEach(deviceName -> { + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(control.getProductKey(), deviceName); + if (device == null) { + log.error("[execute][message({}) config({}) 对应的设备不存在]", message, config); + return; + } + try { + IotDeviceMessage downstreamMessage = deviceDownstreamService.downstreamDevice(new IotDeviceDownstreamReqVO() + .setId(device.getId()).setType(control.getType()).setIdentifier(control.getIdentifier()) + .setData(control.getData())); + log.info("[execute][message({}) config({}) 下发消息({})成功]", message, config, downstreamMessage); + } catch (Exception e) { + log.error("[execute][message({}) config({}) 下发消息失败]", message, config, e); + } + }); + } + + @Override + public IotRuleSceneActionTypeEnum getType() { + return IotRuleSceneActionTypeEnum.DEVICE_CONTROL; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index 60673268c..1b8cf79e0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelParam; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; @@ -135,13 +135,9 @@ public class IotThingModelServiceImpl implements IotThingModelService { } @Override - public List getThingModelListByProductKeyFromCache(String productKey) { - // 保证在 @CacheEvict 之前,忽略租户 - return TenantUtils.executeIgnore(() -> getSelf().getThingModelListByProductKeyFromCache0(productKey)); - } - @Cacheable(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey") - public List getThingModelListByProductKeyFromCache0(String productKey) { + @TenantIgnore // 忽略租户信息,跨租户 productKey 是唯一的 + public List getThingModelListByProductKeyFromCache(String productKey) { return thingModelMapper.selectListByProductKey(productKey); } @@ -354,8 +350,8 @@ public class IotThingModelServiceImpl implements IotThingModelService { } private void deleteThingModelListCache(String productKey) { - // 保证在 @CacheEvict 之前,忽略租户 - TenantUtils.executeIgnore(() -> getSelf().deleteThingModelListCache0(productKey)); + // 保证 Spring AOP 触发 + getSelf().deleteThingModelListCache0(productKey); } @CacheEvict(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey") diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 523d16dea..28b1eb60a 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -311,6 +311,8 @@ yudao: - mail_account - mail_template - sms_template + - iot:device + - iot:thing_model_list sms-code: # 短信验证码相关的配置项 expire-times: 10m send-frequency: 1m From 5e71d1fc851746c3366ce8f1a02f474a5ee434eb Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 3 Feb 2025 13:25:47 +0800 Subject: [PATCH 143/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20IotDataBridg?= =?UTF-8?q?eDO=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81=E7=9A=84=E5=AE=9A?= =?UTF-8?q?=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enums/rule/IotDataBridgDirectionEnum.java | 30 ++++ .../iot/enums/rule/IotDataBridgTypeEnum.java | 41 +++++ .../dal/dataobject/rule/IotDataBridgeDO.java | 140 ++++++++++++++++++ .../action/IotRuleSceneDataBridgeAction.java | 33 +++++ 4 files changed, 244 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgDirectionEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgDirectionEnum.java new file mode 100644 index 000000000..ff4993d0e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgDirectionEnum.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * Iot 数据桥接的方向枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotDataBridgDirectionEnum implements ArrayValuable { + + INPUT(1), // 输入 + OUTPUT(2); // 输出 + + private final Integer type; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgDirectionEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java new file mode 100644 index 000000000..cdec8d797 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * Iot 数据桥接的类型枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotDataBridgTypeEnum implements ArrayValuable { + + HTTP(1), + TCP(2), + WEBSOCKET(3), + + MQTT(10), + + DATABASE(20), + REDIS(21), + + ROCKETMQ(30), + RABBITMQ(31), + KAFKA(32) + ; + + private final Integer type; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgTypeEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java new file mode 100644 index 000000000..568377dd0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.rule; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import lombok.*; + +import java.util.Map; + +/** + * IoT 数据桥梁 DO + * + * @author 芋道源码 + */ +@TableName("iot_data_bridge") +@KeySequence("iot_data_bridge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotDataBridgeDO extends BaseDO { + + /** + * 桥梁编号 + */ + @TableId + private Long id; + /** + * 桥梁名称 + */ + private String name; + /** + * 桥梁描述 + */ + private String description; + /** + * 桥梁状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 桥梁方向 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgDirectionEnum} + */ + private Integer direction; + + /** + * 桥梁类型 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum} + */ + private Integer type; + + /** + * 桥梁配置 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Config config; + + /** + * 文件客户端的配置 + * 不同实现的客户端,需要不同的配置,通过子类来定义 + * + * @author 芋道源码 + */ + @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) + // @JsonTypeInfo 注解的作用,Jackson 多态 + // 1. 序列化到时数据库时,增加 @class 属性。 + // 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型 + public interface Config { + } + + /** + * HTTP 配置 + */ + @Data + public static class HttpConfig implements Config { + + /** + * 请求 URL + */ + private String url; + /** + * 请求方法 + */ + private String method; + /** + * 请求头 + */ + private Map headers; + /** + * 请求参数 + */ + private Map query; + /** + * 请求体 + */ + private String body; + + } + + /** + * MQTT 配置 + */ + @Data + public static class MqttConfig implements Config { + + /** + * MQTT 服务器地址 + */ + private String url; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + /** + * 客户端编号 + */ + private String clientId; + /** + * 主题 + */ + private String topic; + + } + + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java new file mode 100644 index 000000000..7f77ef3f4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.service.rule.action; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import org.springframework.stereotype.Component; + +/** + * IoT 数据桥梁的 {@link IotRuleSceneAction} 实现类 + * + * @author 芋道源码 + */ +@Component +public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { + + @Override + public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { + // TODO @芋艿:http + // TODO @芋艿:mq-redis + // TODO @芋艿:mq-数据库 + // TODO @芋艿:kafka + // TODO @芋艿:rocketmq + // TODO @芋艿:rabbitmq + // TODO @芋艿:mqtt + // TODO @芋艿:tcp + } + + @Override + public IotRuleSceneActionTypeEnum getType() { + return IotRuleSceneActionTypeEnum.DATA_BRIDGE; + } + +} From 7168e60fddc4210691a4f93651b2f0c9c081b1f3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 3 Feb 2025 18:33:43 +0800 Subject: [PATCH 144/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=AE=9E=E7=8E=B0=20IotRuleScene?= =?UTF-8?q?DataBridgeAction=20=E7=9A=84=20http=20=E9=83=A8=E5=88=86?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/common/util/http/HttpUtils.java | 14 ++- .../common/util/servlet/ServletUtils.java | 4 + .../framework/excel/core/util/ExcelUtils.java | 5 +- .../file/core/utils/FileTypeUtils.java | 4 +- .../dal/mysql/rule/IotDataBridgeMapper.java | 9 ++ .../service/rule/IotDataBridgeService.java | 20 ++++ .../rule/IotDataBridgeServiceImpl.java | 45 +++++++++ .../service/rule/IotRuleSceneServiceImpl.java | 8 +- .../action/IotRuleSceneDataBridgeAction.java | 99 ++++++++++++++++++- .../sms/core/client/impl/AliyunSmsClient.java | 2 +- .../sms/core/client/impl/HuaweiSmsClient.java | 8 +- .../server/controller/DefaultController.java | 32 ++++-- 12 files changed, 229 insertions(+), 21 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java index 9e75113d0..e1e0ac08e 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java @@ -7,13 +7,15 @@ import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.util.StringUtils; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; -import jakarta.servlet.http.HttpServletRequest; import java.net.URI; +import java.net.URLEncoder; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Map; /** @@ -23,6 +25,16 @@ import java.util.Map; */ public class HttpUtils { + /** + * 编码 URL 参数 + * + * @param value 参数 + * @return 编码后的参数 + */ + public static String encodeUtf8(String value) { + return URLEncoder.encode(value, StandardCharsets.UTF_8); + } + @SuppressWarnings("unchecked") public static String replaceUrlQuery(String url, String key, String value) { UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset()); diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java index 12731edad..905f5d541 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java @@ -98,4 +98,8 @@ public class ServletUtils { return JakartaServletUtil.getParamMap(request); } + public static Map getHeaderMap(HttpServletRequest request) { + return JakartaServletUtil.getHeaderMap(request); + } + } diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java index f5c4b8313..eb037d9e1 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.excel.core.util; +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.converters.longconverter.LongStringConverter; @@ -8,8 +9,6 @@ import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; import java.util.List; /** @@ -40,7 +39,7 @@ public class ExcelUtils { .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 .sheet(sheetName).doWrite(data); // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 - response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name())); + response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename)); response.setContentType("application/vnd.ms-excel;charset=UTF-8"); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java index 8970c004c..b25870fe8 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.infra.framework.file.core.utils; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import com.alibaba.ttl.TransmittableThreadLocal; import jakarta.servlet.http.HttpServletResponse; import lombok.SneakyThrows; import org.apache.tika.Tika; import java.io.IOException; -import java.net.URLEncoder; /** * 文件类型 Utils @@ -60,7 +60,7 @@ public class FileTypeUtils { */ public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException { // 设置 header 和 contentType - response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); + response.setHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename)); String contentType = getMineType(content, filename); response.setContentType(contentType); // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java new file mode 100644 index 000000000..076b341f0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.rule; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface IotDataBridgeMapper extends BaseMapperX { +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java new file mode 100644 index 000000000..cbf0b36c2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.service.rule; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; + +/** + * IoT 数据桥梁的 Service 接口 + * + * @author 芋道源码 + */ +public interface IotDataBridgeService { + + /** + * 获得指定数据桥梁 + * + * @param id 数据桥梁编号 + * @return 数据桥梁 + */ + IotDataBridgeDO getIotDataBridge(Long id); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java new file mode 100644 index 000000000..7814fd9bb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.iot.service.rule; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataBridgeMapper; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Objects; + +/** + * IoT 数据桥梁的 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class IotDataBridgeServiceImpl implements IotDataBridgeService { + + @Resource + private IotDataBridgeMapper dataBridgeMapper; + + // TODO @芋艿:临时测试 + @Override + public IotDataBridgeDO getIotDataBridge(Long id) { + if (Objects.equals(id, 1L)) { + IotDataBridgeDO.HttpConfig config = new IotDataBridgeDO.HttpConfig() + .setUrl("http://127.0.0.1:48080/test") +// .setMethod("POST") + .setMethod("GET") + .setQuery(MapUtil.of("aaa", "bbb")) + .setHeaders(MapUtil.of("ccc", "ddd")) + .setBody(JsonUtils.toJsonString(MapUtil.of("eee", "fff"))); + return IotDataBridgeDO.builder().id(1L).name("芋道").description("芋道源码").status(0).direction(1) + .type(IotDataBridgTypeEnum.HTTP.getType()).config(config).build(); + } + return dataBridgeMapper.selectById(id); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java index e58821ea7..fe9cd636b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java @@ -139,6 +139,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { ruleScene01.getTriggers().add(trigger01); // 动作 ruleScene01.setActions(CollUtil.newArrayList()); + // 设备控制 IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig(); action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType()); IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl(); @@ -151,7 +152,12 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { .put("color", "red") .build()); action01.setDeviceControl(actionDeviceControl01); - ruleScene01.getActions().add(action01); +// ruleScene01.getActions().add(action01); // TODO 芋艿:先不测试了 + // 数据桥接(http) + IotRuleSceneDO.ActionConfig action02 = new IotRuleSceneDO.ActionConfig(); + action02.setType(IotRuleSceneActionTypeEnum.DATA_BRIDGE.getType()); + action02.setDataBridgeId(1L); + ruleScene01.getActions().add(action02); return ListUtil.toList(ruleScene01); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index 7f77ef3f4..7774368d2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -1,9 +1,28 @@ package cn.iocoder.yudao.module.iot.service.rule.action; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.*; import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.HashMap; +import java.util.Map; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; /** * IoT 数据桥梁的 {@link IotRuleSceneAction} 实现类 @@ -11,11 +30,38 @@ import org.springframework.stereotype.Component; * @author 芋道源码 */ @Component +@Slf4j public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { + @Resource + private RestTemplate restTemplate; + + @Resource + private IotDataBridgeService dataBridgeService; + + private final ObjectMapper objectMapper = new ObjectMapper(); + @Override public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { - // TODO @芋艿:http + // 1. 获得数据桥梁 + Assert.notNull(config.getDataBridgeId(), "数据桥梁编号不能为空"); + IotDataBridgeDO dataBridge = dataBridgeService.getIotDataBridge(config.getDataBridgeId()); + if (dataBridge == null || dataBridge.getConfig() == null) { + log.error("[execute][message({}) config({}) 对应的数据桥梁不存在]", message, config); + return; + } + if (CommonStatusEnum.isDisable(dataBridge.getStatus())) { + log.info("[execute][message({}) config({}) 对应的数据桥梁({}) 状态为禁用]", message, config, dataBridge); + return; + } + + // 2.1 执行 HTTP 请求 + // TODO @芋艿:groovy 或者 javascript 实现数据的转换;可以考虑基于 hutool 的 ScriptUtil 做 + if (IotDataBridgTypeEnum.HTTP.getType().equals(dataBridge.getType())) { + executeHttp(message, (IotDataBridgeDO.HttpConfig) dataBridge.getConfig()); + return; + } + // TODO @芋艿:mq-redis // TODO @芋艿:mq-数据库 // TODO @芋艿:kafka @@ -23,6 +69,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { // TODO @芋艿:rabbitmq // TODO @芋艿:mqtt // TODO @芋艿:tcp + // TODO @芋艿:websocket } @Override @@ -30,4 +77,54 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { return IotRuleSceneActionTypeEnum.DATA_BRIDGE; } + @SuppressWarnings({"unchecked", "deprecation"}) + private void executeHttp(IotDeviceMessage message, IotDataBridgeDO.HttpConfig config) { + String url = null; + HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase()); + HttpEntity requestEntity = null; + ResponseEntity responseEntity = null; + try { + // 1.1 构建 Header + HttpHeaders headers = new HttpHeaders(); + if (CollUtil.isNotEmpty(config.getHeaders())) { + config.getHeaders().putAll(config.getHeaders()); + } + headers.add(HEADER_TENANT_ID, message.getTenantId().toString()); + // 1.2 构建 URL + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(config.getUrl()); + if (CollUtil.isNotEmpty(config.getQuery())) { + config.getQuery().forEach(uriBuilder::queryParam); + } + // 1.3 构建请求体 + if (method == HttpMethod.GET) { + uriBuilder.queryParam("message", HttpUtils.encodeUtf8(JsonUtils.toJsonString(message))); + url = uriBuilder.build().toUriString(); + requestEntity = new HttpEntity<>(headers); + } else { + url = uriBuilder.build().toUriString(); + Map requestBody = JsonUtils.parseObject(config.getBody(), Map.class); + if (requestBody == null) { + requestBody = new HashMap<>(); + } + requestBody.put("message", message); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE); + requestEntity = new HttpEntity<>(JsonUtils.toJsonString(requestBody), headers); + } + + // 2.1 发送请求 + responseEntity = restTemplate.exchange(url, method, requestEntity, String.class); + // 2.2 记录日志 + if (responseEntity.getStatusCode().is2xxSuccessful()) { + log.info("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求成功({})]", + message, config, url, method, requestEntity, responseEntity); + } else { + log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求失败({})]", + message, config, url, method, requestEntity, responseEntity); + } + } catch (Exception e) { + log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求异常({})]", + message, config, url, method, requestEntity, responseEntity, e); + } + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java index 558dbdef2..3dd12491a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java @@ -184,7 +184,7 @@ public class AliyunSmsClient extends AbstractSmsClient { @SneakyThrows private static String percentCode(String str) { Assert.notNull(str, "str 不能为空"); - return URLEncoder.encode(str, StandardCharsets.UTF_8.name()) + return HttpUtils.encodeUtf8(str) .replace("+", "%20") // 加号 "+" 被替换为 "%20" .replace("*", "%2A") // 星号 "*" 被替换为 "%2A" .replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~" diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/HuaweiSmsClient.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/HuaweiSmsClient.java index 82f55395e..622f8ac1b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/HuaweiSmsClient.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/HuaweiSmsClient.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.date.format.FastDateFormat; import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.http.HttpUtil; @@ -19,8 +18,6 @@ import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditS import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; import lombok.extern.slf4j.Slf4j; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.Instant; import java.time.LocalDateTime; @@ -156,10 +153,9 @@ public class HuaweiSmsClient extends AbstractSmsClient { .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(null); } - @SuppressWarnings("CharsetObjectCanBeUsed") - private static void appendToBody(StringBuilder body, String key, String value) throws UnsupportedEncodingException { + private static void appendToBody(StringBuilder body, String key, String value) { if (StrUtil.isNotEmpty(value)) { - body.append(key).append(URLEncoder.encode(value, CharsetUtil.CHARSET_UTF_8.name())); + body.append(key).append(HttpUtils.encodeUtf8(value)); } } diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java index 2bf6e5277..f0e387833 100644 --- a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java +++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java @@ -1,6 +1,10 @@ package cn.iocoder.yudao.server.controller; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import jakarta.annotation.security.PermitAll; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -13,6 +17,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC * @author 芋道源码 */ @RestController +@Slf4j public class DefaultController { @RequestMapping("/admin-api/bpm/**") @@ -27,9 +32,9 @@ public class DefaultController { "[微信公众号 yudao-module-mp - 已禁用][参考 https://doc.iocoder.cn/mp/build/ 开启]"); } - @RequestMapping(value = {"/admin-api/product/**", // 商品中心 + @RequestMapping(value = { "/admin-api/product/**", // 商品中心 "/admin-api/trade/**", // 交易中心 - "/admin-api/promotion/**"}) // 营销中心 + "/admin-api/promotion/**" }) // 营销中心 public CommonResult mall404() { return CommonResult.error(NOT_IMPLEMENTED.getCode(), "[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]"); @@ -47,28 +52,43 @@ public class DefaultController { "[CRM 模块 yudao-module-crm - 已禁用][参考 https://doc.iocoder.cn/crm/build/ 开启]"); } - @RequestMapping(value = {"/admin-api/report/**"}) + @RequestMapping(value = { "/admin-api/report/**"}) public CommonResult report404() { return CommonResult.error(NOT_IMPLEMENTED.getCode(), "[报表模块 yudao-module-report - 已禁用][参考 https://doc.iocoder.cn/report/ 开启]"); } - @RequestMapping(value = {"/admin-api/pay/**"}) + @RequestMapping(value = { "/admin-api/pay/**"}) public CommonResult pay404() { return CommonResult.error(NOT_IMPLEMENTED.getCode(), "[支付模块 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]"); } - @RequestMapping(value = {"/admin-api/ai/**"}) + @RequestMapping(value = { "/admin-api/ai/**"}) public CommonResult ai404() { return CommonResult.error(NOT_IMPLEMENTED.getCode(), "[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]"); } - @RequestMapping(value = {"/admin-api/iot/**"}) + @RequestMapping(value = { "/admin-api/iot/**"}) public CommonResult iot404() { return CommonResult.error(NOT_IMPLEMENTED.getCode(), "[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]"); } + /** + * 测试接口:打印 query、header、body + */ + @RequestMapping(value = { "/test" }) + @PermitAll + public CommonResult test(HttpServletRequest request) { + // 打印查询参数 + log.info("Query: {}", ServletUtils.getParamMap(request)); + // 打印请求头 + log.info("Header: {}", ServletUtils.getHeaderMap(request)); + // 打印请求体 + log.info("Body: {}", ServletUtils.getBody(request)); + return CommonResult.success(true); + } + } From 2109449a896e465e1740f88315864ed4c00ec298 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 3 Feb 2025 20:06:18 +0800 Subject: [PATCH 145/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=9C=89?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=9A=84=20Bridge=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E6=80=9D=E8=B7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/rule/action/IotRuleSceneDataBridgeAction.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index 7774368d2..eb50fb5df 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; -import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.http.*; @@ -29,6 +28,9 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ * * @author 芋道源码 */ +// TODO @芋艿:【优化】因为 bridge 会比较多,所以可以考虑在 rule 下,新建一个 bridge 的 package,然后定义一个 bridgehandler,它有: +// 1. input 方法、output 方法 +// 2. build 方法,用于有状态的连接,例如说 mq、tcp、websocket @Component @Slf4j public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { @@ -39,8 +41,6 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { @Resource private IotDataBridgeService dataBridgeService; - private final ObjectMapper objectMapper = new ObjectMapper(); - @Override public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { // 1. 获得数据桥梁 @@ -62,6 +62,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { return; } + // TODO @芋艿:因为下面的,都是有状态的,所以通过 guava 缓存连接,然后通过 RemovalNotification 实现关闭。例如说,一次新建有效期是 10 分钟; // TODO @芋艿:mq-redis // TODO @芋艿:mq-数据库 // TODO @芋艿:kafka From 8d0caaa16c68e9fe9718f524a2145051c4aed46c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 4 Feb 2025 00:12:08 +0800 Subject: [PATCH 146/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=9F=BA=E4=BA=8E=20Quartz=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20IotSchedulerManager=EF=BC=81=E4=B8=BA?= =?UTF-8?q?=E4=BA=86=E5=85=BC=E5=AE=B9=20boot=20=E5=92=8C=20cloud=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/dataobject/rule/IotRuleSceneDO.java | 12 +- .../job/config/IotJobConfiguration.java | 24 +++ .../job/core/IotSchedulerManager.java | 191 ++++++++++++++++++ .../service/rule/IotRuleSceneServiceImpl.java | 29 +++ .../rule/action/IotRuleSceneAction.java | 8 +- .../action/IotRuleSceneDataBridgeAction.java | 6 +- 6 files changed, 260 insertions(+), 10 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/config/IotJobConfiguration.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/core/IotSchedulerManager.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index 88df1946e..3c6ae6288 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -60,8 +60,6 @@ public class IotRuleSceneDO extends TenantBaseDO { @TableField(typeHandler = JacksonTypeHandler.class) private List triggers; - // TODO @芋艿:需要调研下 https://help.aliyun.com/zh/iot/user-guide/scene-orchestration-1?spm=a2c4g.11186623.help-menu-30520.d_2_4_5_0.45413908fxCSVa - /** * 执行器数组 */ @@ -97,7 +95,7 @@ public class IotRuleSceneDO extends TenantBaseDO { /** * 触发条件数组 * - * 当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 时,必填 + * 必填:当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 时 * 条件与条件之间,是“或”的关系 */ private List conditions; @@ -105,7 +103,7 @@ public class IotRuleSceneDO extends TenantBaseDO { /** * CRON 表达式 * - * 当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#TIMER} 时,必填 + * 必填:当 {@link #type} 为 {@link IotRuleSceneTriggerTypeEnum#TIMER} 时 */ private String cronExpression; @@ -185,15 +183,15 @@ public class IotRuleSceneDO extends TenantBaseDO { /** * 设备控制 * - * 当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DEVICE_CONTROL} 时,必填 + * 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DEVICE_CONTROL} 时 */ private ActionDeviceControl deviceControl; /** * 数据桥接编号 * - * 当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE} 时,必填 - * TODO 芋艿:关联 + * 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE} 时 + * 关联:{@link IotDataBridgeDO#getId()} */ private Long dataBridgeId; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/config/IotJobConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/config/IotJobConfiguration.java new file mode 100644 index 000000000..7cd6f0961 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/config/IotJobConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.iot.framework.job.config; + +import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +/** + * IoT 模块的 Job 自动配置类 + * + * @author 芋道源码 + */ +@Configuration +public class IotJobConfiguration { + + @Bean(initMethod = "start", destroyMethod = "stop") + public IotSchedulerManager iotSchedulerManager(DataSource dataSource, + ApplicationContext applicationContext) { + return new IotSchedulerManager(dataSource, applicationContext); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/core/IotSchedulerManager.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/core/IotSchedulerManager.java new file mode 100644 index 000000000..89eaaed1f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/core/IotSchedulerManager.java @@ -0,0 +1,191 @@ +package cn.iocoder.yudao.module.iot.framework.job.core; + +import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum; +import lombok.extern.slf4j.Slf4j; +import org.quartz.*; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.scheduling.quartz.SpringBeanJobFactory; + +import javax.sql.DataSource; +import java.util.Map; +import java.util.Properties; + +/** + * IoT 模块的 Scheduler 管理类,基于 Quartz 实现 + * + * 疑问:为什么 IoT 模块不复用全局的 SchedulerManager 呢? + * 回复:yudao-cloud 项目,使用的是 XXL-Job 作为调度中心,无法动态添加任务。 + * + * @author 芋道源码 + */ +@Slf4j +public class IotSchedulerManager { + + private static final String SCHEDULER_NAME = "iotScheduler"; + + private final SchedulerFactoryBean schedulerFactoryBean; + + private Scheduler scheduler; + + public IotSchedulerManager(DataSource dataSource, + ApplicationContext applicationContext) { + // 1. 参考 SchedulerFactoryBean 类 + SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); + SpringBeanJobFactory jobFactory = new SpringBeanJobFactory(); + jobFactory.setApplicationContext(applicationContext); + schedulerFactoryBean.setJobFactory(jobFactory); + schedulerFactoryBean.setAutoStartup(true); + schedulerFactoryBean.setSchedulerName(SCHEDULER_NAME); + schedulerFactoryBean.setDataSource(dataSource); + schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(true); + Properties properties = new Properties(); + schedulerFactoryBean.setQuartzProperties(properties); + // 2. 参考 application-local.yaml 配置文件 + // 2.1 Scheduler 相关配置 + properties.put("org.quartz.scheduler.instanceName", SCHEDULER_NAME); + properties.put("org.quartz.scheduler.instanceId", "AUTO"); + // 2.2 JobStore 相关配置 + properties.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore"); + properties.put("org.quartz.jobStore.isClustered", "true"); + properties.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); + properties.put("org.quartz.jobStore.misfireThreshold", "60000"); + // 2.3 线程池相关配置 + properties.put("org.quartz.threadPool.threadCount", "25"); + properties.put("org.quartz.threadPool.threadPriority", "5"); + properties.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); + this.schedulerFactoryBean = schedulerFactoryBean; + } + + public void start() throws Exception { + log.info("[start][Scheduler 初始化开始]"); + // 初始化 + schedulerFactoryBean.afterPropertiesSet(); + schedulerFactoryBean.start(); + // 获得 Scheduler 对象 + this.scheduler = schedulerFactoryBean.getScheduler(); + log.info("[start][Scheduler 初始化完成]"); + } + + public void stop() { + log.info("[stop][Scheduler 关闭开始]"); + schedulerFactoryBean.stop(); + this.scheduler = null; + log.info("[stop][Scheduler 关闭完成]"); + } + + // ========== 参考 SchedulerManager 实现 ========== + + /** + * 添加或更新 Job 到 Quartz 中 + * + * @param jobClass 任务处理器的类 + * @param jobHandlerName 任务处理器的名字 + * @param cronExpression CRON 表达式 + * @param jobDataMap 任务数据 + * @throws SchedulerException 添加异常 + */ + public void addOrUpdateJob(Class jobClass, String jobHandlerName, + String cronExpression, Map jobDataMap) + throws SchedulerException { + if (scheduler.checkExists(new JobKey(jobHandlerName))) { + this.updateJob(jobHandlerName, cronExpression); + } else { + this.addJob(jobClass, jobHandlerName, cronExpression, jobDataMap); + } + } + + /** + * 添加 Job 到 Quartz 中 + * + * @param jobClass 任务处理器的类 + * @param jobHandlerName 任务处理器的名字 + * @param cronExpression CRON 表达式 + * @param jobDataMap 任务数据 + * @throws SchedulerException 添加异常 + */ + public void addJob(Class jobClass, String jobHandlerName, + String cronExpression, Map jobDataMap) + throws SchedulerException { + // 创建 JobDetail 对象 + JobDetail jobDetail = JobBuilder.newJob(jobClass) + .usingJobData(new JobDataMap(jobDataMap)) + .withIdentity(jobHandlerName).build(); + // 创建 Trigger 对象 + Trigger trigger = this.buildTrigger(jobHandlerName, cronExpression); + // 新增 Job 调度 + scheduler.scheduleJob(jobDetail, trigger); + } + + /** + * 更新 Job 到 Quartz + * + * @param jobHandlerName 任务处理器的名字 + * @param cronExpression CRON 表达式 + * @throws SchedulerException 更新异常 + */ + public void updateJob(String jobHandlerName, String cronExpression) + throws SchedulerException { + // 创建新 Trigger 对象 + Trigger newTrigger = this.buildTrigger(jobHandlerName, cronExpression); + // 修改调度 + scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger); + } + + /** + * 删除 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 删除异常 + */ + public void deleteJob(String jobHandlerName) throws SchedulerException { + // 暂停 Trigger 对象 + scheduler.pauseTrigger(new TriggerKey(jobHandlerName)); + // 取消并删除 Job 调度 + scheduler.unscheduleJob(new TriggerKey(jobHandlerName)); + scheduler.deleteJob(new JobKey(jobHandlerName)); + } + + /** + * 暂停 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 暂停异常 + */ + public void pauseJob(String jobHandlerName) throws SchedulerException { + scheduler.pauseJob(new JobKey(jobHandlerName)); + } + + /** + * 启动 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 启动异常 + */ + public void resumeJob(String jobHandlerName) throws SchedulerException { + scheduler.resumeJob(new JobKey(jobHandlerName)); + scheduler.resumeTrigger(new TriggerKey(jobHandlerName)); + } + + /** + * 立即触发一次 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 触发异常 + */ + public void triggerJob(String jobHandlerName) + throws SchedulerException { + // 触发任务 + JobDataMap data = new JobDataMap(); + data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName); + scheduler.triggerJob(new JobKey(jobHandlerName), data); + } + + private Trigger buildTrigger(String jobHandlerName, String cronExpression) { + return TriggerBuilder.newTrigger() + .withIdentity(jobHandlerName) + .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) + .build(); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java index fe9cd636b..71c080d6a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java @@ -23,6 +23,11 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.service.rule.action.IotRuleSceneAction; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.TriggerKey; +import org.quartz.impl.StdSchedulerFactory; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -330,4 +335,28 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { }); } + // TODO @芋艿:测试思路代码,记得删除!!! + // 1. Job 类:IotRuleSceneJob + // 2. 参数:id + // 3. jobHandlerName:IotRuleSceneJob + id + + // 新增:addJob + // 修改:不存在 addJob、存在 updateJob + // 有 + 禁用:1)存在、停止;2)不存在:不处理;TODO 测试:直接暂停,是否可以???(结论:可以) + // 有 + 开启:1)存在,更新;2)不存在,新增; + // 无 + 禁用、开启:1)存在,删除;TODO 测试:直接删除???(结论:可以) + + public static void main2(String[] args) throws SchedulerException { +// System.out.println(QuartzJobBean.class); + Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); + scheduler.start(); + + String jobHandlerName = "123"; + // 暂停 Trigger 对象 + scheduler.pauseTrigger(new TriggerKey(jobHandlerName)); + // 取消并删除 Job 调度 + scheduler.unscheduleJob(new TriggerKey(jobHandlerName)); + scheduler.deleteJob(new JobKey(jobHandlerName)); + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java index 04020c176..1cb17c9b4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java @@ -4,6 +4,8 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import javax.annotation.Nullable; + /** * IOT 规则场景的场景执行器接口 * @@ -14,10 +16,12 @@ public interface IotRuleSceneAction { /** * 执行场景 * - * @param message 消息 + * @param message 消息,允许空 + * 1. 空的情况:定时触发 + * 2. 非空的情况:设备触发 * @param config 配置 */ - void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config); + void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config); /** * 获得类型 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index eb50fb5df..f7f3747e7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -43,7 +43,11 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { @Override public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { - // 1. 获得数据桥梁 + // 1.1 如果消息为空,直接返回 + if (message == null) { + return; + } + // 1.2 获得数据桥梁 Assert.notNull(config.getDataBridgeId(), "数据桥梁编号不能为空"); IotDataBridgeDO dataBridge = dataBridgeService.getIotDataBridge(config.getDataBridgeId()); if (dataBridge == null || dataBridge.getConfig() == null) { From f6f162ad2fb7676e46b9747a661ed17427847292 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 4 Feb 2025 12:39:56 +0800 Subject: [PATCH 147/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20IotRuleScene?= =?UTF-8?q?Job=20=E6=89=A7=E8=A1=8C=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/rule/IotRuleSceneController.java | 27 +++++ .../job/core/IotSchedulerManager.java | 62 ++++++------ .../module/iot/job/rule/IotRuleSceneJob.java | 57 +++++++++++ .../iot/service/rule/IotRuleSceneService.java | 12 ++- .../service/rule/IotRuleSceneServiceImpl.java | 99 ++++++++++++++++--- 5 files changed, 213 insertions(+), 44 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java new file mode 100644 index 000000000..04e2f4570 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule; + +import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "管理后台 - IoT 规则场景") +@RestController +@RequestMapping("/iot/rule-scene") +@Validated +public class IotRuleSceneController { + + @Resource + private IotRuleSceneService ruleSceneService; + + @GetMapping("/test") + @PermitAll + public void test() { + ruleSceneService.test(); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/core/IotSchedulerManager.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/core/IotSchedulerManager.java index 89eaaed1f..c52164b6e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/core/IotSchedulerManager.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/job/core/IotSchedulerManager.java @@ -80,18 +80,18 @@ public class IotSchedulerManager { * 添加或更新 Job 到 Quartz 中 * * @param jobClass 任务处理器的类 - * @param jobHandlerName 任务处理器的名字 + * @param jobName 任务名 * @param cronExpression CRON 表达式 * @param jobDataMap 任务数据 * @throws SchedulerException 添加异常 */ - public void addOrUpdateJob(Class jobClass, String jobHandlerName, + public void addOrUpdateJob(Class jobClass, String jobName, String cronExpression, Map jobDataMap) throws SchedulerException { - if (scheduler.checkExists(new JobKey(jobHandlerName))) { - this.updateJob(jobHandlerName, cronExpression); + if (scheduler.checkExists(new JobKey(jobName))) { + this.updateJob(jobName, cronExpression); } else { - this.addJob(jobClass, jobHandlerName, cronExpression, jobDataMap); + this.addJob(jobClass, jobName, cronExpression, jobDataMap); } } @@ -99,20 +99,20 @@ public class IotSchedulerManager { * 添加 Job 到 Quartz 中 * * @param jobClass 任务处理器的类 - * @param jobHandlerName 任务处理器的名字 + * @param jobName 任务名 * @param cronExpression CRON 表达式 * @param jobDataMap 任务数据 * @throws SchedulerException 添加异常 */ - public void addJob(Class jobClass, String jobHandlerName, + public void addJob(Class jobClass, String jobName, String cronExpression, Map jobDataMap) throws SchedulerException { // 创建 JobDetail 对象 JobDetail jobDetail = JobBuilder.newJob(jobClass) .usingJobData(new JobDataMap(jobDataMap)) - .withIdentity(jobHandlerName).build(); + .withIdentity(jobName).build(); // 创建 Trigger 对象 - Trigger trigger = this.buildTrigger(jobHandlerName, cronExpression); + Trigger trigger = this.buildTrigger(jobName, cronExpression); // 新增 Job 调度 scheduler.scheduleJob(jobDetail, trigger); } @@ -120,70 +120,70 @@ public class IotSchedulerManager { /** * 更新 Job 到 Quartz * - * @param jobHandlerName 任务处理器的名字 + * @param jobName 任务名 * @param cronExpression CRON 表达式 * @throws SchedulerException 更新异常 */ - public void updateJob(String jobHandlerName, String cronExpression) + public void updateJob(String jobName, String cronExpression) throws SchedulerException { // 创建新 Trigger 对象 - Trigger newTrigger = this.buildTrigger(jobHandlerName, cronExpression); + Trigger newTrigger = this.buildTrigger(jobName, cronExpression); // 修改调度 - scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger); + scheduler.rescheduleJob(new TriggerKey(jobName), newTrigger); } /** * 删除 Quartz 中的 Job * - * @param jobHandlerName 任务处理器的名字 + * @param jobName 任务名 * @throws SchedulerException 删除异常 */ - public void deleteJob(String jobHandlerName) throws SchedulerException { + public void deleteJob(String jobName) throws SchedulerException { // 暂停 Trigger 对象 - scheduler.pauseTrigger(new TriggerKey(jobHandlerName)); + scheduler.pauseTrigger(new TriggerKey(jobName)); // 取消并删除 Job 调度 - scheduler.unscheduleJob(new TriggerKey(jobHandlerName)); - scheduler.deleteJob(new JobKey(jobHandlerName)); + scheduler.unscheduleJob(new TriggerKey(jobName)); + scheduler.deleteJob(new JobKey(jobName)); } /** * 暂停 Quartz 中的 Job * - * @param jobHandlerName 任务处理器的名字 + * @param jobName 任务名 * @throws SchedulerException 暂停异常 */ - public void pauseJob(String jobHandlerName) throws SchedulerException { - scheduler.pauseJob(new JobKey(jobHandlerName)); + public void pauseJob(String jobName) throws SchedulerException { + scheduler.pauseJob(new JobKey(jobName)); } /** * 启动 Quartz 中的 Job * - * @param jobHandlerName 任务处理器的名字 + * @param jobName 任务名 * @throws SchedulerException 启动异常 */ - public void resumeJob(String jobHandlerName) throws SchedulerException { - scheduler.resumeJob(new JobKey(jobHandlerName)); - scheduler.resumeTrigger(new TriggerKey(jobHandlerName)); + public void resumeJob(String jobName) throws SchedulerException { + scheduler.resumeJob(new JobKey(jobName)); + scheduler.resumeTrigger(new TriggerKey(jobName)); } /** * 立即触发一次 Quartz 中的 Job * - * @param jobHandlerName 任务处理器的名字 + * @param jobName 任务名 * @throws SchedulerException 触发异常 */ - public void triggerJob(String jobHandlerName) + public void triggerJob(String jobName) throws SchedulerException { // 触发任务 JobDataMap data = new JobDataMap(); - data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName); - scheduler.triggerJob(new JobKey(jobHandlerName), data); + data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobName); + scheduler.triggerJob(new JobKey(jobName), data); } - private Trigger buildTrigger(String jobHandlerName, String cronExpression) { + private Trigger buildTrigger(String jobName, String cronExpression) { return TriggerBuilder.newTrigger() - .withIdentity(jobHandlerName) + .withIdentity(jobName) .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) .build(); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java new file mode 100644 index 000000000..2cda2fc20 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.iot.job.rule; + +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.quartz.JobExecutionContext; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import java.util.Map; + +/** + * IoT 规则场景 Job,用于执行 {@link IotRuleSceneTriggerTypeEnum#TIMER} 类型的规则场景 + * + * @author 芋道源码 + */ +@Slf4j +public class IotRuleSceneJob extends QuartzJobBean { + + /** + * JobData Key - 规则场景编号 + */ + public static final String JOB_DATA_KEY_RULE_SCENE_ID = "ruleSceneId"; + + @Resource + private IotRuleSceneService ruleSceneService; + + @Override + protected void executeInternal(JobExecutionContext context) { + // 获得规则场景编号 + Long ruleSceneId = context.getMergedJobDataMap().getLong(JOB_DATA_KEY_RULE_SCENE_ID); + + // 执行规则场景 + ruleSceneService.executeRuleSceneByTimer(ruleSceneId); + } + + /** + * 创建 JobData Map + * + * @param ruleSceneId 规则场景编号 + * @return JobData Map + */ + public static Map buildJobDataMap(Long ruleSceneId) { + return Map.of(JOB_DATA_KEY_RULE_SCENE_ID, ruleSceneId); + } + + /** + * 创建 Job 名字 + * + * @param ruleSceneId 规则场景编号 + * @return Job 名字 + */ + public static String buildJobName(Long ruleSceneId) { + return String.format("%s_%d", IotRuleSceneJob.class.getSimpleName(), ruleSceneId); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java index afe67c03a..6927b1172 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneService.java @@ -29,6 +29,16 @@ public interface IotRuleSceneService { */ void executeRuleSceneByDevice(IotDeviceMessage message); - // TODO @芋艿:基于 timer 场景,执行规则场景 + /** + * 基于 {@link IotRuleSceneTriggerTypeEnum#TIMER} 场景,执行规则场景 + * + * @param id 场景编号 + */ + void executeRuleSceneByTimer(Long id); + + /** + * TODO 芋艿:测试方法,需要删除 + */ + void test(); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java index 71c080d6a..7f8ff51f1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java @@ -7,6 +7,7 @@ import cn.hutool.core.text.CharPool; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; @@ -19,9 +20,12 @@ import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; +import cn.iocoder.yudao.module.iot.job.rule.IotRuleSceneJob; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.service.rule.action.IotRuleSceneAction; import jakarta.annotation.Resource; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.quartz.JobKey; import org.quartz.Scheduler; @@ -54,6 +58,9 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @Resource private List ruleSceneActions; + @Resource(name = "iotSchedulerManager") + private IotSchedulerManager schedulerManager; + // TODO 芋艿,缓存待实现 @Override @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 @@ -186,7 +193,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { public void executeRuleSceneByDevice(IotDeviceMessage message) { TenantUtils.execute(message.getTenantId(), () -> { // 1. 获得设备匹配的规则场景 - List ruleScenes = getMatchedRuleSceneList(message); + List ruleScenes = getMatchedRuleSceneListByMessage(message); if (CollUtil.isEmpty(ruleScenes)) { return; } @@ -196,13 +203,60 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { }); } + @Override + public void executeRuleSceneByTimer(Long id) { + // 1.1 获得规则场景 +// IotRuleSceneDO scene = TenantUtils.executeIgnore(() -> ruleSceneMapper.selectById(id)); + // TODO @芋艿:这里,临时测试,后续删除。 + IotRuleSceneDO scene = new IotRuleSceneDO().setStatus(CommonStatusEnum.ENABLE.getStatus()); + if (true) { + scene.setTenantId(1L); + IotRuleSceneDO.TriggerConfig triggerConfig = new IotRuleSceneDO.TriggerConfig(); + triggerConfig.setType(IotRuleSceneTriggerTypeEnum.TIMER.getType()); + scene.setTriggers(ListUtil.toList(triggerConfig)); + // 动作 + IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig(); + action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType()); + IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl(); + actionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT"); + actionDeviceControl01.setDeviceNames(ListUtil.of("small")); + actionDeviceControl01.setType(IotDeviceMessageTypeEnum.PROPERTY.getType()); + actionDeviceControl01.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier()); + actionDeviceControl01.setData(MapUtil.builder() + .put("power", 1) + .put("color", "red") + .build()); + action01.setDeviceControl(actionDeviceControl01); + scene.setActions(ListUtil.toList(action01)); + } + if (scene == null) { + log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id); + return; + } + if (CommonStatusEnum.isDisable(scene.getStatus())) { + log.info("[executeRuleSceneByTimer][规则场景({}) 已被禁用]", id); + return; + } + // 1.2 判断是否有定时触发器,避免脏数据 + IotRuleSceneDO.TriggerConfig config = CollUtil.findOne(scene.getTriggers(), + trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType())); + if (config == null) { + log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene); + return; + } + + // 2. 执行规则场景 + TenantUtils.execute(scene.getTenantId(), + () -> executeRuleSceneAction(null, ListUtil.toList(scene))); + } + /** - * 获得匹配的规则场景列表 + * 基于消息,获得匹配的规则场景列表 * * @param message 设备消息 * @return 规则场景列表 */ - private List getMatchedRuleSceneList(IotDeviceMessage message) { + private List getMatchedRuleSceneListByMessage(IotDeviceMessage message) { // 1. 匹配设备 // TODO @芋艿:可能需要 getSelf(); 缓存 List ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache( @@ -335,16 +389,37 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { }); } - // TODO @芋艿:测试思路代码,记得删除!!! - // 1. Job 类:IotRuleSceneJob - // 2. 参数:id - // 3. jobHandlerName:IotRuleSceneJob + id + @Override + @SneakyThrows + public void test() { + // TODO @芋艿:测试思路代码,记得删除!!! + // 1. Job 类:IotRuleSceneJob DONE + // 2. 参数:id DONE + // 3. jobHandlerName:IotRuleSceneJob + id DONE - // 新增:addJob - // 修改:不存在 addJob、存在 updateJob - // 有 + 禁用:1)存在、停止;2)不存在:不处理;TODO 测试:直接暂停,是否可以???(结论:可以) - // 有 + 开启:1)存在,更新;2)不存在,新增; - // 无 + 禁用、开启:1)存在,删除;TODO 测试:直接删除???(结论:可以) + // 新增:addJob + // 修改:不存在 addJob、存在 updateJob + // 有 + 禁用:1)存在、停止;2)不存在:不处理;TODO 测试:直接暂停,是否可以???(结论:可以)pauseJob + // 有 + 开启:1)存在,更新;2)不存在,新增;结论:使用 save(addOrUpdateJob) + // 无 + 禁用、开启:1)存在,删除;TODO 测试:直接删除???(结论:可以)deleteJob + + // + if (true) { + Long id = 1L; + Map jobDataMap = IotRuleSceneJob.buildJobDataMap(id); + schedulerManager.addOrUpdateJob(IotRuleSceneJob.class, + IotRuleSceneJob.buildJobName(id), + "0/10 * * * * ?", + jobDataMap); + } + if (false) { + Long id = 1L; + schedulerManager.pauseJob(IotRuleSceneJob.buildJobName(id)); + } + if (true) { + + } + } public static void main2(String[] args) throws SchedulerException { // System.out.println(QuartzJobBean.class); From d24e3ad773b62f656469fb919f634f2533900cc5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 4 Feb 2025 13:41:52 +0800 Subject: [PATCH 148/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20alert=20?= =?UTF-8?q?=E5=91=8A=E8=AD=A6=E7=9B=B8=E5=85=B3=E7=9A=84=E8=A1=A8=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rule/IotAlertConfigReceiveTypeEnum.java | 31 ++++++++ .../thingmodel/IotDataSpecsDataTypeEnum.java | 1 + .../IotThingModelAccessModeEnum.java | 1 + .../IotThingModelParamDirectionEnum.java | 1 + .../IotThingModelServiceCallTypeEnum.java | 1 + .../IotThingModelServiceEventTypeEnum.java | 1 + .../dal/dataobject/rule/IotAlertConfig.java | 79 +++++++++++++++++++ .../dal/dataobject/rule/IotAlertRecordDO.java | 78 ++++++++++++++++++ .../rule/action/IotRuleSceneAction.java | 1 + .../rule/action/IotRuleSceneAlertAction.java | 28 +++++++ .../action/IotRuleSceneDataBridgeAction.java | 1 - 11 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAlertAction.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java new file mode 100644 index 000000000..87df89f76 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * Iot 告警配置的接收方式枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotAlertConfigReceiveTypeEnum implements ArrayValuable { + + SMS(1), // 短信 + MAIL(2), // 邮箱 + NOTIFY(3); // 通知 + + private final Integer type; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotAlertConfigReceiveTypeEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java index 5133b0038..aa455f8cc 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; import lombok.AllArgsConstructor; import lombok.Getter; +// TODO @puhui999:加个 ArrayValuable /** * IoT 数据定义的数据类型枚举类 * diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java index 0b18bbbf5..6eb6ddb7e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; import lombok.AllArgsConstructor; import lombok.Getter; +// TODO @puhui999:加个 ArrayValuable /** * IOT 产品物模型属性读取类型枚举 * diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java index b1ae8a947..1e875cd23 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; import lombok.AllArgsConstructor; import lombok.Getter; +// TODO @puhui999:加个 ArrayValuable /** * IOT 产品物模型参数是输入参数还是输出参数枚举 * diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java index 66ca6bec5..d547bf104 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; import lombok.AllArgsConstructor; import lombok.Getter; +// TODO @puhui999:加个 ArrayValuable /** * IOT 产品物模型服务调用方式枚举 * diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java index b87d7eb98..89271d7fc 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; import lombok.AllArgsConstructor; import lombok.Getter; +// TODO @puhui999:加个 ArrayValuable /** * IOT 产品物模型事件类型枚举 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java new file mode 100644 index 000000000..94734a2d3 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.rule; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotAlertConfigReceiveTypeEnum; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * IoT 告警配置 DO + * + * @author 芋道源码 + */ +@TableName("iot_alert_config") +@KeySequence("iot_alert_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotAlertConfig extends BaseDO { + + /** + * 配置编号 + */ + @TableId + private Long id; + /** + * 配置名称 + */ + private String name; + /** + * 配置描述 + */ + private String description; + /** + * 配置状态 + * + * TODO 数据字典 + */ + private Integer level; + /** + * 配置状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + + /** + * 关联的规则场景编号数组 + * + * 关联 {@link IotRuleSceneDO#getId()} + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List ruleSceneIds; + + /** + * 接收的用户编号数组 + * + * 关联 {@link AdminUserRespDTO#getId()} + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List receiveUserIds; + /** + * 接收的类型数组 + * + * 枚举 {@link IotAlertConfigReceiveTypeEnum} + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List receiveTypes; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java new file mode 100644 index 000000000..2fc01ba7d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.rule; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +/** + * IoT 告警记录 DO + * + * @author 芋道源码 + */ +@TableName("iot_alert_record") +@KeySequence("iot_alert_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotAlertRecordDO extends BaseDO { + + /** + * 记录编号 + */ + @TableField + private Long id; + /** + * 告警名称 + * + * 冗余 {@link IotAlertConfig#getName()} + */ + private Long configId; + /** + * 告警名称 + * + * 冗余 {@link IotAlertConfig#getName()} + */ + private String name; + + /** + * 产品标识 + * + * 关联 {@link IotProductDO#getProductKey()} ()} + */ + private String productKey; + /** + * 设备名称 + * + * 冗余 {@link IotDeviceDO#getDeviceName()} + */ + private String deviceName; + + // TODO @芋艿:有没更好的方式 + /** + * 触发的设备消息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private IotDeviceMessage deviceMessage; + + /** + * 处理状态 + * + * true - 已处理 + * false - 未处理 + */ + private Boolean processStatus; + /** + * 处理结果(备注) + */ + private String processRemark; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java index 1cb17c9b4..4cf1f8f28 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java @@ -13,6 +13,7 @@ import javax.annotation.Nullable; */ public interface IotRuleSceneAction { + // TODO @芋艿:groovy 或者 javascript 实现数据的转换;可以考虑基于 hutool 的 ScriptUtil 做 /** * 执行场景 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAlertAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAlertAction.java new file mode 100644 index 000000000..eadc17378 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAlertAction.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.iot.service.rule.action; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import org.springframework.stereotype.Component; + +import javax.annotation.Nullable; + +/** + * IoT 告警的 {@link IotRuleSceneAction} 实现类 + * + * @author 芋道源码 + */ +@Component +public class IotRuleSceneAlertAction implements IotRuleSceneAction { + + @Override + public void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { + // TODO @芋艿:待实现 + } + + @Override + public IotRuleSceneActionTypeEnum getType() { + return IotRuleSceneActionTypeEnum.ALERT; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index f7f3747e7..82b046714 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -60,7 +60,6 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { } // 2.1 执行 HTTP 请求 - // TODO @芋艿:groovy 或者 javascript 实现数据的转换;可以考虑基于 hutool 的 ScriptUtil 做 if (IotDataBridgTypeEnum.HTTP.getType().equals(dataBridge.getType())) { executeHttp(message, (IotDataBridgeDO.HttpConfig) dataBridge.getConfig()); return; From d23be8616483862d0cfe034fa532c9312ff2e3fb Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 4 Feb 2025 16:35:55 +0800 Subject: [PATCH 149/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thingmodel/IotThingModelController.java | 7 ++-- .../module/iot/convert/package-info.java | 4 ++- .../thingmodel/IotThingModelConvert.java | 12 ------- .../thingmodel/IotThingModelServiceImpl.java | 35 +++++++++---------- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java index e4913486d..382940fc4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java @@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelL import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.thingmodel.IotThingModelConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import io.swagger.v3.oas.annotations.Operation; @@ -62,7 +61,7 @@ public class IotThingModelController { @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") public CommonResult getThingModel(@RequestParam("id") Long id) { IotThingModelDO thingModel = thingModelService.getThingModel(id); - return success(IotThingModelConvert.INSTANCE.convert(thingModel)); + return success(BeanUtils.toBean(thingModel, IotThingModelRespVO.class)); } @GetMapping("/list-by-product-id") @@ -71,7 +70,7 @@ public class IotThingModelController { @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") public CommonResult> getThingModelListByProductId(@RequestParam("productId") Long productId) { List list = thingModelService.getThingModelListByProductId(productId); - return success(IotThingModelConvert.INSTANCE.convertList(list)); + return success(BeanUtils.toBean(list, IotThingModelRespVO.class)); } // TODO @puhui @super:getThingModelListByProductId 和 getThingModelListByProductId 可以融合么? @@ -80,7 +79,7 @@ public class IotThingModelController { @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") public CommonResult> getThingModelListByProductId(@Valid IotThingModelListReqVO reqVO) { List list = thingModelService.getThingModelList(reqVO); - return success(IotThingModelConvert.INSTANCE.convertList(list)); + return success(BeanUtils.toBean(list, IotThingModelRespVO.class)); } @GetMapping("/page") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java index 28131f090..18d7ad21d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java @@ -1,4 +1,6 @@ /** - * TODO 芋艿:占位 + * 提供 POJO 类的实体转换 + * + * 目前使用 MapStruct 框架 */ package cn.iocoder.yudao.module.iot.convert; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java index 2e9b5441c..9577b18f7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.convert.thingmodel; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; @@ -12,7 +11,6 @@ import org.mapstruct.Mapping; import org.mapstruct.Named; import org.mapstruct.factory.Mappers; -import java.util.List; import java.util.Objects; @Mapper @@ -20,21 +18,11 @@ public interface IotThingModelConvert { IotThingModelConvert INSTANCE = Mappers.getMapper(IotThingModelConvert.class); - // 将 SaveReqVO 转换为 DO @Mapping(target = "property", expression = "java(convertToProperty(bean))") @Mapping(target = "event", expression = "java(convertToEvent(bean))") @Mapping(target = "service", expression = "java(convertToService(bean))") IotThingModelDO convert(IotThingModelSaveReqVO bean); - // 将 DO 转换为 RespVO - @Mapping(target = "property", source = "property") - @Mapping(target = "event", source = "event") - @Mapping(target = "service", source = "service") - IotThingModelRespVO convert(IotThingModelDO bean); - - // 批量转换 - List convertList(List list); - @Named("convertToProperty") default ThingModelProperty convertToProperty(IotThingModelSaveReqVO bean) { if (Objects.equals(bean.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index 1b8cf79e0..c57ab76ba 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -58,9 +58,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); // 1.2 功能名称在同一产品下是否唯一 validateNameUnique(createReqVO.getProductId(), createReqVO.getName()); - // 1.3 系统保留字段,不能用于标识符定义 - validateNotDefaultEventAndService(createReqVO.getIdentifier()); - // 1.4 校验产品状态,发布状态下,不允许新增功能 + // 1.3 校验产品状态,发布状态下,不允许新增功能 validateProductStatus(createReqVO.getProductId()); // 2. 插入数据库 @@ -71,7 +69,6 @@ public class IotThingModelServiceImpl implements IotThingModelService { if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } - // TODO @puhui999: 服务和事件的情况 method 怎么设置?在前端设置还是后端设置? // 4. 删除缓存 deleteThingModelListCache(createReqVO.getProductKey()); @@ -177,14 +174,6 @@ public class IotThingModelServiceImpl implements IotThingModelService { } } - // TODO @芋艿:在 review 下 - private void validateNotDefaultEventAndService(String identifier) { - // 系统保留字段,不能用于标识符定义 - if (StrUtil.equalsAny(identifier, "set", "get", "post", "property", "event", "time", "value")) { - throw exception(THING_MODEL_IDENTIFIER_INVALID); - } - } - private void validateNameUnique(Long productId, String name) { IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndName(productId, name); if (thingModel != null) { @@ -193,6 +182,12 @@ public class IotThingModelServiceImpl implements IotThingModelService { } private void validateIdentifierUnique(Long productId, String identifier) { + // 系统保留字段,不能用于标识符定义 + if (StrUtil.equalsAny(identifier, "set", "get", "post", "property", "event", "time", "value")) { + throw exception(THING_MODEL_IDENTIFIER_INVALID); + } + + // 校验唯一 IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (thingModel != null) { throw exception(THING_MODEL_IDENTIFIER_EXISTS); @@ -215,17 +210,17 @@ public class IotThingModelServiceImpl implements IotThingModelService { // 2.1 生成属性上报事件 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties); if (propertyPostEvent != null) { - newThingModels.add(buildEventThingModelDO(productId, productKey, propertyPostEvent, "属性上报事件")); + newThingModels.add(buildEventThingModel(productId, productKey, propertyPostEvent, "属性上报事件")); } // 2.2 生成属性设置服务 ThingModelService propertySetService = generatePropertySetService(properties); if (propertySetService != null) { - newThingModels.add(buildServiceThingModelDO(productId, productKey, propertySetService, "属性设置服务")); + newThingModels.add(buildServiceThingModel(productId, productKey, propertySetService, "属性设置服务")); } // 2.3 生成属性获取服务 ThingModelService propertyGetService = generatePropertyGetService(properties); if (propertyGetService != null) { - newThingModels.add(buildServiceThingModelDO(productId, productKey, propertyGetService, "属性获取服务")); + newThingModels.add(buildServiceThingModel(productId, productKey, propertyGetService, "属性获取服务")); } // 3.1 获取数据库中的默认的旧事件和服务列表 @@ -269,8 +264,8 @@ public class IotThingModelServiceImpl implements IotThingModelService { /** * 构建事件功能对象 */ - private IotThingModelDO buildEventThingModelDO(Long productId, String productKey, - ThingModelEvent event, String description) { + private IotThingModelDO buildEventThingModel(Long productId, String productKey, + ThingModelEvent event, String description) { return new IotThingModelDO().setProductId(productId).setProductKey(productKey) .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(description) .setType(IotThingModelTypeEnum.EVENT.getType()).setEvent(event); @@ -279,13 +274,14 @@ public class IotThingModelServiceImpl implements IotThingModelService { /** * 构建服务功能对象 */ - private IotThingModelDO buildServiceThingModelDO(Long productId, String productKey, - ThingModelService service, String description) { + private IotThingModelDO buildServiceThingModel(Long productId, String productKey, + ThingModelService service, String description) { return new IotThingModelDO().setProductId(productId).setProductKey(productKey) .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(description) .setType(IotThingModelTypeEnum.SERVICE.getType()).setService(service); } + // TODO @haohao:是不是不用生成这个?目前属性上报,是个批量接口 /** * 生成属性上报事件 */ @@ -301,6 +297,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { .setOutputParams(buildInputOutputParam(thingModels, IotThingModelParamDirectionEnum.OUTPUT)); } + // TODO @haohao:是不是不用生成这个?目前属性上报,是个批量接口 /** * 生成属性设置服务 */ From b46e630912e6f4c11623b7341ff7a15de0aea0f5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 4 Feb 2025 17:34:04 +0800 Subject: [PATCH 150/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9Aplugin=20=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/plugin/PluginInfoController.java | 1 + .../plugin/vo/info/PluginInfoSaveReqVO.java | 2 +- .../dataobject/plugin/IotPluginInfoDO.java | 6 ++- ...ation.java => IotPluginConfiguration.java} | 28 ++++++---- .../core/CustomPluginStateListener.java | 25 --------- .../plugin/core/IotPluginStartRunner.java | 52 +++++++++++++++++++ .../plugin/core/IotPluginStateListener.java | 21 ++++++++ .../framework/plugin/core/PluginStart.java | 49 ----------------- .../service/plugin/IotPluginInfoService.java | 2 +- .../plugin/IotPluginInfoServiceImpl.java | 40 ++++++-------- .../service/rule/IotRuleSceneServiceImpl.java | 5 +- 11 files changed, 120 insertions(+), 111 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/{UnifiedConfiguration.java => IotPluginConfiguration.java} (52%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/CustomPluginStateListener.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStateListener.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/PluginStart.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java index 7d9472d24..9b7800159 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java @@ -78,6 +78,7 @@ public class PluginInfoController { return success(true); } + // TODO @haohao:要不独立一个 VO,不用 PluginInfoSaveReqVO @PutMapping("/update-status") @Operation(summary = "修改插件状态") @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoSaveReqVO.java index e6453b457..c2a16ac49 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoSaveReqVO.java @@ -13,7 +13,7 @@ public class PluginInfoSaveReqVO { // TODO @haohao:一些枚举字段,需要加枚举校验。例如说,deployType、status、type 等 - @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") + @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") private Long id; @Schema(description = "插件包标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInfoDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInfoDO.java index f55a9f5ba..3a9c588d4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInfoDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInfoDO.java @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; +// TODO @haohao:建议 IotPluginInfoDO 改成 IotPluginConfigDO,插件配置。项目里,暂时没有用 info 作为配置的哈。 /** * IoT 插件信息 DO * @@ -38,7 +39,7 @@ public class IotPluginInfoDO extends BaseDO { */ private String name; /** - * 描述 + * 插件描述 */ private String description; /** @@ -68,12 +69,14 @@ public class IotPluginInfoDO extends BaseDO { */ // TODO @芋艿:枚举字段 private String protocol; + // TODO @haohao:这个字段,是不是直接用 CommonStatus,开启、禁用;然后插件实例那,online 是否在线 /** * 状态 *

* 枚举 {@link IotPluginStatusEnum} */ private Integer status; + // TODO @芋艿:configSchema、config 示例字段 /** * 插件配置项描述信息 @@ -83,6 +86,7 @@ public class IotPluginInfoDO extends BaseDO { * 插件配置信息 */ private String config; + // TODO @芋艿:script 后续的使用 /** * 插件脚本 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/UnifiedConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/IotPluginConfiguration.java similarity index 52% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/UnifiedConfiguration.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/IotPluginConfiguration.java index 849b6b16f..b695cbe39 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/UnifiedConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/IotPluginConfiguration.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.iot.framework.plugin.config; -import cn.iocoder.yudao.module.iot.framework.plugin.core.CustomPluginStateListener; +import cn.iocoder.yudao.module.iot.framework.plugin.core.IotPluginStartRunner; +import cn.iocoder.yudao.module.iot.framework.plugin.core.IotPluginStateListener; +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInfoService; import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; import org.springframework.beans.factory.annotation.Value; @@ -9,16 +11,24 @@ import org.springframework.context.annotation.Configuration; import java.nio.file.Paths; -// TODO @芋艿:需要 review 下 -@Slf4j +/** + * IoT 插件配置类 + * + * @author haohao + */ @Configuration -public class UnifiedConfiguration { - - @Value("${pf4j.pluginsDir:pluginsDir}") - private String pluginsDir; +@Slf4j +public class IotPluginConfiguration { @Bean - public SpringPluginManager pluginManager() { + public IotPluginStartRunner pluginStartRunner(SpringPluginManager pluginManager, + IotPluginInfoService pluginInfoService) { + return new IotPluginStartRunner(pluginManager, pluginInfoService); + } + + // TODO @芋艿:需要 review 下 + @Bean + public SpringPluginManager pluginManager(@Value("${pf4j.pluginsDir:pluginsDir}") String pluginsDir) { log.info("[init][实例化 SpringPluginManager]"); SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { // SpringPluginManager springPluginManager = new SpringPluginManager() { @@ -30,7 +40,7 @@ public class UnifiedConfiguration { } }; - springPluginManager.addPluginStateListener(new CustomPluginStateListener()); + springPluginManager.addPluginStateListener(new IotPluginStateListener()); return springPluginManager; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/CustomPluginStateListener.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/CustomPluginStateListener.java deleted file mode 100644 index 9833a815b..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/CustomPluginStateListener.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.iot.framework.plugin.core; - -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginStateEvent; -import org.pf4j.PluginStateListener; -import org.springframework.stereotype.Component; - -// TODO @芋艿:需要 review 下 -@Component -@Slf4j -public class CustomPluginStateListener implements PluginStateListener { - - @Override - public void pluginStateChanged(PluginStateEvent event) { - // 1. 获取插件ID - String pluginId = event.getPlugin().getPluginId(); - // 2. 获取插件旧状态 - String oldState = event.getOldState().toString(); - // 3. 获取插件新状态 - String newState = event.getPluginState().toString(); - // 4. 打印日志信息 - log.info("插件的状态 '{}' 已更改为 '{}' 至 '{}'", pluginId, oldState, newState); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java new file mode 100644 index 000000000..f3654bc30 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.iot.framework.plugin.core; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInfoService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.spring.SpringPluginManager; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; + +import java.util.List; + +/** + * IoT 插件启动 Runner + * + * 用于 Spring Boot 启动时,启动 {@link IotPluginDeployTypeEnum#JAR} 部署类型的插件 + */ +@RequiredArgsConstructor +@Slf4j +public class IotPluginStartRunner implements ApplicationRunner { + + private final SpringPluginManager springPluginManager; + + private final IotPluginInfoService pluginInfoService; + + @Override + public void run(ApplicationArguments args) { + List pluginInfoList = TenantUtils.executeIgnore( + // TODO @haohao:需要查询部署类型哈 + () -> pluginInfoService.getPluginInfoListByStatus(IotPluginStatusEnum.RUNNING.getStatus())); + if (CollUtil.isEmpty(pluginInfoList)) { + log.info("[run][没有需要启动的插件]"); + return; + } + + // 遍历插件列表,逐个启动 + pluginInfoList.forEach(pluginInfo -> { + try { + log.info("[run][插件({}) 启动开始]", pluginInfo.getPluginKey()); + springPluginManager.startPlugin(pluginInfo.getPluginKey()); + log.info("[run][插件({}) 启动完成]", pluginInfo.getPluginKey()); + } catch (Exception e) { + log.error("[run][插件({}) 启动异常]", pluginInfo.getPluginKey(), e); + } + }); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStateListener.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStateListener.java new file mode 100644 index 000000000..bbc73c619 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStateListener.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.framework.plugin.core; + +import lombok.extern.slf4j.Slf4j; +import org.pf4j.PluginStateEvent; +import org.pf4j.PluginStateListener; + +/** + * IoT 插件状态监听器,用于 log 插件的状态变化 + * + * @author haohao + */ +@Slf4j +public class IotPluginStateListener implements PluginStateListener { + + @Override + public void pluginStateChanged(PluginStateEvent event) { + log.info("[pluginStateChanged][插件({}) 状态变化,从 {} 变为 {}]", event.getPlugin().getPluginId(), + event.getOldState().toString(), event.getPluginState().toString()); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/PluginStart.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/PluginStart.java deleted file mode 100644 index 76b0fa67b..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/PluginStart.java +++ /dev/null @@ -1,49 +0,0 @@ -package cn.iocoder.yudao.module.iot.framework.plugin.core; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO; -import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; -import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInfoService; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.spring.SpringPluginManager; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.List; - -// TODO @芋艿:需要 review 下 -@Component -@Slf4j -public class PluginStart implements ApplicationRunner { - - @Resource - private IotPluginInfoService pluginInfoService; - - @Resource - private SpringPluginManager pluginManager; - - @Override - public void run(ApplicationArguments args) { - TenantUtils.executeIgnore(() -> { // 1. 忽略租户上下文执行 - List pluginInfoList = pluginInfoService - .getPluginInfoListByStatus(IotPluginStatusEnum.RUNNING.getStatus()); // 2. 获取运行中的插件列表 - if (CollUtil.isEmpty(pluginInfoList)) { // 3. 检查插件列表是否为空 - log.info("[run] 没有需要启动的插件"); // 4. 日志记录没有插件需要启动 - return; - } - pluginInfoList.forEach(pluginInfo -> { // 5. 使用lambda表达式遍历插件列表 - try { - log.info("[run][启动插件] pluginKey = {}", pluginInfo.getPluginKey()); // 6. 日志记录插件启动信息 - pluginManager.startPlugin(pluginInfo.getPluginKey()); // 7. 启动插件 - } catch (Exception e) { - log.error("[run][启动插件失败] pluginKey = {}", pluginInfo.getPluginKey(), e); // 8. 记录启动失败的日志 - } - }); - }); - - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoService.java index 3ac8680b8..1a8654ebc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoService.java @@ -14,7 +14,7 @@ import java.util.List; /** * IoT 插件信息 Service 接口 * - * @author 芋道源码 + * @author haohao */ public interface IotPluginInfoService { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoServiceImpl.java index c111da326..400f1e39e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoServiceImpl.java @@ -23,7 +23,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INFO_N /** * IoT 插件信息 Service 实现类 * - * @author 芋道源码 + * @author haohao */ @Service @Validated @@ -37,7 +37,7 @@ public class IotPluginInfoServiceImpl implements IotPluginInfoService { private IotPluginInstanceService pluginInstanceService; @Resource - private SpringPluginManager pluginManager; + private SpringPluginManager springPluginManager; @Override public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) { @@ -60,18 +60,17 @@ public class IotPluginInfoServiceImpl implements IotPluginInfoService { public void deletePluginInfo(Long id) { // 1.1 校验存在 IotPluginInfoDO pluginInfoDO = validatePluginInfoExists(id); - // 1.2 停止插件 + // 1.2 未开启状态,才允许删除 if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { throw exception(PLUGIN_INFO_DELETE_FAILED_RUNNING); } - // 2. 卸载插件 + // 2.1 卸载插件 pluginInstanceService.stopAndUnloadPlugin(pluginInfoDO.getPluginKey()); - - // 3. 删除插件文件 + // 2.2 删除插件文件 pluginInstanceService.deletePluginFile(pluginInfoDO); - // 4. 删除插件信息 + // 3. 删除插件信息 pluginInfoMapper.deleteById(id); } @@ -97,17 +96,18 @@ public class IotPluginInfoServiceImpl implements IotPluginInfoService { public void uploadFile(Long id, MultipartFile file) { // 1. 校验插件信息是否存在 IotPluginInfoDO pluginInfoDo = validatePluginInfoExists(id); + // TODO @haohao:最好校验下 file 相关参数,是否完整,类似:version 之类是不是可以解析到 - // 2. 停止并卸载旧的插件 + // 2.1 停止并卸载旧的插件 pluginInstanceService.stopAndUnloadPlugin(pluginInfoDo.getPluginKey()); - - // 3 上传新的插件文件,更新插件启用状态文件 + // 2.2 上传新的插件文件,更新插件启用状态文件 String pluginKeyNew = pluginInstanceService.uploadAndLoadNewPlugin(file); - // 4. 更新插件信息 + // 3. 更新插件信息 updatePluginInfo(pluginInfoDo, pluginKeyNew, file); } + // TODO @haohao:这个方法,要不合并到 uploadFile 里; /** * 更新插件信息 * @@ -116,18 +116,15 @@ public class IotPluginInfoServiceImpl implements IotPluginInfoService { * @param file 文件 */ private void updatePluginInfo(IotPluginInfoDO pluginInfoDo, String pluginKeyNew, MultipartFile file) { - // 创建新的插件信息对象并链式设置属性 IotPluginInfoDO updatedPluginInfo = new IotPluginInfoDO() .setId(pluginInfoDo.getId()) .setPluginKey(pluginKeyNew) - .setStatus(IotPluginStatusEnum.STOPPED.getStatus()) + .setStatus(IotPluginStatusEnum.STOPPED.getStatus()) // TODO @haohao:这个状态,是不是非 stop 哈? .setFileName(file.getOriginalFilename()) - .setScript("") - .setConfigSchema(pluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()) - .setVersion(pluginManager.getPlugin(pluginKeyNew).getDescriptor().getVersion()) - .setDescription(pluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()); - - // 执行更新 + .setScript("") // TODO @haohao:这个设置为 "" 会不会覆盖数据里的哈?应该从插件里读取?未来? + .setConfigSchema(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()) + .setVersion(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getVersion()) + .setDescription(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()); pluginInfoMapper.updateById(updatedPluginInfo); } @@ -140,10 +137,7 @@ public class IotPluginInfoServiceImpl implements IotPluginInfoService { pluginInstanceService.updatePluginStatus(pluginInfoDo, status); // 3. 更新数据库中的插件状态 - IotPluginInfoDO updatedPluginInfo = new IotPluginInfoDO(); - updatedPluginInfo.setId(id); - updatedPluginInfo.setStatus(status); - pluginInfoMapper.updateById(updatedPluginInfo); + pluginInfoMapper.updateById(new IotPluginInfoDO().setId(id).setStatus(status)); } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java index 7f8ff51f1..2219d4bad 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java @@ -404,7 +404,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { // 无 + 禁用、开启:1)存在,删除;TODO 测试:直接删除???(结论:可以)deleteJob // - if (true) { + if (false) { Long id = 1L; Map jobDataMap = IotRuleSceneJob.buildJobDataMap(id); schedulerManager.addOrUpdateJob(IotRuleSceneJob.class, @@ -417,7 +417,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { schedulerManager.pauseJob(IotRuleSceneJob.buildJobName(id)); } if (true) { - + Long id = 1L; + schedulerManager.deleteJob(IotRuleSceneJob.buildJobName(id)); } } From 6eadbba34554f2364f7bb77daed829bec8945637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 5 Feb 2025 21:44:23 +0800 Subject: [PATCH 151/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E3=80=91IoT=EF=BC=9A=E9=87=8D=E6=9E=84=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E9=85=8D=E7=BD=AE=E7=AE=A1=E7=90=86=EF=BC=8C=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=20PluginInfo=20=E4=B8=BA=20PluginConfig?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../yudao-spring-boot-starter-mybatis/pom.xml | 4 + .../module/iot/enums/ErrorCodeConstants.java | 7 +- yudao-module-iot/yudao-module-iot-biz/pom.xml | 5 - .../admin/plugin/PluginConfigController.java | 90 +++++++++ .../admin/plugin/PluginInfoController.java | 90 --------- .../PluginConfigImportReqVO.java} | 4 +- .../PluginConfigPageReqVO.java} | 6 +- .../PluginConfigRespVO.java} | 6 +- .../PluginConfigSaveReqVO.java} | 6 +- .../vo/config/PluginConfigStatusReqVO.java | 19 ++ ...uginInfoDO.java => IotPluginConfigDO.java} | 12 +- .../plugin/IotPluginInstanceDO.java | 2 +- .../mysql/plugin/IotPluginConfigMapper.java | 33 +++ .../dal/mysql/plugin/IotPluginInfoMapper.java | 32 --- .../plugin/config/IotPluginConfiguration.java | 7 +- .../plugin/core/IotPluginStartRunner.java | 27 +-- .../plugin/IotPluginConfigService.java | 100 ++++++++++ .../plugin/IotPluginConfigServiceImpl.java | 188 ++++++++++++++++++ .../service/plugin/IotPluginInfoService.java | 92 --------- .../plugin/IotPluginInfoServiceImpl.java | 158 --------------- .../plugin/IotPluginInstanceService.java | 10 +- .../plugin/IotPluginInstanceServiceImpl.java | 20 +- yudao-server/pom.xml | 10 +- 24 files changed, 494 insertions(+), 436 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginConfigController.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/{info/PluginInfoImportReqVO.java => config/PluginConfigImportReqVO.java} (83%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/{info/PluginInfoPageReqVO.java => config/PluginConfigPageReqVO.java} (71%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/{info/PluginInfoRespVO.java => config/PluginConfigRespVO.java} (90%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/{info/PluginInfoSaveReqVO.java => config/PluginConfigSaveReqVO.java} (91%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigStatusReqVO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/{IotPluginInfoDO.java => IotPluginConfigDO.java} (82%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginConfigMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInfoMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigServiceImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoServiceImpl.java diff --git a/pom.xml b/pom.xml index 43da0c8d0..a34330972 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ - + yudao-module-iot ${project.artifactId} diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml index 1f3c9144b..2a14c88b8 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -63,6 +63,10 @@ opengauss-jdbc true + + com.taosdata.jdbc + taos-jdbcdriver + com.alibaba diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index ed9b0ef13..e85d4b368 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -39,12 +39,13 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在"); ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除"); - // ========== 插件信息 1-050-006-000 ========== - ErrorCode PLUGIN_INFO_NOT_EXISTS = new ErrorCode(1_050_006_000, "插件信息不存在"); + // ========== 插件配置 1-050-006-000 ========== + ErrorCode PLUGIN_CONFIG_NOT_EXISTS = new ErrorCode(1_050_006_000, "插件配置不存在"); ErrorCode PLUGIN_INSTALL_FAILED = new ErrorCode(1_050_006_001, "插件安装失败"); ErrorCode PLUGIN_INSTALL_FAILED_FILE_NAME_NOT_MATCH = new ErrorCode(1_050_006_002, "插件安装失败,文件名与原插件id不匹配"); - ErrorCode PLUGIN_INFO_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件"); + ErrorCode PLUGIN_CONFIG_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件"); ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效"); + ErrorCode PLUGIN_CONFIG_KEY_DUPLICATE = new ErrorCode(1_050_006_005, "插件标识已存在"); // ========== 插件实例 1-050-007-000 ========== diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index cc3141939..805205a16 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -52,11 +52,6 @@ yudao-spring-boot-starter-redis - - com.taosdata.jdbc - taos-jdbcdriver - - cn.iocoder.boot diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginConfigController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginConfigController.java new file mode 100644 index 000000000..e21b10241 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginConfigController.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugin; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigImportReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigStatusReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO; +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginConfigService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 插件配置") +@RestController +@RequestMapping("/iot/plugin-config") +@Validated +public class PluginConfigController { + + @Resource + private IotPluginConfigService pluginConfigService; + + @PostMapping("/create") + @Operation(summary = "创建插件配置") + @PreAuthorize("@ss.hasPermission('iot:plugin-config:create')") + public CommonResult createPluginConfig(@Valid @RequestBody PluginConfigSaveReqVO createReqVO) { + return success(pluginConfigService.createPluginConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新插件配置") + @PreAuthorize("@ss.hasPermission('iot:plugin-config:update')") + public CommonResult updatePluginConfig(@Valid @RequestBody PluginConfigSaveReqVO updateReqVO) { + pluginConfigService.updatePluginConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除插件配置") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:plugin-config:delete')") + public CommonResult deletePluginConfig(@RequestParam("id") Long id) { + pluginConfigService.deletePluginConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得插件配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:plugin-config:query')") + public CommonResult getPluginConfig(@RequestParam("id") Long id) { + IotPluginConfigDO pluginConfig = pluginConfigService.getPluginConfig(id); + return success(BeanUtils.toBean(pluginConfig, PluginConfigRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得插件配置分页") + @PreAuthorize("@ss.hasPermission('iot:plugin-config:query')") + public CommonResult> getPluginConfigPage(@Valid PluginConfigPageReqVO pageReqVO) { + PageResult pageResult = pluginConfigService.getPluginConfigPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, PluginConfigRespVO.class)); + } + + @PostMapping("/upload-file") + @Operation(summary = "上传插件文件") + @PreAuthorize("@ss.hasPermission('iot:plugin-config:update')") + public CommonResult uploadFile(@Valid PluginConfigImportReqVO reqVO) { + pluginConfigService.uploadFile(reqVO.getId(), reqVO.getFile()); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "修改插件状态") + @PreAuthorize("@ss.hasPermission('iot:plugin-config:update')") + public CommonResult updatePluginConfigStatus(@Valid @RequestBody PluginConfigStatusReqVO reqVO) { + pluginConfigService.updatePluginStatus(reqVO.getId(), reqVO.getStatus()); + return success(true); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java deleted file mode 100644 index 9b7800159..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java +++ /dev/null @@ -1,90 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugin; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoImportReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO; -import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInfoService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - IoT 插件信息") -@RestController -@RequestMapping("/iot/plugin-info") -@Validated -public class PluginInfoController { - - @Resource - private IotPluginInfoService pluginInfoService; - - @PostMapping("/create") - @Operation(summary = "创建插件信息") - @PreAuthorize("@ss.hasPermission('iot:plugin-info:create')") - public CommonResult createPluginInfo(@Valid @RequestBody PluginInfoSaveReqVO createReqVO) { - return success(pluginInfoService.createPluginInfo(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新插件信息") - @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") - public CommonResult updatePluginInfo(@Valid @RequestBody PluginInfoSaveReqVO updateReqVO) { - pluginInfoService.updatePluginInfo(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除插件信息") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:plugin-info:delete')") - public CommonResult deletePluginInfo(@RequestParam("id") Long id) { - pluginInfoService.deletePluginInfo(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得插件信息") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") - public CommonResult getPluginInfo(@RequestParam("id") Long id) { - IotPluginInfoDO pluginInfo = pluginInfoService.getPluginInfo(id); - return success(BeanUtils.toBean(pluginInfo, PluginInfoRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得插件信息分页") - @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") - public CommonResult> getPluginInfoPage(@Valid PluginInfoPageReqVO pageReqVO) { - PageResult pageResult = pluginInfoService.getPluginInfoPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, PluginInfoRespVO.class)); - } - - @PostMapping("/upload-file") - @Operation(summary = "上传插件文件") - @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") - public CommonResult uploadFile(@Valid PluginInfoImportReqVO reqVO) { - pluginInfoService.uploadFile(reqVO.getId(), reqVO.getFile()); - return success(true); - } - - // TODO @haohao:要不独立一个 VO,不用 PluginInfoSaveReqVO - @PutMapping("/update-status") - @Operation(summary = "修改插件状态") - @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") - public CommonResult updateUserStatus(@Valid @RequestBody PluginInfoSaveReqVO reqVO) { - pluginInfoService.updatePluginStatus(reqVO.getId(), reqVO.getStatus()); - return success(true); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoImportReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigImportReqVO.java similarity index 83% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoImportReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigImportReqVO.java index fc2f8da8a..b9b277a54 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoImportReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigImportReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; @@ -7,7 +7,7 @@ import org.springframework.web.multipart.MultipartFile; @Schema(description = "管理后台 - IoT 插件上传 Request VO") @Data -public class PluginInfoImportReqVO { +public class PluginConfigImportReqVO { @Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") private Long id; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigPageReqVO.java similarity index 71% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigPageReqVO.java index cac975be1..1666d5d6b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigPageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; @@ -6,9 +6,9 @@ import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -@Schema(description = "管理后台 - IoT 插件信息分页 Request VO") +@Schema(description = "管理后台 - IoT 插件配置分页 Request VO") @Data -public class PluginInfoPageReqVO extends PageParam { +public class PluginConfigPageReqVO extends PageParam { @Schema(description = "插件名称", example = "http") private String name; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigRespVO.java similarity index 90% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigRespVO.java index 685d408de..2b8c4dcde 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigRespVO.java @@ -1,13 +1,13 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; -@Schema(description = "管理后台 - IoT 插件信息 Response VO") +@Schema(description = "管理后台 - IoT 插件配置 Response VO") @Data -public class PluginInfoRespVO { +public class PluginConfigRespVO { @Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") private Long id; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigSaveReqVO.java similarity index 91% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigSaveReqVO.java index c2a16ac49..e48869d64 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/info/PluginInfoSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigSaveReqVO.java @@ -1,13 +1,13 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info; +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -@Schema(description = "管理后台 - IoT 插件信息新增/修改 Request VO") +@Schema(description = "管理后台 - IoT 插件配置新增/修改 Request VO") @Data -public class PluginInfoSaveReqVO { +public class PluginConfigSaveReqVO { // TODO @haohao:新增的字段有点多,每个都需要哇? diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigStatusReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigStatusReqVO.java new file mode 100644 index 000000000..eae4aa0a2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/config/PluginConfigStatusReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 插件配置状态 Request VO") +@Data +public class PluginConfigStatusReqVO { + + @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") + private Long id; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED) + @InEnum(IotPluginStatusEnum.class) + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInfoDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInfoDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java index 3a9c588d4..d0695f896 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInfoDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.plugin; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; @@ -9,21 +10,20 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; -// TODO @haohao:建议 IotPluginInfoDO 改成 IotPluginConfigDO,插件配置。项目里,暂时没有用 info 作为配置的哈。 /** - * IoT 插件信息 DO + * IoT 插件配置 DO * * @author 芋道源码 */ -@TableName("iot_plugin_info") -@KeySequence("iot_plugin_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName("iot_plugin_config") +@KeySequence("iot_plugin_config_seq") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor -public class IotPluginInfoDO extends BaseDO { +public class IotPluginConfigDO extends BaseDO { /** * 主键 ID @@ -73,7 +73,7 @@ public class IotPluginInfoDO extends BaseDO { /** * 状态 *

- * 枚举 {@link IotPluginStatusEnum} + * 枚举 {@link CommonStatusEnum} */ private Integer status; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java index 1def80185..71d741b05 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java @@ -31,7 +31,7 @@ public class IotPluginInstanceDO extends BaseDO { /** * 插件编号 *

- * 关联 {@link IotPluginInfoDO#getId()} + * 关联 {@link IotPluginConfigDO#getId()} */ private Long pluginId; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginConfigMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginConfigMapper.java new file mode 100644 index 000000000..0e2163a3f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginConfigMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.plugin; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface IotPluginConfigMapper extends BaseMapperX { + + default PageResult selectPage(PluginConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotPluginConfigDO::getName, reqVO.getName()) + .eqIfPresent(IotPluginConfigDO::getStatus, reqVO.getStatus()) + .orderByDesc(IotPluginConfigDO::getId)); + } + + default List selectListByStatusAndDeployType(Integer status, Integer deployType) { + return selectList(new LambdaQueryWrapperX() + .eq(IotPluginConfigDO::getStatus, status) + .eq(IotPluginConfigDO::getDeployType, deployType) + .orderByAsc(IotPluginConfigDO::getId)); + } + + default IotPluginConfigDO selectByPluginKey(String pluginKey) { + return selectOne(IotPluginConfigDO::getPluginKey, pluginKey); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInfoMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInfoMapper.java deleted file mode 100644 index 88058185f..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInfoMapper.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.plugin; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -@Mapper -public interface IotPluginInfoMapper extends BaseMapperX { - - default PageResult selectPage(PluginInfoPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(IotPluginInfoDO::getName, reqVO.getName()) - .eqIfPresent(IotPluginInfoDO::getStatus, reqVO.getStatus()) - .orderByDesc(IotPluginInfoDO::getId)); - } - - default List selectListByStatus(Integer status) { - return selectList(new LambdaQueryWrapperX() - .eq(IotPluginInfoDO::getStatus, status) - .orderByAsc(IotPluginInfoDO::getId)); - } - - default IotPluginInfoDO selectByPluginKey(String pluginKey) { - return selectOne(IotPluginInfoDO::getPluginKey, pluginKey); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/IotPluginConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/IotPluginConfiguration.java index b695cbe39..0a2812ac8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/IotPluginConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/config/IotPluginConfiguration.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.framework.plugin.config; import cn.iocoder.yudao.module.iot.framework.plugin.core.IotPluginStartRunner; import cn.iocoder.yudao.module.iot.framework.plugin.core.IotPluginStateListener; -import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInfoService; +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginConfigService; import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; import org.springframework.beans.factory.annotation.Value; @@ -22,8 +22,8 @@ public class IotPluginConfiguration { @Bean public IotPluginStartRunner pluginStartRunner(SpringPluginManager pluginManager, - IotPluginInfoService pluginInfoService) { - return new IotPluginStartRunner(pluginManager, pluginInfoService); + IotPluginConfigService pluginConfigService) { + return new IotPluginStartRunner(pluginManager, pluginConfigService); } // TODO @芋艿:需要 review 下 @@ -31,7 +31,6 @@ public class IotPluginConfiguration { public SpringPluginManager pluginManager(@Value("${pf4j.pluginsDir:pluginsDir}") String pluginsDir) { log.info("[init][实例化 SpringPluginManager]"); SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { -// SpringPluginManager springPluginManager = new SpringPluginManager() { @Override public void startPlugins() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java index f3654bc30..8036eb2d4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java @@ -2,10 +2,10 @@ package cn.iocoder.yudao.module.iot.framework.plugin.core; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; -import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInfoService; +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginConfigService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; @@ -25,28 +25,29 @@ public class IotPluginStartRunner implements ApplicationRunner { private final SpringPluginManager springPluginManager; - private final IotPluginInfoService pluginInfoService; + private final IotPluginConfigService pluginConfigService; @Override public void run(ApplicationArguments args) { - List pluginInfoList = TenantUtils.executeIgnore( - // TODO @haohao:需要查询部署类型哈 - () -> pluginInfoService.getPluginInfoListByStatus(IotPluginStatusEnum.RUNNING.getStatus())); - if (CollUtil.isEmpty(pluginInfoList)) { + List pluginConfigList = TenantUtils.executeIgnore( + // 查询运行中且部署类型为 JAR 的插件 + () -> pluginConfigService.getPluginConfigListByStatusAndDeployType( + IotPluginStatusEnum.RUNNING.getStatus(), IotPluginDeployTypeEnum.JAR.getDeployType())); + if (CollUtil.isEmpty(pluginConfigList)) { log.info("[run][没有需要启动的插件]"); return; } // 遍历插件列表,逐个启动 - pluginInfoList.forEach(pluginInfo -> { + pluginConfigList.forEach(pluginConfig -> { try { - log.info("[run][插件({}) 启动开始]", pluginInfo.getPluginKey()); - springPluginManager.startPlugin(pluginInfo.getPluginKey()); - log.info("[run][插件({}) 启动完成]", pluginInfo.getPluginKey()); + log.info("[run][插件({}) 启动开始]", pluginConfig.getPluginKey()); + springPluginManager.startPlugin(pluginConfig.getPluginKey()); + log.info("[run][插件({}) 启动完成]", pluginConfig.getPluginKey()); } catch (Exception e) { - log.error("[run][插件({}) 启动异常]", pluginInfo.getPluginKey(), e); + log.error("[run][插件({}) 启动异常]", pluginConfig.getPluginKey(), e); } }); } -} +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigService.java new file mode 100644 index 000000000..8b6610f15 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigService.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.iot.service.plugin; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * IoT 插件配置 Service 接口 + * + * @author haohao + */ +public interface IotPluginConfigService { + + /** + * 创建插件配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createPluginConfig(@Valid PluginConfigSaveReqVO createReqVO); + + /** + * 更新插件配置 + * + * @param updateReqVO 更新信息 + */ + void updatePluginConfig(@Valid PluginConfigSaveReqVO updateReqVO); + + /** + * 删除插件配置 + * + * @param id 编号 + */ + void deletePluginConfig(Long id); + + /** + * 获得插件配置 + * + * @param id 编号 + * @return 插件配置 + */ + IotPluginConfigDO getPluginConfig(Long id); + + /** + * 获得插件配置分页 + * + * @param pageReqVO 分页查询 + * @return 插件配置分页 + */ + PageResult getPluginConfigPage(PluginConfigPageReqVO pageReqVO); + + /** + * 上传插件的 JAR 包 + * + * @param id 插件id + * @param file 文件 + */ + void uploadFile(Long id, MultipartFile file); + + /** + * 更新插件的状态 + * + * @param id 插件id + * @param status 状态 {@link IotPluginStatusEnum} + */ + void updatePluginStatus(Long id, Integer status); + + /** + * 获得插件配置列表 + * + * @return 插件配置列表 + */ + List getPluginConfigList(); + + /** + * 根据状态和部署类型获得插件配置列表 + * + * @param status 状态 {@link IotPluginStatusEnum} + * @param deployType 部署类型 {@link IotPluginDeployTypeEnum} + * @return 插件配置列表 + */ + List getPluginConfigListByStatusAndDeployType(Integer status, Integer deployType); + + /** + * 根据插件包标识符获取插件配置 + * + * @param pluginKey 插件包标识符 + * @return 插件配置 + */ + IotPluginConfigDO getPluginConfigByPluginKey(@NotEmpty(message = "插件包标识符不能为空") String pluginKey); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigServiceImpl.java new file mode 100644 index 000000000..18376bc57 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginConfigServiceImpl.java @@ -0,0 +1,188 @@ +package cn.iocoder.yudao.module.iot.service.plugin; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO; +import cn.iocoder.yudao.module.iot.dal.mysql.plugin.IotPluginConfigMapper; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.PluginWrapper; +import org.pf4j.spring.SpringPluginManager; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +/** + * IoT 插件配置 Service 实现类 + * + * @author haohao + */ +@Service +@Validated +@Slf4j +public class IotPluginConfigServiceImpl implements IotPluginConfigService { + + @Resource + private IotPluginConfigMapper pluginConfigMapper; + + @Resource + private IotPluginInstanceService pluginInstanceService; + + @Resource + private SpringPluginManager springPluginManager; + + @Override + public Long createPluginConfig(PluginConfigSaveReqVO createReqVO) { + // 1. 校验插件标识唯一性:确保没有其他配置使用相同的 pluginKey(新建时 id 为 null) + validatePluginKeyUnique(null, createReqVO.getPluginKey()); + IotPluginConfigDO pluginConfig = BeanUtils.toBean(createReqVO, IotPluginConfigDO.class); + // 2. 插入插件配置到数据库 + pluginConfigMapper.insert(pluginConfig); + return pluginConfig.getId(); + } + + @Override + public void updatePluginConfig(PluginConfigSaveReqVO updateReqVO) { + // 1. 校验插件配置是否存在:根据传入 ID 判断记录是否存在 + validatePluginConfigExists(updateReqVO.getId()); + // 2. 校验插件标识唯一性:确保更新后的 pluginKey 没有被其他记录占用 + validatePluginKeyUnique(updateReqVO.getId(), updateReqVO.getPluginKey()); + // 3. 将更新请求对象转换为插件配置数据对象 + IotPluginConfigDO updateObj = BeanUtils.toBean(updateReqVO, IotPluginConfigDO.class); + pluginConfigMapper.updateById(updateObj); + } + + /** + * 校验插件标识唯一性 + * + * @param id 当前插件配置的 ID(如果为 null 则说明为新建操作) + * @param pluginKey 待校验的插件标识 + */ + private void validatePluginKeyUnique(Long id, String pluginKey) { + // 1. 根据 pluginKey 从数据库中查询已有的插件配置 + IotPluginConfigDO pluginConfig = pluginConfigMapper.selectByPluginKey(pluginKey); + // 2. 如果查询到记录且记录的 ID 与当前 ID 不相同,则认为存在重复,抛出异常 + if (pluginConfig != null && !pluginConfig.getId().equals(id)) { + throw exception(PLUGIN_CONFIG_KEY_DUPLICATE); + } + } + + @Override + public void deletePluginConfig(Long id) { + // 1. 校验存在 + IotPluginConfigDO pluginConfigDO = validatePluginConfigExists(id); + // 2. 未开启状态,才允许删除 + if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginConfigDO.getStatus())) { + throw exception(PLUGIN_CONFIG_DELETE_FAILED_RUNNING); + } + + // 3. 卸载插件 + pluginInstanceService.stopAndUnloadPlugin(pluginConfigDO.getPluginKey()); + // 4. 删除插件文件 + pluginInstanceService.deletePluginFile(pluginConfigDO); + + // 5. 删除插件配置 + pluginConfigMapper.deleteById(id); + } + + /** + * 校验插件配置是否存在 + * + * @param id 插件配置编号 + * @return 插件配置 + */ + private IotPluginConfigDO validatePluginConfigExists(Long id) { + IotPluginConfigDO pluginConfig = pluginConfigMapper.selectById(id); + if (pluginConfig == null) { + throw exception(PLUGIN_CONFIG_NOT_EXISTS); + } + return pluginConfig; + } + + @Override + public IotPluginConfigDO getPluginConfig(Long id) { + return pluginConfigMapper.selectById(id); + } + + @Override + public PageResult getPluginConfigPage(PluginConfigPageReqVO pageReqVO) { + return pluginConfigMapper.selectPage(pageReqVO); + } + + @Override + public void uploadFile(Long id, MultipartFile file) { + // 1. 校验插件配置是否存在 + IotPluginConfigDO pluginConfigDO = validatePluginConfigExists(id); + + // 2.1 停止并卸载旧的插件 + pluginInstanceService.stopAndUnloadPlugin(pluginConfigDO.getPluginKey()); + // 2.2 上传新的插件文件,更新插件启用状态文件 + String pluginKeyNew = pluginInstanceService.uploadAndLoadNewPlugin(file); + + // 3. 校验 file 相关参数,是否完整 + validatePluginConfigFile(pluginKeyNew); + + // 4. 更新插件配置 + IotPluginConfigDO updatedPluginConfig = new IotPluginConfigDO() + .setId(pluginConfigDO.getId()) + .setPluginKey(pluginKeyNew) + .setStatus(IotPluginStatusEnum.STOPPED.getStatus()) // TODO @haohao:这个状态,是不是非 stop 哈? + .setFileName(file.getOriginalFilename()) + .setScript("") // TODO @haohao:这个设置为 "" 会不会覆盖数据里的哈?应该从插件里读取?未来? + .setConfigSchema(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()) + .setVersion(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getVersion()) + .setDescription(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()); + pluginConfigMapper.updateById(updatedPluginConfig); + } + + /** + * 校验 file 相关参数 + * + * @param pluginKeyNew 插件标识符 + */ + private void validatePluginConfigFile(String pluginKeyNew) { + // TODO @haohao:校验 file 相关参数,是否完整,类似:version 之类是不是可以解析到 + PluginWrapper plugin = springPluginManager.getPlugin(pluginKeyNew); + if (plugin == null) { + throw exception(PLUGIN_INSTALL_FAILED); + } + if (plugin.getDescriptor().getVersion() == null) { + throw exception(PLUGIN_INSTALL_FAILED); + } + } + + @Override + public void updatePluginStatus(Long id, Integer status) { + // 1. 校验插件配置是否存在 + IotPluginConfigDO pluginConfigDo = validatePluginConfigExists(id); + + // 2. 更新插件状态 + pluginInstanceService.updatePluginStatus(pluginConfigDo, status); + + // 3. 更新数据库中的插件状态 + pluginConfigMapper.updateById(new IotPluginConfigDO().setId(id).setStatus(status)); + } + + @Override + public List getPluginConfigList() { + return pluginConfigMapper.selectList(); + } + + @Override + public List getPluginConfigListByStatusAndDeployType(Integer status, Integer deployType) { + return pluginConfigMapper.selectListByStatusAndDeployType(status, deployType); + } + + @Override + public IotPluginConfigDO getPluginConfigByPluginKey(String pluginKey) { + return pluginConfigMapper.selectByPluginKey(pluginKey); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoService.java deleted file mode 100644 index 1a8654ebc..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoService.java +++ /dev/null @@ -1,92 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.plugin; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO; -import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; - -/** - * IoT 插件信息 Service 接口 - * - * @author haohao - */ -public interface IotPluginInfoService { - - /** - * 创建插件信息 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createPluginInfo(@Valid PluginInfoSaveReqVO createReqVO); - - /** - * 更新插件信息 - * - * @param updateReqVO 更新信息 - */ - void updatePluginInfo(@Valid PluginInfoSaveReqVO updateReqVO); - - /** - * 删除插件信息 - * - * @param id 编号 - */ - void deletePluginInfo(Long id); - - /** - * 获得插件信息 - * - * @param id 编号 - * @return 插件信息 - */ - IotPluginInfoDO getPluginInfo(Long id); - - /** - * 获得插件信息分页 - * - * @param pageReqVO 分页查询 - * @return 插件信息分页 - */ - PageResult getPluginInfoPage(PluginInfoPageReqVO pageReqVO); - - /** - * 上传插件的 JAR 包 - * - * @param id 插件id - * @param file 文件 - */ - void uploadFile(Long id, MultipartFile file); - - /** - * 更新插件的状态 - * - * @param id 插件id - * @param status 状态 {@link IotPluginStatusEnum} - */ - void updatePluginStatus(Long id, Integer status); - - /** - * 获得插件信息列表 - * - * @return 插件信息列表 - */ - List getPluginInfoList(); - - /** - * 根据状态获得插件信息列表 - * - * @param status 状态 {@link IotPluginStatusEnum} - * @return 插件信息列表 - */ - List getPluginInfoListByStatus(Integer status); - - IotPluginInfoDO getPluginInfoByPluginKey(@NotEmpty(message = "插件包标识符不能为空") String pluginKey); - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoServiceImpl.java deleted file mode 100644 index 400f1e39e..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoServiceImpl.java +++ /dev/null @@ -1,158 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.plugin; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO; -import cn.iocoder.yudao.module.iot.dal.mysql.plugin.IotPluginInfoMapper; -import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.spring.SpringPluginManager; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INFO_DELETE_FAILED_RUNNING; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INFO_NOT_EXISTS; - -/** - * IoT 插件信息 Service 实现类 - * - * @author haohao - */ -@Service -@Validated -@Slf4j -public class IotPluginInfoServiceImpl implements IotPluginInfoService { - - @Resource - private IotPluginInfoMapper pluginInfoMapper; - - @Resource - private IotPluginInstanceService pluginInstanceService; - - @Resource - private SpringPluginManager springPluginManager; - - @Override - public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) { - // TODO @haohao:pluginKey 唯一值 - IotPluginInfoDO pluginInfo = BeanUtils.toBean(createReqVO, IotPluginInfoDO.class); - pluginInfoMapper.insert(pluginInfo); - return pluginInfo.getId(); - } - - @Override - public void updatePluginInfo(PluginInfoSaveReqVO updateReqVO) { - // 校验存在 - validatePluginInfoExists(updateReqVO.getId()); - // 更新 - IotPluginInfoDO updateObj = BeanUtils.toBean(updateReqVO, IotPluginInfoDO.class); - pluginInfoMapper.updateById(updateObj); - } - - @Override - public void deletePluginInfo(Long id) { - // 1.1 校验存在 - IotPluginInfoDO pluginInfoDO = validatePluginInfoExists(id); - // 1.2 未开启状态,才允许删除 - if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { - throw exception(PLUGIN_INFO_DELETE_FAILED_RUNNING); - } - - // 2.1 卸载插件 - pluginInstanceService.stopAndUnloadPlugin(pluginInfoDO.getPluginKey()); - // 2.2 删除插件文件 - pluginInstanceService.deletePluginFile(pluginInfoDO); - - // 3. 删除插件信息 - pluginInfoMapper.deleteById(id); - } - - private IotPluginInfoDO validatePluginInfoExists(Long id) { - IotPluginInfoDO pluginInfo = pluginInfoMapper.selectById(id); - if (pluginInfo == null) { - throw exception(PLUGIN_INFO_NOT_EXISTS); - } - return pluginInfo; - } - - @Override - public IotPluginInfoDO getPluginInfo(Long id) { - return pluginInfoMapper.selectById(id); - } - - @Override - public PageResult getPluginInfoPage(PluginInfoPageReqVO pageReqVO) { - return pluginInfoMapper.selectPage(pageReqVO); - } - - @Override - public void uploadFile(Long id, MultipartFile file) { - // 1. 校验插件信息是否存在 - IotPluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // TODO @haohao:最好校验下 file 相关参数,是否完整,类似:version 之类是不是可以解析到 - - // 2.1 停止并卸载旧的插件 - pluginInstanceService.stopAndUnloadPlugin(pluginInfoDo.getPluginKey()); - // 2.2 上传新的插件文件,更新插件启用状态文件 - String pluginKeyNew = pluginInstanceService.uploadAndLoadNewPlugin(file); - - // 3. 更新插件信息 - updatePluginInfo(pluginInfoDo, pluginKeyNew, file); - } - - // TODO @haohao:这个方法,要不合并到 uploadFile 里; - /** - * 更新插件信息 - * - * @param pluginInfoDo 插件信息 - * @param pluginKeyNew 插件标识符 - * @param file 文件 - */ - private void updatePluginInfo(IotPluginInfoDO pluginInfoDo, String pluginKeyNew, MultipartFile file) { - IotPluginInfoDO updatedPluginInfo = new IotPluginInfoDO() - .setId(pluginInfoDo.getId()) - .setPluginKey(pluginKeyNew) - .setStatus(IotPluginStatusEnum.STOPPED.getStatus()) // TODO @haohao:这个状态,是不是非 stop 哈? - .setFileName(file.getOriginalFilename()) - .setScript("") // TODO @haohao:这个设置为 "" 会不会覆盖数据里的哈?应该从插件里读取?未来? - .setConfigSchema(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()) - .setVersion(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getVersion()) - .setDescription(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription()); - pluginInfoMapper.updateById(updatedPluginInfo); - } - - @Override - public void updatePluginStatus(Long id, Integer status) { - // 1. 校验插件信息是否存在 - IotPluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - - // 2. 更新插件状态 - pluginInstanceService.updatePluginStatus(pluginInfoDo, status); - - // 3. 更新数据库中的插件状态 - pluginInfoMapper.updateById(new IotPluginInfoDO().setId(id).setStatus(status)); - } - - @Override - public List getPluginInfoList() { - return pluginInfoMapper.selectList(); - } - - @Override - public List getPluginInfoListByStatus(Integer status) { - return pluginInfoMapper.selectListByStatus(status); - } - - @Override - public IotPluginInfoDO getPluginInfoByPluginKey(String pluginKey) { - return pluginInfoMapper.selectByPluginKey(pluginKey); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceService.java index 1e4807080..56e1bf0f0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceService.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.plugin; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; import org.springframework.web.multipart.MultipartFile; @@ -38,9 +38,9 @@ public interface IotPluginInstanceService { /** * 删除插件文件 * - * @param pluginInfoDo 插件信息 + * @param pluginConfigDO 插件配置 */ - void deletePluginFile(IotPluginInfoDO pluginInfoDo); + void deletePluginFile(IotPluginConfigDO pluginConfigDO); /** * 上传并加载新的插件文件 @@ -53,10 +53,10 @@ public interface IotPluginInstanceService { /** * 更新插件状态 * - * @param pluginInfoDo 插件信息 + * @param pluginConfigDO 插件配置 * @param status 新状态 */ - void updatePluginStatus(IotPluginInfoDO pluginInfoDo, Integer status); + void updatePluginStatus(IotPluginConfigDO pluginConfigDO, Integer status); // ========== 设备与插件的映射操作 ========== diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java index 6742eccd7..a3edbc175 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java @@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; import cn.iocoder.yudao.module.iot.dal.mysql.plugin.IotPluginInstanceMapper; import cn.iocoder.yudao.module.iot.dal.redis.plugin.DevicePluginProcessIdRedisDAO; @@ -45,7 +45,7 @@ public class IotPluginInstanceServiceImpl implements IotPluginInstanceService { @Resource @Lazy // 延迟加载,避免循环依赖 - private IotPluginInfoService pluginInfoService; + private IotPluginConfigService pluginConfigService; @Resource private IotPluginInstanceMapper pluginInstanceMapper; @@ -79,7 +79,7 @@ public class IotPluginInstanceServiceImpl implements IotPluginInstanceService { } // 情况二:不存在,则创建 - IotPluginInfoDO info = pluginInfoService.getPluginInfoByPluginKey(heartbeatReqDTO.getPluginKey()); + IotPluginConfigDO info = pluginConfigService.getPluginConfigByPluginKey(heartbeatReqDTO.getPluginKey()); if (info == null) { log.error("[heartbeatPluginInstance][心跳({}) 对应的插件不存在]", heartbeatReqDTO); return; @@ -129,18 +129,18 @@ public class IotPluginInstanceServiceImpl implements IotPluginInstanceService { } @Override - public void deletePluginFile(IotPluginInfoDO pluginInfoDO) { - File file = new File(pluginsDir, pluginInfoDO.getFileName()); + public void deletePluginFile(IotPluginConfigDO pluginConfigDO) { + File file = new File(pluginsDir, pluginConfigDO.getFileName()); if (!file.exists()) { return; } try { TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 if (!file.delete()) { - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName()); + log.error("[deletePluginFile][删除插件文件({}) 失败]", pluginConfigDO.getFileName()); } } catch (InterruptedException e) { - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), e); + log.error("[deletePluginFile][删除插件文件({}) 失败]", pluginConfigDO.getFileName(), e); } } @@ -171,13 +171,13 @@ public class IotPluginInstanceServiceImpl implements IotPluginInstanceService { } @Override - public void updatePluginStatus(IotPluginInfoDO pluginInfoDo, Integer status) { - String pluginKey = pluginInfoDo.getPluginKey(); + public void updatePluginStatus(IotPluginConfigDO pluginConfigDO, Integer status) { + String pluginKey = pluginConfigDO.getPluginKey(); PluginWrapper plugin = pluginManager.getPlugin(pluginKey); if (plugin == null) { // 插件不存在且状态为停止,抛出异常 - if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { + if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginConfigDO.getStatus())) { throw exception(ErrorCodeConstants.PLUGIN_STATUS_INVALID); } return; diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index efd53c84a..492e31db5 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -109,11 +109,11 @@ - - - - - + + cn.iocoder.boot + yudao-module-iot-biz + ${revision} + From 00edd5a7246b5c5dd91f6d7f88723c6a0a22495a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 5 Feb 2025 23:15:43 +0800 Subject: [PATCH 152/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20ota=20?= =?UTF-8?q?=E7=9A=84=E8=A1=A8=E7=BB=93=E6=9E=84=E8=AE=BE=E8=AE=A1=EF=BC=88?= =?UTF-8?q?90%=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/dataobject/ota/IotOtaFirmwareDO.java | 81 ++++++++++++++++++ .../dataobject/ota/IotOtaUpgradeRecordDO.java | 83 +++++++++++++++++++ .../dataobject/ota/IotOtaUpgradeTaskDO.java | 63 ++++++++++++++ .../dal/dataobject/rule/IotAlertRecordDO.java | 1 + .../IotDeviceDownstreamServiceImpl.java | 1 + 5 files changed, 229 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java new file mode 100644 index 000000000..12e5147ed --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.ota; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * IoT OTA 固件 DO + * + * @see https://help.aliyun.com/zh/iot/user-guide/ota-upgrade-overview + * + * @author 芋道源码 + */ +@TableName(value = "iot_ota_firmware", autoResultMap = true) +@KeySequence("iot_ota_firmware_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotOtaFirmwareDO extends BaseDO { + + /** + * 固件编号 + */ + @TableField + private Long id; + /** + * 固件名称 + */ + private String name; + /** + * 固件版本 + */ + private String description; + /** + * 版本号 + */ + private String version; + + /** + * 产品编号 + * + * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} + */ + private String productId; + /** + * 产品标识 + * + * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()} + */ + private String productKey; + + /** + * 签名方式 + * + * 例如说:MD5、SHA256 + */ + private String signMethod; + /** + * 固件文件签名 + */ + private String fileSign; + /** + * 固件文件大小 + */ + private Long fileSize; + /** + * 固件文件 URL + */ + private String fileUrl; + + /** + * 自定义信息,建议使用 JSON 格式 + */ + private String information; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java new file mode 100644 index 000000000..b4868f387 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.ota; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * IoT OTA 升级记录 DO + * + * @author 芋道源码 + */ +@TableName(value = "iot_ota_upgrade_record", autoResultMap = true) +@KeySequence("iot_ota_upgrade_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotOtaUpgradeRecordDO extends BaseDO { + + @TableId + private Long id; + + /** + * 固件编号 + * + * 关联 {@link IotOtaFirmwareDO#getId()} + */ + private Long firmwareId; + /** + * 任务编号 + * + * 关联 {@link IotOtaUpgradeTaskDO#getId()} + */ + private Long taskId; + + /** + * 升级状态 + * + * TODO + */ + private Integer status; + /** + * 升级进度,百分比 + */ + private Integer progress; + + /** + * 产品标识 + * + * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} + */ + private String productKey; + /** + * 设备名称 + * + * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} + */ + private String deviceName; + /** + * 设备编号 + * + * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} + */ + private String deviceId; + + /** + * 升级开始时间 + */ + private LocalDateTime startTime; + /** + * 升级结束时间 + */ + private LocalDateTime endTime; + + + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java new file mode 100644 index 000000000..529accfdd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.ota; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.util.List; + +/** + * IoT OTA 升级任务 DO + * + * @author 芋道源码 + */ +@TableName(value = "iot_ota_upgrade_task", autoResultMap = true) +@KeySequence("iot_ota_upgrade_task_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotOtaUpgradeTaskDO extends BaseDO { + + /** + * 任务编号 + */ + @TableField + private Long id; + /** + * 任务名称 + */ + private String name; + /** + * 任务描述 + */ + private String description; + + /** + * 固件编号 + * + * 关联 {@link IotOtaFirmwareDO#getId()} + */ + private Long firmwareId; + + /** + * 任务类型 + * + * TODO @芋艿:1-全部、2-指定设备 + */ + private Integer type; + /** + * 选中的设备名字数组 + * + * 关联 {@link IotDeviceDO#getDeviceName()} + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List deviceNames; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java index 2fc01ba7d..fbcf1fe79 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java @@ -63,6 +63,7 @@ public class IotAlertRecordDO extends BaseDO { @TableField(typeHandler = JacksonTypeHandler.class) private IotDeviceMessage deviceMessage; + // TODO @芋艿:换成枚举,枚举对应 ApiErrorLogProcessStatusEnum /** * 处理状态 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java index 006636c23..bac2ef6c9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java @@ -57,6 +57,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic public IotDeviceMessage downstreamDevice(IotDeviceDownstreamReqVO downstreamReqVO) { // 校验设备是否存在 IotDeviceDO device = deviceService.validateDeviceExists(downstreamReqVO.getId()); + // TODO @芋艿:离线设备,不允许推送 // TODO 芋艿:父设备的处理 IotDeviceDO parentDevice = null; From 8ced4a0a2cee3dbee171ecdcfb7766ede875f2d5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 6 Feb 2025 22:00:34 +0800 Subject: [PATCH 153/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20ota=20?= =?UTF-8?q?=E7=9A=84=E8=A1=A8=E7=BB=93=E6=9E=84=E8=AE=BE=E8=AE=A1=EF=BC=88?= =?UTF-8?q?100%=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ota/IotOtaUpgradeRecordStatusEnum.java | 38 +++++++++++++++++++ .../enums/ota/IotOtaUpgradeTaskScopeEnum.java | 33 ++++++++++++++++ .../ota/IotOtaUpgradeTaskStatusEnum.java | 35 +++++++++++++++++ .../dataobject/ota/IotOtaUpgradeRecordDO.java | 30 ++++++++------- .../dataobject/ota/IotOtaUpgradeTaskDO.java | 13 +++++-- 5 files changed, 133 insertions(+), 16 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java new file mode 100644 index 000000000..e809a7e5b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.enums.ota; + + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IoT OTA 升级记录的范围枚举 + * + * @author haohao + */ +@RequiredArgsConstructor +@Getter +public enum IotOtaUpgradeRecordStatusEnum implements ArrayValuable { + + PENDING(0), // 待推送 + PUSHED(10), // 已推送 + UPGRADING(20), // 升级中 + SUCCESS(30), // 升级成功 + FAILURE(40), // 升级失败 + CANCELED(50),; // 已取消 + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeRecordStatusEnum::getStatus).toArray(Integer[]::new); + + /** + * 范围 + */ + private final Integer status; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java new file mode 100644 index 000000000..6dccbb041 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.enums.ota; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IoT OTA 升级任务的范围枚举 + * + * @author haohao + */ +@RequiredArgsConstructor +@Getter +public enum IotOtaUpgradeTaskScopeEnum implements ArrayValuable { + + ALL(1), // 全部设备:只包括当前产品下的设备,不包括未来创建的设备 + SELECT(2); // 指定设备 + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskScopeEnum::getScope).toArray(Integer[]::new); + + /** + * 范围 + */ + private final Integer scope; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java new file mode 100644 index 000000000..78af16cb2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.enums.ota; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IoT OTA 升级任务的范围枚举 + * + * @author haohao + */ +@RequiredArgsConstructor +@Getter +public enum IotOtaUpgradeTaskStatusEnum implements ArrayValuable { + + IN_PROGRESS(10), // 进行中:升级中 + COMPLETED(20), // 已完成:已结束,全部升级完成 + INCOMPLETE(21), // 未完成:已结束,部分升级完成 + CANCELED(30),; // 已取消:一般是主动取消任务 + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskStatusEnum::getStatus).toArray(Integer[]::new); + + /** + * 范围 + */ + private final Integer status; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java index b4868f387..14924a786 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java @@ -39,17 +39,6 @@ public class IotOtaUpgradeRecordDO extends BaseDO { */ private Long taskId; - /** - * 升级状态 - * - * TODO - */ - private Integer status; - /** - * 升级进度,百分比 - */ - private Integer progress; - /** * 产品标识 * @@ -69,6 +58,23 @@ public class IotOtaUpgradeRecordDO extends BaseDO { */ private String deviceId; + /** + * 升级状态 + * + * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum} + */ + private Integer status; + /** + * 升级进度,百分比 + */ + private Integer progress; + /** + * 升级进度描述 + * + * 注意,只记录设备最后一次的升级进度描述 + * 如果想看历史记录,可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志 + */ + private String description; /** * 升级开始时间 */ @@ -78,6 +84,4 @@ public class IotOtaUpgradeRecordDO extends BaseDO { */ private LocalDateTime endTime; - - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java index 529accfdd..7d9e4425d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java @@ -47,11 +47,18 @@ public class IotOtaUpgradeTaskDO extends BaseDO { private Long firmwareId; /** - * 任务类型 + * 任务状态 * - * TODO @芋艿:1-全部、2-指定设备 + * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum} */ - private Integer type; + private Integer status; + + /** + * 升级范围 + * + * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum} + */ + private Integer scope; /** * 选中的设备名字数组 * From 8fac009d4bca81f785218cc323fd0ad8292fa828 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 7 Feb 2025 09:44:41 +0800 Subject: [PATCH 154/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E5=9F=BA=E4=BA=8E=20review=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=20ota=20=E7=9A=84=E8=A1=A8=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/dal/dataobject/device/IotDeviceDO.java | 8 +++++--- .../iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java | 7 +++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index 351e00185..d99145476 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.type.LongSetTypeHandler; import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; import com.baomidou.mybatisplus.annotation.KeySequence; @@ -116,9 +116,11 @@ public class IotDeviceDO extends TenantBaseDO { */ private String ip; /** - * 设备的固件版本 + * 固件编号 + * + * 关联 {@link IotOtaFirmwareDO#getId()} */ - private String firmwareVersion; + private String firmwareId; /** * 设备密钥,用于设备认证,需安全存储 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java index 14924a786..52f6d8375 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.ota; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -57,6 +58,12 @@ public class IotOtaUpgradeRecordDO extends BaseDO { * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} */ private String deviceId; + /** + * 来源的固件编号 + * + * 关联 {@link IotDeviceDO#getFirmwareId()} + */ + private Long fromFirmwareId; /** * 升级状态 From 795e06bc8fc1ae36d93e8e2e9dd41be7f4c019e7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 7 Feb 2025 21:06:03 +0800 Subject: [PATCH 155/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E3=80=91IoT=EF=BC=9A=E6=8F=92=E4=BB=B6=E8=BF=98?= =?UTF-8?q?=E6=98=AF=E8=80=83=E8=99=91=E6=94=AF=E6=8C=81=E5=A4=9A=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=EF=BC=8C=E5=9B=A0=E6=AD=A4=E9=9C=80=E8=A6=81=E5=BF=BD?= =?UTF-8?q?=E7=95=A5=E9=83=A8=E5=88=86=E5=9C=BA=E6=99=AF=E4=B8=8B=E7=9A=84?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=EF=BC=8C=E9=81=BF=E5=85=8D=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/dataobject/plugin/IotPluginConfigDO.java | 5 ++--- .../dal/dataobject/plugin/IotPluginInstanceDO.java | 4 ++-- .../iot/job/plugin/IotPluginInstancesJob.java | 2 ++ .../plugin/IotPluginInstanceServiceImpl.java | 13 +++++++++---- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java index d0695f896..69b738391 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java @@ -1,9 +1,8 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.plugin; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum; -import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; @@ -23,7 +22,7 @@ import lombok.*; @Builder @NoArgsConstructor @AllArgsConstructor -public class IotPluginConfigDO extends BaseDO { +public class IotPluginConfigDO extends TenantBaseDO { /** * 主键 ID diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java index 71d741b05..c64fe86c6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.plugin; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -21,7 +21,7 @@ import java.time.LocalDateTime; @Builder @NoArgsConstructor @AllArgsConstructor -public class IotPluginInstanceDO extends BaseDO { +public class IotPluginInstanceDO extends TenantBaseDO { /** * 主键 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/IotPluginInstancesJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/IotPluginInstancesJob.java index 261af3e58..1d2441737 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/IotPluginInstancesJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/IotPluginInstancesJob.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.job.plugin; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService; import org.springframework.stereotype.Component; @@ -28,6 +29,7 @@ public class IotPluginInstancesJob implements JobHandler { private IotPluginInstanceService pluginInstanceService; @Override + @TenantJob public String execute(String param) { int count = pluginInstanceService.offlineTimeoutPluginInstance( LocalDateTime.now().minus(OFFLINE_TIMEOUT)); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java index a3edbc175..8c9973a70 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.service.plugin; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; @@ -62,7 +63,8 @@ public class IotPluginInstanceServiceImpl implements IotPluginInstanceService { @Override public void heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) { // 情况一:已存在,则进行更新 - IotPluginInstanceDO instance = pluginInstanceMapper.selectByProcessId(heartbeatReqDTO.getProcessId()); + IotPluginInstanceDO instance = TenantUtils.executeIgnore( + () -> pluginInstanceMapper.selectByProcessId(heartbeatReqDTO.getProcessId())); if (instance != null) { IotPluginInstanceDO.IotPluginInstanceDOBuilder updateObj = IotPluginInstanceDO.builder().id(instance.getId()) .hostIp(heartbeatReqDTO.getHostIp()).downstreamPort(heartbeatReqDTO.getDownstreamPort()) @@ -74,12 +76,14 @@ public class IotPluginInstanceServiceImpl implements IotPluginInstanceService { } else { updateObj.offlineTime(LocalDateTime.now()); } - pluginInstanceMapper.updateById(updateObj.build()); + TenantUtils.execute(instance.getTenantId(), + () -> pluginInstanceMapper.updateById(updateObj.build())); return; } // 情况二:不存在,则创建 - IotPluginConfigDO info = pluginConfigService.getPluginConfigByPluginKey(heartbeatReqDTO.getPluginKey()); + IotPluginConfigDO info = TenantUtils.executeIgnore( + () -> pluginConfigService.getPluginConfigByPluginKey(heartbeatReqDTO.getPluginKey())); if (info == null) { log.error("[heartbeatPluginInstance][心跳({}) 对应的插件不存在]", heartbeatReqDTO); return; @@ -93,7 +97,8 @@ public class IotPluginInstanceServiceImpl implements IotPluginInstanceService { } else { insertObj.offlineTime(LocalDateTime.now()); } - pluginInstanceMapper.insert(insertObj.build()); + TenantUtils.execute(info.getTenantId(), + () -> pluginInstanceMapper.insert(insertObj.build())); } @Override From 4919439b960f09f03b836d3d4d7b2a07b892b695 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 7 Feb 2025 21:18:57 +0800 Subject: [PATCH 156/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9AOTA=20=E5=8D=87=E7=BA=A7=E7=9A=84?= =?UTF-8?q?=E4=B8=8B=E8=A1=8C=E6=B6=88=E6=81=AF=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../downstream/IotDeviceOtaUpgradeReqDTO.java | 66 ++++++++++++++++ .../upstream/IotDeviceOtaProgressReqDTO.java | 35 +++++++++ .../upstream/IotDeviceOtaPullReqDTO.java | 21 +++++ .../upstream/IotDeviceOtaReportReqDTO.java | 21 +++++ .../IotDeviceMessageIdentifierEnum.java | 7 +- .../device/IotDeviceMessageTypeEnum.java | 3 +- .../admin/device/IotDeviceController.http | 21 +++++ .../IotDeviceDownstreamServiceImpl.java | 78 +++++++++++++++---- .../IotDeviceDownstreamHandler.java | 13 +++- .../downstream/IotDeviceDownstreamServer.java | 7 +- .../IotDeviceOtaUpgradeVertxHandler.java | 60 ++++++++++++++ .../IotDeviceDownstreamHandlerImpl.java | 10 ++- 12 files changed, 311 insertions(+), 31 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceOtaUpgradeReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaProgressReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaPullReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaReportReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceOtaUpgradeReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceOtaUpgradeReqDTO.java new file mode 100644 index 000000000..8eccec42e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceOtaUpgradeReqDTO.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream; + +import cn.hutool.core.map.MapUtil; +import lombok.Data; + +import java.util.Map; + +/** + * IoT 设备【OTA】升级下发 Request DTO(更新固件消息) + * + * @author 芋道源码 + */ +@Data +public class IotDeviceOtaUpgradeReqDTO extends IotDeviceDownstreamAbstractReqDTO { + + /** + * 固件编号 + */ + private Long firmwareId; + /** + * 固件版本 + */ + private String version; + + /** + * 签名方式 + * + * 例如说:MD5、SHA256 + */ + private String signMethod; + /** + * 固件文件签名 + */ + private String fileSign; + /** + * 固件文件大小 + */ + private Long fileSize; + /** + * 固件文件 URL + */ + private String fileUrl; + + /** + * 自定义信息,建议使用 JSON 格式 + */ + private String information; + + public static IotDeviceOtaUpgradeReqDTO build(Map map) { + return new IotDeviceOtaUpgradeReqDTO() + .setFirmwareId(MapUtil.getLong(map, "firmwareId")).setVersion((String) map.get("version")) + .setSignMethod((String) map.get("signMethod")).setFileSign((String) map.get("fileSign")) + .setFileSize(MapUtil.getLong(map, "fileSize")).setFileUrl((String) map.get("fileUrl")) + .setInformation((String) map.get("information")); + } + + public static Map build(IotDeviceOtaUpgradeReqDTO dto) { + return MapUtil.builder() + .put("firmwareId", dto.getFirmwareId()).put("version", dto.getVersion()) + .put("signMethod", dto.getSignMethod()).put("fileSign", dto.getFileSign()) + .put("fileSize", dto.getFileSize()).put("fileUrl", dto.getFileUrl()) + .put("information", dto.getInformation()) + .build(); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaProgressReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaProgressReqDTO.java new file mode 100644 index 000000000..a88a72e91 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaProgressReqDTO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; + +import lombok.Data; + +// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/progress +/** + * IoT 设备【OTA】升级进度 Request DTO(上报更新固件进度) + * + * @author 芋道源码 + */ +@Data +public class IotDeviceOtaProgressReqDTO extends IotDeviceUpstreamAbstractReqDTO { + + /** + * 固件编号 + */ + private Long firmwareId; + + /** + * 升级状态 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum} + */ + private Integer status; + /** + * 升级进度,百分比 + */ + private Integer progress; + + /** + * 升级进度描述 + */ + private String description; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaPullReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaPullReqDTO.java new file mode 100644 index 000000000..6328704e5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaPullReqDTO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; + +// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/pull +/** + * IoT 设备【OTA】升级下拉 Request DTO(拉取固件更新) + * + * @author 芋道源码 + */ +public class IotDeviceOtaPullReqDTO { + + /** + * 固件编号 + */ + private Long firmwareId; + + /** + * 固件版本 + */ + private String version; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaReportReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaReportReqDTO.java new file mode 100644 index 000000000..2b3b91c98 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaReportReqDTO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; + +// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/report +/** + * IoT 设备【OTA】上报 Request DTO(上报固件版本) + * + * @author 芋道源码 + */ +public class IotDeviceOtaReportReqDTO { + + /** + * 固件编号 + */ + private Long firmwareId; + + /** + * 固件版本 + */ + private String version; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java index 8f6270c7b..f8eca51ed 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java @@ -21,7 +21,12 @@ public enum IotDeviceMessageIdentifierEnum { CONFIG_SET("set"), // 下行 SERVICE_INVOKE("${identifier}"), // 下行 - SERVICE_REPLY_SUFFIX("_reply"); // 芋艿:TODO 芋艿:【讨论】上行 or 下行 + SERVICE_REPLY_SUFFIX("_reply"), // 芋艿:TODO 芋艿:【讨论】上行 or 下行 + + OTA_UPGRADE("upgrade"), // 下行 + OTA_PULL("pull"), // 上行 + OTA_PROGRESS("progress"), // 上行 + OTA_REPORT("report"),; // 上行 /** * 标志符 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java index 45b7596ce..2ee0a8acc 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java @@ -17,7 +17,8 @@ public enum IotDeviceMessageTypeEnum implements ArrayValuable { PROPERTY("property"), // 设备属性 EVENT("event"), // 设备事件 SERVICE("service"), // 设备服务 - CONFIG("config"); // 设备配置 + CONFIG("config"), // 设备配置 + OTA("ota"),; // 设备 OTA public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http index 042ad7e7f..c1190cec1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http @@ -51,4 +51,25 @@ Authorization: Bearer {{token}} "id": 25, "type": "config", "identifier": "set" +} + +### 请求 /iot/device/downstream 接口(OTA 升级) => 成功 +POST {{baseUrl}}/iot/device/downstream +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "id": 25, + "type": "ota", + "identifier": "upgrade", + "data": { + "firmwareId": 1, + "version": "1.0.0", + "signMethod": "MD5", + "fileSign": "d41d8cd98f00b204e9800998ecf8427e", + "fileSize": 1024, + "fileUrl": "http://example.com/firmware.bin", + "information": "{\"desc\":\"升级到最新版本\"}" + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java index bac2ef6c9..7c1ec5bb8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java @@ -80,11 +80,15 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic } // 配置下发 if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.CONFIG.getType()) - && Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) { + && Objects.equals(downstreamReqVO.getIdentifier(), + IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) { return setDeviceConfig(downstreamReqVO, device, parentDevice); } - // TODO 芋艿:ota 升级 - return null; + // OTA 升级 + if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.OTA.getType())) { + return otaUpgrade(downstreamReqVO, device, parentDevice); + } + throw new IllegalArgumentException("不支持的下行消息类型:" + downstreamReqVO); } /** @@ -97,7 +101,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic */ @SuppressWarnings("unchecked") private IotDeviceMessage invokeDeviceService(IotDeviceDownstreamReqVO downstreamReqVO, - IotDeviceDO device, IotDeviceDO parentDevice) { + IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数校验 if (!(downstreamReqVO.getData() instanceof Map)) { throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型"); @@ -105,9 +109,10 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic // TODO @super:【可优化】过滤掉不合法的服务 // 2. 发送请求 - String url = String.format( "sys/%s/%s/thing/service/%s", - getProductKey(device, parentDevice), getDeviceName(device, parentDevice), downstreamReqVO.getIdentifier()); - IotDeviceServiceInvokeReqDTO reqDTO = new IotDeviceServiceInvokeReqDTO() + String url = String.format("sys/%s/%s/thing/service/%s", + getProductKey(device, parentDevice), getDeviceName(device, parentDevice), + downstreamReqVO.getIdentifier()); + IotDeviceServiceInvokeReqDTO reqDTO = new IotDeviceServiceInvokeReqDTO() .setParams((Map) downstreamReqVO.getData()); CommonResult result = requestPlugin(url, reqDTO, device); @@ -144,7 +149,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic // TODO @super:【可优化】过滤掉不合法的属性 // 2. 发送请求 - String url = String.format( "sys/%s/%s/thing/service/property/set", + String url = String.format("sys/%s/%s/thing/service/property/set", getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); IotDevicePropertySetReqDTO reqDTO = new IotDevicePropertySetReqDTO() .setProperties((Map) downstreamReqVO.getData()); @@ -184,7 +189,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic // TODO @super:【可优化】过滤掉不合法的属性 // 2. 发送请求 - String url = String.format( "sys/%s/%s/thing/service/property/get", + String url = String.format("sys/%s/%s/thing/service/property/get", getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); IotDevicePropertyGetReqDTO reqDTO = new IotDevicePropertyGetReqDTO() .setIdentifiers((List) downstreamReqVO.getData()); @@ -214,14 +219,14 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic * @param parentDevice 父设备 * @return 下发消息 */ - @SuppressWarnings({"unchecked", "unused"}) + @SuppressWarnings({ "unchecked", "unused" }) private IotDeviceMessage setDeviceConfig(IotDeviceDownstreamReqVO downstreamReqVO, IotDeviceDO device, IotDeviceDO parentDevice) { // 1. 参数转换,无需校验 Map config = JsonUtils.parseObject(device.getConfig(), Map.class); // 2. 发送请求 - String url = String.format( "sys/%s/%s/thing/service/config/set", + String url = String.format("sys/%s/%s/thing/service/config/set", getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); IotDeviceConfigSetReqDTO reqDTO = new IotDeviceConfigSetReqDTO() .setConfig(config); @@ -243,16 +248,54 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic return message; } + /** + * 设备 OTA 升级 + * + * @param downstreamReqVO 下行请求 + * @param device 设备 + * @param parentDevice 父设备 + * @return 下发消息 + */ + private IotDeviceMessage otaUpgrade(IotDeviceDownstreamReqVO downstreamReqVO, + IotDeviceDO device, IotDeviceDO parentDevice) { + // 1. 参数校验 + if (!(downstreamReqVO.getData() instanceof Map data)) { + throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型"); + } + + // 2. 发送请求 + String url = String.format("ota/%s/%s/upgrade", + getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); + IotDeviceOtaUpgradeReqDTO reqDTO = IotDeviceOtaUpgradeReqDTO.build(data); + CommonResult result = requestPlugin(url, reqDTO, device); + + // 3. 发送设备消息 + IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) + .setType(IotDeviceMessageTypeEnum.OTA.getType()) + .setIdentifier(IotDeviceMessageIdentifierEnum.OTA_UPGRADE.getIdentifier()) + .setData(downstreamReqVO.getData()); + sendDeviceMessage(message, device, result.getCode()); + + // 4. 如果不成功,抛出异常,提示用户 + if (result.isError()) { + log.error("[otaUpgrade][设备({}) OTA 升级失败,请求参数:({}),响应结果:({})]", + device.getDeviceKey(), reqDTO, result); + throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); + } + return message; + } + /** * 请求插件 * - * @param url URL - * @param reqDTO 请求参数,只需要设置子类的参数! - * @param device 设备 + * @param url URL + * @param reqDTO 请求参数,只需要设置子类的参数! + * @param device 设备 * @return 响应结果 */ - @SuppressWarnings({"unchecked", "HttpUrlsUsage"}) - private CommonResult requestPlugin(String url, IotDeviceDownstreamAbstractReqDTO reqDTO, IotDeviceDO device) { + @SuppressWarnings({ "unchecked", "HttpUrlsUsage" }) + private CommonResult requestPlugin(String url, IotDeviceDownstreamAbstractReqDTO reqDTO, + IotDeviceDO device) { // 获得设备对应的插件实例 IotPluginInstanceDO pluginInstance = pluginInstanceService.getPluginInstanceByDeviceKey(device.getDeviceKey()); if (pluginInstance == null) { @@ -266,7 +309,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic ResponseEntity> responseEntity; try { responseEntity = restTemplate.postForEntity( - String.format("http://%s:%d/%s", pluginInstance.getHostIp(), pluginInstance.getDownstreamPort(), url), + String.format("http://%s:%d/%s", pluginInstance.getHostIp(), pluginInstance.getDownstreamPort(), + url), reqDTO, (Class>) (Class) CommonResult.class); Assert.isTrue(responseEntity.getStatusCode().is2xxSuccessful(), "HTTP 状态码不是 2xx,而是" + responseEntity.getStatusCode()); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java index 62d72785d..38aba3df6 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; /** * IoT 设备下行处理器 @@ -47,4 +44,12 @@ public interface IotDeviceDownstreamHandler { */ CommonResult setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO); + /** + * 升级设备 OTA + * + * @param upgradeReqDTO 升级设备 OTA 的请求 + * @return 是否成功 + */ + CommonResult upgradeDeviceOta(IotDeviceOtaUpgradeReqDTO upgradeReqDTO); + } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java index 6b08dba00..719fdb5c3 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream; import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; -import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceConfigSetVertxHandler; -import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertyGetVertxHandler; -import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertySetVertxHandler; -import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceServiceInvokeVertxHandler; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.*; import io.vertx.core.Vertx; import io.vertx.core.http.HttpServer; import io.vertx.ext.web.Router; @@ -39,6 +36,8 @@ public class IotDeviceDownstreamServer { .handler(new IotDevicePropertyGetVertxHandler(deviceDownstreamHandler)); router.post(IotDeviceConfigSetVertxHandler.PATH) .handler(new IotDeviceConfigSetVertxHandler(deviceDownstreamHandler)); + router.post(IotDeviceOtaUpgradeVertxHandler.PATH) + .handler(new IotDeviceOtaUpgradeVertxHandler(deviceDownstreamHandler)); // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java new file mode 100644 index 000000000..f81d385dc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceOtaUpgradeReqDTO; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import io.vertx.core.json.JsonObject; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; + +@Slf4j +@RequiredArgsConstructor +public class IotDeviceOtaUpgradeVertxHandler implements Handler { + + public static final String PATH = "/ota/:productKey/:deviceName/upgrade"; + + private final IotDeviceDownstreamHandler deviceDownstreamHandler; + + @Override + public void handle(RoutingContext routingContext) { + // 1. 解析参数 + IotDeviceOtaUpgradeReqDTO reqDTO; + try { + String productKey = routingContext.pathParam("productKey"); + String deviceName = routingContext.pathParam("deviceName"); + JsonObject body = routingContext.body().asJsonObject(); + String requestId = body.getString("requestId"); + Long firmwareId = body.getLong("firmwareId"); + String version = body.getString("version"); + String signMethod = body.getString("signMethod"); + String fileSign = body.getString("fileSign"); + Long fileSize = body.getLong("fileSize"); + String fileUrl = body.getString("fileUrl"); + String information = body.getString("information"); + reqDTO = ((IotDeviceOtaUpgradeReqDTO) new IotDeviceOtaUpgradeReqDTO() + .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName)) + .setFirmwareId(firmwareId).setVersion(version) + .setSignMethod(signMethod).setFileSign(fileSign).setFileSize(fileSize).setFileUrl(fileUrl) + .setInformation(information); + } catch (Exception e) { + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + return; + } + + // 2. 调用处理器 + try { + CommonResult result = deviceDownstreamHandler.upgradeDeviceOta(reqDTO); + IotPluginCommonUtils.writeJson(routingContext, result); + } catch (Exception e) { + log.error("[handle][请求参数({}) OTA 升级异常]", reqDTO, e); + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + } + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java index 3c86ad6d2..869fe7234 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.downstream; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED; @@ -39,4 +36,9 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性"); } + @Override + public CommonResult upgradeDeviceOta(IotDeviceOtaUpgradeReqDTO upgradeReqDTO) { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性"); + } + } From 724512399a5f434f9fa5272b37800a361259b1b4 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 8 Feb 2025 07:29:17 +0800 Subject: [PATCH 157/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E5=8A=A8=E6=80=81=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=20js=E3=80=81groovy=20demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/yudao-module-iot-biz/pom.xml | 21 +++++++ .../iocoder/yudao/module/iot/ScriptTest.java | 61 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/ScriptTest.java diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 805205a16..6f01e3319 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -81,6 +81,27 @@ pf4j-spring + + + org.apache.groovy + groovy-all + 4.0.25 + pom + + + + + org.graalvm.js + js + 24.1.2 + pom + + + org.graalvm.js + js-scriptengine + 24.1.2 + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/ScriptTest.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/ScriptTest.java new file mode 100644 index 000000000..9f54d60e8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/ScriptTest.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.iot; + +import cn.hutool.script.ScriptUtil; +import javax.script.Bindings; +import javax.script.ScriptEngine; +import javax.script.ScriptException; + +/** + * TODO 芋艿:测试脚本的接入 + */ +public class ScriptTest { + + public static void main2(String[] args) { + // 创建一个 Groovy 脚本引擎 + ScriptEngine engine = ScriptUtil.createGroovyEngine(); + + // 创建绑定参数 + Bindings bindings = engine.createBindings(); + bindings.put("name", "Alice"); + bindings.put("age", 30); + + // 定义一个稍微复杂的 Groovy 脚本 + String script = "def greeting = 'Hello, ' + name + '!';\n" + + "def ageInFiveYears = age + 5;\n" + + "def message = greeting + ' In five years, you will be ' + ageInFiveYears + ' years old.';\n" + + "return message.toUpperCase();\n"; + + try { + // 执行脚本并获取结果 + Object result = engine.eval(script, bindings); + System.out.println(result); // 输出: HELLO, ALICE! IN FIVE YEARS, YOU WILL BE 35 YEARS OLD. + } catch (ScriptException e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + // 创建一个 JavaScript 脚本引擎 + ScriptEngine jsEngine = ScriptUtil.createJsEngine(); + + // 创建绑定参数 + Bindings jsBindings = jsEngine.createBindings(); + jsBindings.put("name", "Bob"); + jsBindings.put("age", 25); + + // 定义一个简单的 JavaScript 脚本 + String jsScript = "var greeting = 'Hello, ' + name + '!';\n" + + "var ageInTenYears = age + 10;\n" + + "var message = greeting + ' In ten years, you will be ' + ageInTenYears + ' years old.';\n" + + "message.toUpperCase();\n"; + + try { + // 执行脚本并获取结果 + Object jsResult = jsEngine.eval(jsScript, jsBindings); + System.out.println(jsResult); // 输出: HELLO, BOB! IN TEN YEARS, YOU WILL BE 35 YEARS OLD. + } catch (ScriptException e) { + e.printStackTrace(); + } + } + +} From d718f801084f9c92ce69b695e059a53a6adb04a5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 8 Feb 2025 07:39:48 +0800 Subject: [PATCH 158/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9Aplugin=20=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml | 1 + .../module/iot/framework/plugin/core/IotPluginStartRunner.java | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml index 2a14c88b8..95ab6f7a4 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -63,6 +63,7 @@ opengauss-jdbc true + com.taosdata.jdbc taos-jdbcdriver diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java index 8036eb2d4..64d258514 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/IotPluginStartRunner.java @@ -30,7 +30,6 @@ public class IotPluginStartRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) { List pluginConfigList = TenantUtils.executeIgnore( - // 查询运行中且部署类型为 JAR 的插件 () -> pluginConfigService.getPluginConfigListByStatusAndDeployType( IotPluginStatusEnum.RUNNING.getStatus(), IotPluginDeployTypeEnum.JAR.getDeployType())); if (CollUtil.isEmpty(pluginConfigList)) { From 6abd67a38c671219f138a52a50d4d4ceda632af3 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sat, 8 Feb 2025 17:31:11 +0800 Subject: [PATCH 159/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E7=89=A9=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thingmodel/IotDataSpecsDataTypeEnum.java | 13 +++++- .../IotThingModelAccessModeEnum.java | 13 +++++- .../IotThingModelParamDirectionEnum.java | 14 +++++- .../IotThingModelServiceCallTypeEnum.java | 13 +++++- .../IotThingModelServiceEventTypeEnum.java | 13 +++++- .../thingmodel/model/ThingModelEvent.java | 11 ++++- .../thingmodel/model/ThingModelParam.java | 14 +++++- .../thingmodel/model/ThingModelProperty.java | 16 +++++-- .../thingmodel/model/ThingModelService.java | 12 +++++- .../thingmodel/vo/IotThingModelListReqVO.java | 7 ++- .../thingmodel/vo/IotThingModelPageReqVO.java | 7 ++- .../thingmodel/vo/IotThingModelRespVO.java | 13 +++--- .../thingmodel/vo/IotThingModelSaveReqVO.java | 15 ++++--- .../thingmodel/IotThingModelServiceImpl.java | 43 +++++++++++-------- 14 files changed, 148 insertions(+), 56 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java index aa455f8cc..5524fdeb4 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; -// TODO @puhui999:加个 ArrayValuable +import java.util.Arrays; + /** * IoT 数据定义的数据类型枚举类 * @@ -11,7 +13,7 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotDataSpecsDataTypeEnum { +public enum IotDataSpecsDataTypeEnum implements ArrayValuable { INT("int"), FLOAT("float"), @@ -23,6 +25,13 @@ public enum IotDataSpecsDataTypeEnum { STRUCT("struct"), ARRAY("array"); + public static final String[] ARRAYS = Arrays.stream(values()).map(IotDataSpecsDataTypeEnum::getDataType).toArray(String[]::new); + private final String dataType; + @Override + public String[] array() { + return ARRAYS; + } + } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java index 6eb6ddb7e..a78614853 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; -// TODO @puhui999:加个 ArrayValuable +import java.util.Arrays; + /** * IOT 产品物模型属性读取类型枚举 * @@ -11,11 +13,18 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotThingModelAccessModeEnum { +public enum IotThingModelAccessModeEnum implements ArrayValuable { READ_ONLY("r"), READ_WRITE("rw"); + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelAccessModeEnum::getMode).toArray(String[]::new); + private final String mode; + @Override + public String[] array() { + return ARRAYS; + } + } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java index 1e875cd23..00158a0f9 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java @@ -1,9 +1,12 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; -// TODO @puhui999:加个 ArrayValuable +import java.util.Arrays; + + /** * IOT 产品物模型参数是输入参数还是输出参数枚举 * @@ -11,11 +14,18 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotThingModelParamDirectionEnum { +public enum IotThingModelParamDirectionEnum implements ArrayValuable { INPUT("input"), // 输入参数 OUTPUT("output"); // 输出参数 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelParamDirectionEnum::getDirection).toArray(String[]::new); + private final String direction; + @Override + public String[] array() { + return ARRAYS; + } + } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java index d547bf104..d6ed70e50 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; -// TODO @puhui999:加个 ArrayValuable +import java.util.Arrays; + /** * IOT 产品物模型服务调用方式枚举 * @@ -11,11 +13,18 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotThingModelServiceCallTypeEnum { +public enum IotThingModelServiceCallTypeEnum implements ArrayValuable { ASYNC("async"), // 异步调用 SYNC("sync"); // 同步调用 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelServiceCallTypeEnum::getType).toArray(String[]::new); + private final String type; + @Override + public String[] array() { + return ARRAYS; + } + } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java index 89271d7fc..584c0743f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.iot.enums.thingmodel; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; -// TODO @puhui999:加个 ArrayValuable +import java.util.Arrays; + /** * IOT 产品物模型事件类型枚举 * @@ -11,12 +13,19 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotThingModelServiceEventTypeEnum { +public enum IotThingModelServiceEventTypeEnum implements ArrayValuable { INFO("info"), // 信息 ALERT("alert"), // 告警 ERROR("error"); // 故障 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelServiceEventTypeEnum::getType).toArray(String[]::new); + private final String type; + @Override + public String[] array() { + return ARRAYS; + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index 0a5e0056f..151d1f571 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -1,11 +1,14 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; +import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceEventTypeEnum; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; import lombok.Data; import java.util.List; -// TODO @puhui999:必要的参数校验 /** * 物模型中的事件 * @@ -17,10 +20,13 @@ public class ThingModelEvent { /** * 事件标识符 */ + @NotEmpty(message = "事件标识符不能为空") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "事件标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符") private String identifier; /** * 事件名称 */ + @NotEmpty(message = "事件名称不能为空") private String name; /** * 是否是标准品类的必选事件 @@ -31,12 +37,15 @@ public class ThingModelEvent { * * 枚举 {@link IotThingModelServiceEventTypeEnum} */ + @NotEmpty(message = "事件类型不能为空") + @InEnum(IotThingModelServiceEventTypeEnum.class) private String type; /** * 事件的输出参数 * * 输出参数定义事件调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 */ + @Valid private List outputParams; /** * 标识设备需要执行的具体操作 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java index 6215d1537..dc1e7deac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java @@ -1,12 +1,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; +import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelParamDirectionEnum; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; import lombok.Data; import java.util.List; -// TODO @puhui999:必要的参数校验 /** * IOT 产品物模型中的参数 * @@ -18,16 +21,21 @@ public class ThingModelParam { /** * 参数标识符 */ + @NotEmpty(message = "参数标识符不能为空") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "参数标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符") private String identifier; /** * 参数名称 */ + @NotEmpty(message = "参数名称不能为空") private String name; /** * 用于区分输入或输出参数 * * 枚举 {@link IotThingModelParamDirectionEnum} */ + @NotEmpty(message = "参数方向不能为空") + @InEnum(IotThingModelParamDirectionEnum.class) private String direction; /** * 参数的序号。从 0 开始排序,且不能重复。 @@ -37,7 +45,11 @@ public class ThingModelParam { private Integer paraOrder; /** * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致 + * + * 枚举 {@link IotDataSpecsDataTypeEnum} */ + @NotEmpty(message = "数据类型不能为空") + @InEnum(IotDataSpecsDataTypeEnum.class) private String dataType; /** * 参数值的数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index 157a4c488..866f25b84 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -1,12 +1,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; +import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelAccessModeEnum; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; import lombok.Data; import java.util.List; -// TODO @puhui999:必要的参数校验 /** * 物模型中的属性 * @@ -20,26 +23,33 @@ public class ThingModelProperty { /** * 属性标识符 */ + @NotEmpty(message = "属性标识符不能为空") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "属性标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符") private String identifier; /** * 属性名称 */ + @NotEmpty(message = "属性名称不能为空") private String name; /** * 云端可以对该属性进行的操作类型 * * 枚举 {@link IotThingModelAccessModeEnum} */ + @NotEmpty(message = "操作类型不能为空") + @InEnum(IotThingModelAccessModeEnum.class) private String accessMode; /** * 是否是标准品类的必选服务 */ private Boolean required; /** - * 数据类型,与 dataSpecs 的 dataType 保持一致 + * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致 * - * 枚举 {@link cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum} + * 枚举 {@link IotDataSpecsDataTypeEnum} */ + @NotEmpty(message = "数据类型不能为空") + @InEnum(IotDataSpecsDataTypeEnum.class) private String dataType; /** * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index 067ca2ea1..7db2b5f7a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -1,11 +1,14 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; +import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceCallTypeEnum; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; import lombok.Data; import java.util.List; -// TODO @puhui999:必要的参数校验 /** * 物模型中的服务 * @@ -17,10 +20,13 @@ public class ThingModelService { /** * 服务标识符 */ + @NotEmpty(message = "服务标识符不能为空") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "服务标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符") private String identifier; /** * 服务名称 */ + @NotEmpty(message = "服务名称不能为空") private String name; /** * 是否是标准品类的必选服务 @@ -31,18 +37,22 @@ public class ThingModelService { * * 枚举 {@link IotThingModelServiceCallTypeEnum} */ + @NotEmpty(message = "调用类型不能为空") + @InEnum(IotThingModelServiceCallTypeEnum.class) private String callType; /** * 服务的输入参数 * * 输入参数定义服务调用时所需提供的信息,用于控制设备行为或执行特定任务 */ + @Valid private List inputParams; /** * 服务的输出参数 * * 输出参数定义服务调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 */ + @Valid private List outputParams; /** * 标识设备需要执行的具体操作 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java index 8f7f374dd..5b92256bb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java @@ -6,19 +6,18 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; -// TODO @puhui999:部分字段,可以用 cursor 加上 example @Schema(description = "管理后台 - IoT 产品物模型 List Request VO") @Data public class IotThingModelListReqVO { - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @NotNull(message = "产品编号不能为空") private Long productId; - @Schema(description = "功能标识") + @Schema(description = "功能标识", example = "temperature") private String identifier; - @Schema(description = "功能名称", example = "张三") + @Schema(description = "功能名称", example = "温度") private String name; @Schema(description = "功能类型", example = "1") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java index 404bc7cc2..447eb6e9a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java @@ -9,21 +9,20 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -// TODO @puhui999:部分字段,可以用 cursor 加上 example @Schema(description = "管理后台 - IoT 产品物模型分页 Request VO") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) public class IotThingModelPageReqVO extends PageParam { - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @NotNull(message = "产品编号不能为空") private Long productId; - @Schema(description = "功能标识") + @Schema(description = "功能标识", example = "temperature") private String identifier; - @Schema(description = "功能名称", example = "张三") + @Schema(description = "功能名称", example = "温度") private String name; @Schema(description = "功能类型", example = "1") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java index 37a42edc9..72565a8c4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java @@ -10,7 +10,6 @@ import lombok.Data; import java.time.LocalDateTime; -// TODO @puhui999:部分字段,可以用 cursor 加上 example @Schema(description = "管理后台 - IoT 产品物模型 Response VO") @Data @ExcelIgnoreUnannotated @@ -20,23 +19,23 @@ public class IotThingModelRespVO { @ExcelProperty("产品ID") private Long id; - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long productId; - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature_sensor") @ExcelProperty("产品标识") private String productKey; - @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature") private String identifier; - @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温度") private String name; - @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "测量当前环境温度") private String description; - @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer type; @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java index 18b8f4042..1e8564df4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java @@ -6,11 +6,11 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelP import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; -// TODO @puhui999:部分字段,可以用 cursor 加上 example @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") @Data public class IotThingModelSaveReqVO { @@ -22,33 +22,36 @@ public class IotThingModelSaveReqVO { @NotNull(message = "产品ID不能为空") private Long productId; - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature_001") @NotEmpty(message = "产品标识不能为空") private String productKey; - @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temp_monitor") @NotEmpty(message = "功能标识不能为空") private String identifier; - @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温度监测器") @NotEmpty(message = "功能名称不能为空") private String name; - @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "用于监测环境温度的传感器") private String description; - @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "功能类型不能为空") @InEnum(IotThingModelTypeEnum.class) private Integer type; @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) + @Valid private ThingModelProperty property; @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED) + @Valid private ThingModelService service; @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED) + @Valid private ThingModelEvent event; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index c57ab76ba..b9167e4ef 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -55,7 +55,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { @Transactional(rollbackFor = Exception.class) public Long createThingModel(IotThingModelSaveReqVO createReqVO) { // 1.1 校验功能标识符在同一产品下是否唯一 - validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); + validateIdentifierUnique(null, createReqVO.getProductId(), createReqVO.getIdentifier()); // 1.2 功能名称在同一产品下是否唯一 validateNameUnique(createReqVO.getProductId(), createReqVO.getName()); // 1.3 校验产品状态,发布状态下,不允许新增功能 @@ -81,7 +81,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { // 1.1 校验功能是否存在 validateProductThingModelMapperExists(updateReqVO.getId()); // 1.2 校验功能标识符是否唯一 - validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); + validateIdentifierUnique(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); // 1.3 校验产品状态,发布状态下,不允许操作功能 validateProductStatus(updateReqVO.getProductId()); @@ -159,8 +159,23 @@ public class IotThingModelServiceImpl implements IotThingModelService { } } - // TODO @puhui999:这个方法,和 validateIdentifierUnique 可以融合下 - private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { + private void validateIdentifierUnique(Long id, Long productId, String identifier) { + // 1.0 情况一:创建时校验 + if (id == null) { + // 1.1 系统保留字段,不能用于标识符定义 + if (StrUtil.equalsAny(identifier, "set", "get", "post", "property", "event", "time", "value")) { + throw exception(THING_MODEL_IDENTIFIER_INVALID); + } + + // 1.2 校验唯一 + IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier); + if (thingModel != null) { + throw exception(THING_MODEL_IDENTIFIER_EXISTS); + } + return; + } + + // 2.0 情况二:更新时校验 IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) { throw exception(THING_MODEL_IDENTIFIER_EXISTS); @@ -181,23 +196,10 @@ public class IotThingModelServiceImpl implements IotThingModelService { } } - private void validateIdentifierUnique(Long productId, String identifier) { - // 系统保留字段,不能用于标识符定义 - if (StrUtil.equalsAny(identifier, "set", "get", "post", "property", "event", "time", "value")) { - throw exception(THING_MODEL_IDENTIFIER_INVALID); - } - - // 校验唯一 - IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier); - if (thingModel != null) { - throw exception(THING_MODEL_IDENTIFIER_EXISTS); - } - } - /** * 创建默认的事件和服务 * - * @param productId 产品编号 + * @param productId 产品编号 * @param productKey 产品标识 */ public void createDefaultEventsAndServices(Long productId, String productKey) { @@ -282,6 +284,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { } // TODO @haohao:是不是不用生成这个?目前属性上报,是个批量接口 + /** * 生成属性上报事件 */ @@ -298,6 +301,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { } // TODO @haohao:是不是不用生成这个?目前属性上报,是个批量接口 + /** * 生成属性设置服务 */ @@ -352,7 +356,8 @@ public class IotThingModelServiceImpl implements IotThingModelService { } @CacheEvict(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey") - public void deleteThingModelListCache0(String productKey) {} + public void deleteThingModelListCache0(String productKey) { + } private IotThingModelServiceImpl getSelf() { return SpringUtil.getBean(getClass()); From 5f7bb8041f984980e9b56b66947e60a6dc2c6152 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 8 Feb 2025 19:31:50 +0800 Subject: [PATCH 160/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=20register=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/api/device/IotDeviceUpstreamApi.java | 14 +++-- .../upstream/IotDeviceRegisterReqDTO.java | 12 ++++ .../IotDeviceMessageIdentifierEnum.java | 6 +- .../device/IotDeviceMessageTypeEnum.java | 11 ++-- .../api/device/IoTDeviceUpstreamApiImpl.java | 11 ++-- .../device/vo/device/IotDeviceSaveReqVO.java | 2 + .../dal/dataobject/product/IotProductDO.java | 4 +- .../iot/service/device/IotDeviceService.java | 13 +++- .../service/device/IotDeviceServiceImpl.java | 59 ++++++++++++++----- .../control/IotDeviceUpstreamService.java | 8 +++ .../control/IotDeviceUpstreamServiceImpl.java | 28 +++++++-- .../service/product/IotProductService.java | 8 +++ .../product/IotProductServiceImpl.java | 5 ++ 13 files changed, 146 insertions(+), 35 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java index a6601d551..a69ea180c 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.iot.api.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*; import cn.iocoder.yudao.module.iot.enums.ApiConstants; import jakarta.validation.Valid; import org.springframework.web.bind.annotation.PostMapping; @@ -47,6 +44,15 @@ public interface IotDeviceUpstreamApi { @PostMapping(PREFIX + "/report-event") CommonResult reportDeviceEvent(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO); + // TODO @芋艿:这个需要 plugins 接入下 + /** + * 注册设备 + * + * @param registerReqDTO 注册设备 DTO + */ + @PostMapping(PREFIX + "/register") + CommonResult registerDevice(@Valid @RequestBody IotDeviceRegisterReqDTO registerReqDTO); + // ========== 插件相关 ========== /** diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java new file mode 100644 index 000000000..a627cba42 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; + +import lombok.Data; + +/** + * IoT 设备【注册】注册 Request DTO + * + * @author 芋道源码 + */ +@Data +public class IotDeviceRegisterReqDTO extends IotDeviceUpstreamAbstractReqDTO { +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java index f8eca51ed..6dd10a386 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java @@ -26,7 +26,11 @@ public enum IotDeviceMessageIdentifierEnum { OTA_UPGRADE("upgrade"), // 下行 OTA_PULL("pull"), // 上行 OTA_PROGRESS("progress"), // 上行 - OTA_REPORT("report"),; // 上行 + OTA_REPORT("report"), // 上行 + + REGISTER_REGISTER("register"), // 上行 + REGISTER_SUB_REGISTER("sub_register"), // 上行 + REGISTER_SUB_UNREGISTER("sub_unregister"),; // 下行 /** * 标志符 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java index 2ee0a8acc..000af57d4 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java @@ -14,11 +14,12 @@ import java.util.Arrays; public enum IotDeviceMessageTypeEnum implements ArrayValuable { STATE("state"), // 设备状态 - PROPERTY("property"), // 设备属性 - EVENT("event"), // 设备事件 - SERVICE("service"), // 设备服务 - CONFIG("config"), // 设备配置 - OTA("ota"),; // 设备 OTA + PROPERTY("property"), // 设备属性:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 + EVENT("event"), // 设备事件:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 + SERVICE("service"), // 设备服务:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 + CONFIG("config"), // 设备配置:可参考 https://help.aliyun.com/zh/iot/user-guide/remote-configuration-1 远程配置 + OTA("ota"), // 设备 OTA:可参考 https://help.aliyun.com/zh/iot/user-guide/ota-update OTA 升级 + REGISTER("register"),; // 设备注册:可参考 https://help.aliyun.com/zh/iot/user-guide/register-devices 设备身份注册 public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java index 6a437dfca..21b6c542a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.iot.api.device; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*; import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService; import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService; import org.springframework.validation.annotation.Validated; @@ -46,6 +43,12 @@ public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi { return success(true); } + @Override + public CommonResult registerDevice(IotDeviceRegisterReqDTO registerReqDTO) { + deviceUpstreamService.registerDevice(registerReqDTO); + return success(true); + } + // ========== 插件相关 ========== @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java index 7d9ac6a0d..5da2f501b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.Size; import lombok.Data; @@ -18,6 +19,7 @@ public class IotDeviceSaveReqVO { private String deviceKey; @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @NotEmpty(message = "设备名称不能为空") private String deviceName; @Schema(description = "备注名称", example = "张三") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java index 34fd35706..37c7be44b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.product; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -19,7 +19,7 @@ import lombok.*; @Builder @NoArgsConstructor @AllArgsConstructor -public class IotProductDO extends BaseDO { +public class IotProductDO extends TenantBaseDO { /** * 产品 ID diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index f77ae3a37..9ff0e81c2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; import javax.annotation.Nullable; import java.util.Collection; @@ -17,13 +18,23 @@ import java.util.List; public interface IotDeviceService { /** - * 创建设备 + * 【管理员】创建设备 * * @param createReqVO 创建信息 * @return 编号 */ Long createDevice(@Valid IotDeviceSaveReqVO createReqVO); + /** + * 【设备注册】创建设备 + * + * @param productKey 产品标识 + * @param deviceName 设备名称 + * @return 设备 + */ + IotDeviceDO createDevice(@NotEmpty(message = "产品标识不能为空") String productKey, + @NotEmpty(message = "设备名称不能为空") String deviceName); + /** * 更新设备 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 2680f47d1..6e20d724f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -71,7 +71,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { } }); // 1.3 校验设备名称在同一产品下是否唯一 - if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), createReqVO.getDeviceKey()) != null) { + if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), createReqVO.getDeviceName()) != null) { throw exception(DEVICE_NAME_EXISTS); } // 1.4 校验父设备是否为合法网关 @@ -82,23 +82,54 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 1.5 校验分组存在 deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds()); - // 2.1 转换 VO 为 DO - // TODO @芋艿:各种 mqtt 是不是可以简化! - IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class, o -> { - o.setProductKey(product.getProductKey()).setDeviceType(product.getDeviceType()); - // 生成并设置必要的字段 - o.setDeviceSecret(generateDeviceSecret()) - .setMqttClientId(generateMqttClientId()) - .setMqttUsername(generateMqttUsername(o.getDeviceName(), o.getProductKey())) - .setMqttPassword(generateMqttPassword()); - // 设置设备状态为未激活 - o.setState(IotDeviceStateEnum.INACTIVE.getState()); - }); - // 2.2 插入到数据库 + // 2. 插入到数据库 + IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class); + initDevice(device, product); deviceMapper.insert(device); return device.getId(); } + @Override + public IotDeviceDO createDevice(String productKey, String deviceName) { + // 1.1 校验产品是否存在 + IotProductDO product = TenantUtils.executeIgnore(() -> + productService.getProductByProductKey(productKey)); + if (product == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + // 1.2 校验设备标识是否唯一 + String deviceKey = generateDeviceKey(); + TenantUtils.executeIgnore(() -> { + if (deviceMapper.selectByDeviceKey(deviceKey) != null) { + throw exception(PRODUCT_KEY_EXISTS); + } + }); + return TenantUtils.execute(product.getTenantId(), () -> { + // 1.3 校验设备名称在同一产品下是否唯一 + if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), deviceName) != null) { + throw exception(DEVICE_NAME_EXISTS); + } + + // 2. 插入到数据库 + IotDeviceDO device = new IotDeviceDO().setDeviceName(deviceName).setDeviceKey(deviceKey); + initDevice(device, product); + deviceMapper.insert(device); + return device; + }); + } + + private void initDevice(IotDeviceDO device, IotProductDO product) { + device.setProductId(product.getId()).setProductKey(product.getProductKey()).setDeviceType(product.getDeviceType()); + // 生成并设置必要的字段 + // TODO @芋艿:各种 mqtt 是不是可以简化! + device.setDeviceSecret(generateDeviceSecret()) + .setMqttClientId(generateMqttClientId()) + .setMqttUsername(generateMqttUsername(device.getDeviceName(), device.getProductKey())) + .setMqttPassword(generateMqttPassword()); + // 设置设备状态为未激活 + device.setState(IotDeviceStateEnum.INACTIVE.getState()); + } + @Override public void updateDevice(IotDeviceSaveReqVO updateReqVO) { updateReqVO.setDeviceKey(null).setDeviceName(null).setProductId(null); // 不允许更新 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java index 8bc0ffd69..330444e34 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.service.device.control; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceRegisterReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; import jakarta.validation.Valid; @@ -43,4 +44,11 @@ public interface IotDeviceUpstreamService { */ void reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO); + /** + * 注册设备 + * + * @param registerReqDTO 注册设备 DTO + */ + void registerDevice(IotDeviceRegisterReqDTO registerReqDTO); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index 1cbf3cd2a..e3cd43bad 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -7,10 +7,7 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceUpstreamAbstractReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; @@ -165,6 +162,29 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { sendDeviceMessage(message, device); } + @Override + public void registerDevice(IotDeviceRegisterReqDTO registerReqDTO) { + // 1.1 注册设备 + log.info("[registerDevice][注册设备: {}]", registerReqDTO); + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( + registerReqDTO.getProductKey(), registerReqDTO.getDeviceName()); + boolean register = device == null; + if (device == null) { + device = deviceService.createDevice(registerReqDTO.getProductKey(), registerReqDTO.getDeviceName()); + log.info("[registerDevice][请求({}) 成功注册设备({})]", registerReqDTO, device); + } + // 1.2 记录设备的最后时间 + updateDeviceLastTime(device, registerReqDTO); + + // 2. 发送设备消息 + if (register) { + IotDeviceMessage message = BeanUtils.toBean(registerReqDTO, IotDeviceMessage.class) + .setType(IotDeviceMessageTypeEnum.REGISTER.getType()) + .setIdentifier(IotDeviceMessageIdentifierEnum.REGISTER_REGISTER.getIdentifier()); + sendDeviceMessage(message, device); + } + } + private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) { // 1. 【异步】记录设备与插件实例的映射 pluginInstanceService.updateDevicePluginInstanceProcessIdAsync(device.getDeviceKey(), reqDTO.getProcessId()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 9a2e96f67..a317cacae 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -45,6 +45,14 @@ public interface IotProductService { */ IotProductDO getProduct(Long id); + /** + * 根据产品 key 获得产品 + * + * @param productKey 产品 key + * @return 产品 + */ + IotProductDO getProductByProductKey(String productKey); + /** * 校验产品存在 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 3fa0bcf0b..fc2300b7c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -105,6 +105,11 @@ public class IotProductServiceImpl implements IotProductService { return productMapper.selectById(id); } + @Override + public IotProductDO getProductByProductKey(String productKey) { + return productMapper.selectByProductKey(productKey); + } + @Override public PageResult getProductPage(IotProductPageReqVO pageReqVO) { return productMapper.selectPage(pageReqVO); From 4254c06c3764a8c8b25d4182ef8d50f03ef88bad Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 8 Feb 2025 20:56:16 +0800 Subject: [PATCH 161/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=20sub=20register=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/api/device/IotDeviceUpstreamApi.java | 9 +++ .../upstream/IotDeviceRegisterReqDTO.java | 2 +- .../upstream/IotDeviceRegisterSubReqDTO.java | 42 +++++++++++++ .../IotDeviceMessageIdentifierEnum.java | 4 +- .../product/IotProductDeviceTypeEnum.java | 10 +++ .../api/device/IoTDeviceUpstreamApiImpl.java | 6 ++ .../device/vo/device/IotDeviceSaveReqVO.java | 4 +- .../iot/service/device/IotDeviceService.java | 15 ++++- .../service/device/IotDeviceServiceImpl.java | 61 ++++++++++--------- .../control/IotDeviceUpstreamService.java | 12 ++-- .../control/IotDeviceUpstreamServiceImpl.java | 59 +++++++++++++++--- 11 files changed, 176 insertions(+), 48 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java index a69ea180c..b6068de63 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java @@ -53,6 +53,15 @@ public interface IotDeviceUpstreamApi { @PostMapping(PREFIX + "/register") CommonResult registerDevice(@Valid @RequestBody IotDeviceRegisterReqDTO registerReqDTO); + // TODO @芋艿:这个需要 plugins 接入下 + /** + * 注册子设备 + * + * @param registerReqDTO 注册子设备 DTO + */ + @PostMapping(PREFIX + "/register-sub") + CommonResult registerSubDevice(@Valid @RequestBody IotDeviceRegisterSubReqDTO registerReqDTO); + // ========== 插件相关 ========== /** diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java index a627cba42..cab55e832 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; import lombok.Data; /** - * IoT 设备【注册】注册 Request DTO + * IoT 设备【注册】自己 Request DTO * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java new file mode 100644 index 000000000..6e985f955 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +import java.util.List; + +/** + * IoT 设备【注册】子设备 Request DTO + * + * @author 芋道源码 + */ +@Data +public class IotDeviceRegisterSubReqDTO extends IotDeviceUpstreamAbstractReqDTO { + + /** + * 子设备数组 + */ + @NotEmpty(message = "子设备不能为空") + private List params; + + /** + * 设备信息 + */ + @Data + public static class Device { + + /** + * 产品标识 + */ + @NotEmpty(message = "产品标识不能为空") + private String productKey; + + /** + * 设备名称 + */ + @NotEmpty(message = "设备名称不能为空") + private String deviceName; + + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java index 6dd10a386..7932844a7 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java @@ -29,8 +29,8 @@ public enum IotDeviceMessageIdentifierEnum { OTA_REPORT("report"), // 上行 REGISTER_REGISTER("register"), // 上行 - REGISTER_SUB_REGISTER("sub_register"), // 上行 - REGISTER_SUB_UNREGISTER("sub_unregister"),; // 下行 + REGISTER_REGISTER_SUB("register_sub"), // 上行 + REGISTER_UNREGISTER_SUB("unregister_sub"),; // 下行 /** * 标志符 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java index cc81e945b..238e3e25f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java @@ -46,4 +46,14 @@ public enum IotProductDeviceTypeEnum implements ArrayValuable { return GATEWAY.getType().equals(type); } + /** + * 判断是否是网关子设备 + * + * @param type 类型 + * @return 是否是网关子设备 + */ + public static boolean isGatewaySub(Integer type) { + return GATEWAY_SUB.getType().equals(type); + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java index 21b6c542a..46a3e1f6c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java @@ -49,6 +49,12 @@ public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi { return success(true); } + @Override + public CommonResult registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) { + deviceUpstreamService.registerSubDevice(registerReqDTO); + return success(true); + } + // ========== 插件相关 ========== @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java index 5da2f501b..7bf0f33ee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.Size; import lombok.Data; @@ -18,8 +17,7 @@ public class IotDeviceSaveReqVO { @Size(max = 50, message = "设备编号长度不能超过 50 个字符") private String deviceKey; - @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") - @NotEmpty(message = "设备名称不能为空") + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.AUTO, example = "王五") private String deviceName; @Schema(description = "备注名称", example = "张三") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 9ff0e81c2..fc6717bfd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -30,10 +30,12 @@ public interface IotDeviceService { * * @param productKey 产品标识 * @param deviceName 设备名称 + * @param gatewayId 网关设备 ID * @return 设备 */ IotDeviceDO createDevice(@NotEmpty(message = "产品标识不能为空") String productKey, - @NotEmpty(message = "设备名称不能为空") String deviceName); + @NotEmpty(message = "设备名称不能为空") String deviceName, + Long gatewayId); /** * 更新设备 @@ -42,6 +44,17 @@ public interface IotDeviceService { */ void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO); + // TODO @芋艿:先这么实现。未来看情况,要不要自己实现 + /** + * 更新设备的所属网关 + * + * @param id 编号 + * @param gatewayId 网关设备 ID + */ + default void updateDeviceGateway(Long id, Long gatewayId) { + updateDevice(new IotDeviceSaveReqVO().setId(id).setGatewayId(gatewayId)); + } + /** * 更新设备状态 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 6e20d724f..144377fa0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -64,22 +64,10 @@ public class IotDeviceServiceImpl implements IotDeviceService { if (product == null) { throw exception(PRODUCT_NOT_EXISTS); } - // 1.2 校验设备标识是否唯一 - TenantUtils.executeIgnore(() -> { - if (deviceMapper.selectByDeviceKey(createReqVO.getDeviceKey()) != null) { - throw exception(PRODUCT_KEY_EXISTS); - } - }); - // 1.3 校验设备名称在同一产品下是否唯一 - if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), createReqVO.getDeviceName()) != null) { - throw exception(DEVICE_NAME_EXISTS); - } - // 1.4 校验父设备是否为合法网关 - if (IotProductDeviceTypeEnum.isGateway(product.getDeviceType()) - && createReqVO.getGatewayId() != null) { - validateGatewayDeviceExists(createReqVO.getGatewayId()); - } - // 1.5 校验分组存在 + // 1.2 统一校验 + validateCreateDeviceParam(product.getProductKey(), createReqVO.getDeviceName(), createReqVO.getDeviceKey(), + createReqVO.getGatewayId(), product); + // 1.3 校验分组存在 deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds()); // 2. 插入到数据库 @@ -90,34 +78,47 @@ public class IotDeviceServiceImpl implements IotDeviceService { } @Override - public IotDeviceDO createDevice(String productKey, String deviceName) { + public IotDeviceDO createDevice(String productKey, String deviceName, Long gatewayId) { + String deviceKey = generateDeviceKey(); // 1.1 校验产品是否存在 IotProductDO product = TenantUtils.executeIgnore(() -> productService.getProductByProductKey(productKey)); if (product == null) { throw exception(PRODUCT_NOT_EXISTS); } - // 1.2 校验设备标识是否唯一 - String deviceKey = generateDeviceKey(); - TenantUtils.executeIgnore(() -> { - if (deviceMapper.selectByDeviceKey(deviceKey) != null) { - throw exception(PRODUCT_KEY_EXISTS); - } - }); return TenantUtils.execute(product.getTenantId(), () -> { - // 1.3 校验设备名称在同一产品下是否唯一 - if (deviceMapper.selectByProductKeyAndDeviceName(product.getProductKey(), deviceName) != null) { - throw exception(DEVICE_NAME_EXISTS); - } + // 1.2 校验设备名称在同一产品下是否唯一 + validateCreateDeviceParam(productKey, deviceName, deviceKey, gatewayId, product); // 2. 插入到数据库 - IotDeviceDO device = new IotDeviceDO().setDeviceName(deviceName).setDeviceKey(deviceKey); + IotDeviceDO device = new IotDeviceDO().setDeviceName(deviceName).setDeviceKey(deviceKey) + .setGatewayId(gatewayId); initDevice(device, product); deviceMapper.insert(device); return device; }); } + private void validateCreateDeviceParam(String productKey, String deviceName, String deviceKey, + Long gatewayId, IotProductDO product) { + TenantUtils.executeIgnore(() -> { + // 校验设备名称在同一产品下是否唯一 + if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) { + throw exception(DEVICE_NAME_EXISTS); + } + // 校验设备标识是否唯一 + if (deviceMapper.selectByDeviceKey(deviceKey) != null) { + throw exception(DEVICE_KEY_EXISTS); + } + }); + + // 校验父设备是否为合法网关 + if (IotProductDeviceTypeEnum.isGatewaySub(product.getDeviceType()) + && gatewayId != null) { + validateGatewayDeviceExists(gatewayId); + } + } + private void initDevice(IotDeviceDO device, IotProductDO product) { device.setProductId(product.getId()).setProductKey(product.getProductKey()).setDeviceType(product.getDeviceType()); // 生成并设置必要的字段 @@ -136,7 +137,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 1.1 校验存在 IotDeviceDO device = validateDeviceExists(updateReqVO.getId()); // 1.2 校验父设备是否为合法网关 - if (IotProductDeviceTypeEnum.isGateway(device.getDeviceType()) + if (IotProductDeviceTypeEnum.isGatewaySub(device.getDeviceType()) && updateReqVO.getGatewayId() != null) { validateGatewayDeviceExists(updateReqVO.getGatewayId()); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java index 330444e34..41a8f8b5e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java @@ -1,9 +1,6 @@ package cn.iocoder.yudao.module.iot.service.device.control; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceRegisterReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; import jakarta.validation.Valid; @@ -51,4 +48,11 @@ public interface IotDeviceUpstreamService { */ void registerDevice(IotDeviceRegisterReqDTO registerReqDTO); + /** + * 注册子设备 + * + * @param registerReqDTO 注册子设备 DTO + */ + void registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index e3cd43bad..14897ab10 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.device.control; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjUtil; @@ -13,6 +14,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; +import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; @@ -164,20 +166,30 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { @Override public void registerDevice(IotDeviceRegisterReqDTO registerReqDTO) { - // 1.1 注册设备 log.info("[registerDevice][注册设备: {}]", registerReqDTO); - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( - registerReqDTO.getProductKey(), registerReqDTO.getDeviceName()); - boolean register = device == null; + registerDevice0(registerReqDTO.getProductKey(), registerReqDTO.getDeviceName(), null, registerReqDTO); + } + + private void registerDevice0(String productKey, String deviceName, Long gatewayId, + IotDeviceUpstreamAbstractReqDTO registerReqDTO) { + // 1.1 注册设备 + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(productKey, deviceName); + boolean registerNew = device == null; if (device == null) { - device = deviceService.createDevice(registerReqDTO.getProductKey(), registerReqDTO.getDeviceName()); - log.info("[registerDevice][请求({}) 成功注册设备({})]", registerReqDTO, device); + device = deviceService.createDevice(productKey, deviceName, gatewayId); + log.info("[registerDevice0][消息({}) 设备({}/{}) 成功注册]", registerReqDTO, productKey, device); + } else if (gatewayId != null && ObjUtil.notEqual(device.getGatewayId(), gatewayId)) { + Long deviceId = device.getId(); + TenantUtils.execute(device.getTenantId(), + () -> deviceService.updateDeviceGateway(deviceId, gatewayId)); + log.info("[registerDevice0][消息({}) 设备({}/{}) 更新网关设备编号({})]", + registerReqDTO, productKey, device, gatewayId); } // 1.2 记录设备的最后时间 updateDeviceLastTime(device, registerReqDTO); // 2. 发送设备消息 - if (register) { + if (registerNew) { IotDeviceMessage message = BeanUtils.toBean(registerReqDTO, IotDeviceMessage.class) .setType(IotDeviceMessageTypeEnum.REGISTER.getType()) .setIdentifier(IotDeviceMessageIdentifierEnum.REGISTER_REGISTER.getIdentifier()); @@ -185,6 +197,39 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { } } + @Override + public void registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) { + // 1.1 注册子设备 + log.info("[registerSubDevice][注册子设备: {}]", registerReqDTO); + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( + registerReqDTO.getProductKey(), registerReqDTO.getDeviceName()); + if (device == null) { + log.error("[registerSubDevice][设备({}/{}) 不存在]", + registerReqDTO.getProductKey(), registerReqDTO.getDeviceName()); + return; + } + if (!IotProductDeviceTypeEnum.isGateway(device.getDeviceType())) { + log.error("[registerSubDevice][设备({}/{}) 不是网关设备({}),无法进行注册]", + registerReqDTO.getProductKey(), registerReqDTO.getDeviceName(), device); + return; + } + // 1.2 记录设备的最后时间 + updateDeviceLastTime(device, registerReqDTO); + + // 2. 处理子设备 + if (CollUtil.isNotEmpty(registerReqDTO.getParams())) { + registerReqDTO.getParams().forEach(subDevice -> registerDevice0( + subDevice.getProductKey(), subDevice.getDeviceName(), device.getId(), registerReqDTO)); + } + + // 3. 发送设备消息 + IotDeviceMessage message = BeanUtils.toBean(registerReqDTO, IotDeviceMessage.class) + .setType(IotDeviceMessageTypeEnum.REGISTER.getType()) + .setIdentifier(IotDeviceMessageIdentifierEnum.REGISTER_REGISTER_SUB.getIdentifier()) + .setData(registerReqDTO.getParams()); + sendDeviceMessage(message, device); + } + private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) { // 1. 【异步】记录设备与插件实例的映射 pluginInstanceService.updateDevicePluginInstanceProcessIdAsync(device.getDeviceKey(), reqDTO.getProcessId()); From bc9b3715b1e6d03e6cb0aa117ec0e0afdd02137d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 8 Feb 2025 21:44:49 +0800 Subject: [PATCH 162/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT=EF=BC=9A=E8=AE=BE=E5=A4=87=E6=8B=93?= =?UTF-8?q?=E6=89=91=E5=9B=BE=E7=9A=84=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/api/device/IotDeviceUpstreamApi.java | 9 ++++ .../upstream/IotDeviceEventReportReqDTO.java | 2 + .../IotDevicePropertyReportReqDTO.java | 2 + .../upstream/IotDeviceRegisterSubReqDTO.java | 1 + .../upstream/IotDeviceStateUpdateReqDTO.java | 2 + .../upstream/IotDeviceTopologyAddReqDTO.java | 43 +++++++++++++++++ .../IotDeviceMessageIdentifierEnum.java | 5 +- .../device/IotDeviceMessageTypeEnum.java | 3 +- .../api/device/IoTDeviceUpstreamApiImpl.java | 6 +++ .../admin/device/IotDeviceController.java | 2 + .../iot/mq/message/IotDeviceMessage.java | 3 +- .../iot/service/device/IotDeviceService.java | 8 ++-- .../service/device/IotDeviceServiceImpl.java | 15 +++--- .../IotDeviceDownstreamServiceImpl.java | 1 + .../control/IotDeviceUpstreamService.java | 7 +++ .../control/IotDeviceUpstreamServiceImpl.java | 47 +++++++++++++++++++ .../upstream/IotDeviceUpstreamClient.java | 23 +++++++-- 17 files changed, 161 insertions(+), 18 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java index b6068de63..7d198eba3 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java @@ -62,6 +62,15 @@ public interface IotDeviceUpstreamApi { @PostMapping(PREFIX + "/register-sub") CommonResult registerSubDevice(@Valid @RequestBody IotDeviceRegisterSubReqDTO registerReqDTO); + // TODO @芋艿:这个需要 plugins 接入下 + /** + * 注册设备拓扑 + * + * @param addReqDTO 注册设备拓扑 DTO + */ + @PostMapping(PREFIX + "/add-topology") + CommonResult addDeviceTopology(@Valid @RequestBody IotDeviceTopologyAddReqDTO addReqDTO); + // ========== 插件相关 ========== /** diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java index 8a7f3ff14..34e6283d9 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java @@ -7,6 +7,8 @@ import java.util.Map; /** * IoT 设备【事件】上报 Request DTO + * + * @author 芋道源码 */ @Data public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java index c1654e69b..4a276bd22 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java @@ -7,6 +7,8 @@ import java.util.Map; /** * IoT 设备【属性】上报 Request DTO + * + * @author 芋道源码 */ @Data public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java index 6e985f955..0b826fbb1 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java @@ -13,6 +13,7 @@ import java.util.List; @Data public class IotDeviceRegisterSubReqDTO extends IotDeviceUpstreamAbstractReqDTO { + // TODO @芋艿:看看要不要优化命名 /** * 子设备数组 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceStateUpdateReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceStateUpdateReqDTO.java index 02852cfe7..38c479a57 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceStateUpdateReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceStateUpdateReqDTO.java @@ -7,6 +7,8 @@ import lombok.Data; /** * IoT 设备【状态】更新 Request DTO + * + * @author 芋道源码 */ @Data public class IotDeviceStateUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java new file mode 100644 index 000000000..38b2b69ef --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +import java.util.List; + +/** + * IoT 设备【拓扑】添加 Request DTO + */ +@Data +public class IotDeviceTopologyAddReqDTO extends IotDeviceUpstreamAbstractReqDTO { + + // TODO @芋艿:看看要不要优化命名 + /** + * 子设备数组 + */ + @NotEmpty(message = "子设备不能为空") + private List params; + + /** + * 设备信息 + */ + @Data + public static class Device { + + /** + * 产品标识 + */ + @NotEmpty(message = "产品标识不能为空") + private String productKey; + + /** + * 设备名称 + */ + @NotEmpty(message = "设备名称不能为空") + private String deviceName; + + // TODO @芋艿:阿里云还有 sign 签名 + + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java index 7932844a7..5bd169aba 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java @@ -30,7 +30,10 @@ public enum IotDeviceMessageIdentifierEnum { REGISTER_REGISTER("register"), // 上行 REGISTER_REGISTER_SUB("register_sub"), // 上行 - REGISTER_UNREGISTER_SUB("unregister_sub"),; // 下行 + REGISTER_UNREGISTER_SUB("unregister_sub"), // 下行 + + TOPOLOGY_ADD("topology_add"), // 下行; + ; /** * 标志符 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java index 000af57d4..0354157ed 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java @@ -19,7 +19,8 @@ public enum IotDeviceMessageTypeEnum implements ArrayValuable { SERVICE("service"), // 设备服务:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务 CONFIG("config"), // 设备配置:可参考 https://help.aliyun.com/zh/iot/user-guide/remote-configuration-1 远程配置 OTA("ota"), // 设备 OTA:可参考 https://help.aliyun.com/zh/iot/user-guide/ota-update OTA 升级 - REGISTER("register"),; // 设备注册:可参考 https://help.aliyun.com/zh/iot/user-guide/register-devices 设备身份注册 + REGISTER("register"), // 设备注册:可参考 https://help.aliyun.com/zh/iot/user-guide/register-devices 设备身份注册 + TOPOLOGY("topology"),; // 设备拓扑:可参考 https://help.aliyun.com/zh/iot/user-guide/manage-topological-relationships 设备拓扑 public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java index 46a3e1f6c..442c6b0ca 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java @@ -55,6 +55,12 @@ public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi { return success(true); } + @Override + public CommonResult addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) { + deviceUpstreamService.addDeviceTopology(addReqDTO); + return success(true); + } + // ========== 插件相关 ========== @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 24d426381..ac2c6ebd8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -61,6 +61,8 @@ public class IotDeviceController { return success(true); } + // TODO @芋艿:参考阿里云:1)绑定网关;2)解绑网关 + @PutMapping("/update-group") @Operation(summary = "更新设备分组") @PreAuthorize("@ss.hasPermission('iot:device:update')") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java index e4766755d..0e8309a82 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java @@ -9,8 +9,9 @@ import lombok.NoArgsConstructor; import java.time.LocalDateTime; +// TODO @芋艿:参考阿里云的物模型,优化 IoT 上下行消息的设计,尽量保持一致(渐进式,不要一口气)! /** - * 设备消息 + * IoT 设备消息 */ @Data @NoArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index fc6717bfd..24532d254 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -30,12 +30,12 @@ public interface IotDeviceService { * * @param productKey 产品标识 * @param deviceName 设备名称 - * @param gatewayId 网关设备 ID + * @param gatewayId 网关设备 ID * @return 设备 */ IotDeviceDO createDevice(@NotEmpty(message = "产品标识不能为空") String productKey, - @NotEmpty(message = "设备名称不能为空") String deviceName, - Long gatewayId); + @NotEmpty(message = "设备名称不能为空") String deviceName, + Long gatewayId); /** * 更新设备 @@ -58,7 +58,7 @@ public interface IotDeviceService { /** * 更新设备状态 * - * @param id 编号 + * @param id 编号 * @param state 状态 */ void updateDeviceState(Long id, Integer state); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 144377fa0..66854e84b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -81,8 +81,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { public IotDeviceDO createDevice(String productKey, String deviceName, Long gatewayId) { String deviceKey = generateDeviceKey(); // 1.1 校验产品是否存在 - IotProductDO product = TenantUtils.executeIgnore(() -> - productService.getProductByProductKey(productKey)); + IotProductDO product = TenantUtils.executeIgnore(() -> productService.getProductByProductKey(productKey)); if (product == null) { throw exception(PRODUCT_NOT_EXISTS); } @@ -100,7 +99,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { } private void validateCreateDeviceParam(String productKey, String deviceName, String deviceKey, - Long gatewayId, IotProductDO product) { + Long gatewayId, IotProductDO product) { TenantUtils.executeIgnore(() -> { // 校验设备名称在同一产品下是否唯一 if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) { @@ -120,7 +119,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { } private void initDevice(IotDeviceDO device, IotProductDO product) { - device.setProductId(product.getId()).setProductKey(product.getProductKey()).setDeviceType(product.getDeviceType()); + device.setProductId(product.getId()).setProductKey(product.getProductKey()) + .setDeviceType(product.getDeviceType()); // 生成并设置必要的字段 // TODO @芋艿:各种 mqtt 是不是可以简化! device.setDeviceSecret(generateDeviceSecret()) @@ -269,7 +269,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 2. 更新状态和时间 IotDeviceDO updateObj = new IotDeviceDO().setId(id).setState(state); if (device.getOnlineTime() == null - && Objects.equals(state, IotDeviceStateEnum.ONLINE.getState())) { + && Objects.equals(state, IotDeviceStateEnum.ONLINE.getState())) { updateObj.setActiveTime(LocalDateTime.now()); } if (Objects.equals(state, IotDeviceStateEnum.ONLINE.getState())) { @@ -363,7 +363,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { // 2.1.1 校验字段是否符合要求 try { ValidationUtils.validate(importDevice); - } catch (ConstraintViolationException ex){ + } catch (ConstraintViolationException ex) { respVO.getFailureDeviceNames().put(importDevice.getDeviceName(), ex.getMessage()); return; } @@ -427,7 +427,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { } @CacheEvict(value = RedisKeyConstants.DEVICE, key = "#device.productKey + '_' + #device.deviceName") - public void deleteDeviceCache0(IotDeviceDO device) {} + public void deleteDeviceCache0(IotDeviceDO device) { + } private IotDeviceServiceImpl getSelf() { return SpringUtil.getBean(getClass()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java index 7c1ec5bb8..3aab53de9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java @@ -88,6 +88,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.OTA.getType())) { return otaUpgrade(downstreamReqVO, device, parentDevice); } + // TODO @芋艿:取消设备的网关的时,要不要下发 REGISTER_UNREGISTER_SUB ? throw new IllegalArgumentException("不支持的下行消息类型:" + downstreamReqVO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java index 41a8f8b5e..39b0d19c0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java @@ -55,4 +55,11 @@ public interface IotDeviceUpstreamService { */ void registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO); + /** + * 添加设备拓扑 + * + * @param addReqDTO 添加设备拓扑 DTO + */ + void addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index 14897ab10..ad065f930 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -220,6 +220,7 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { if (CollUtil.isNotEmpty(registerReqDTO.getParams())) { registerReqDTO.getParams().forEach(subDevice -> registerDevice0( subDevice.getProductKey(), subDevice.getDeviceName(), device.getId(), registerReqDTO)); + // TODO @芋艿:后续要处理,每个设备是否成功 } // 3. 发送设备消息 @@ -230,6 +231,52 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { sendDeviceMessage(message, device); } + @Override + public void addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) { + // 1.1 获得设备 + log.info("[addDeviceTopology][添加设备拓扑: {}]", addReqDTO); + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( + addReqDTO.getProductKey(), addReqDTO.getDeviceName()); + if (device == null) { + log.error("[addDeviceTopology][设备({}/{}) 不存在]", + addReqDTO.getProductKey(), addReqDTO.getDeviceName()); + return; + } + if (!IotProductDeviceTypeEnum.isGateway(device.getDeviceType())) { + log.error("[addDeviceTopology][设备({}/{}) 不是网关设备({}),无法进行拓扑添加]", + addReqDTO.getProductKey(), addReqDTO.getDeviceName(), device); + return; + } + // 1.2 记录设备的最后时间 + updateDeviceLastTime(device, addReqDTO); + + // 2. 处理拓扑 + if (CollUtil.isNotEmpty(addReqDTO.getParams())) { + TenantUtils.execute(device.getTenantId(), () -> { + addReqDTO.getParams().forEach(subDevice -> { + IotDeviceDO subDeviceDO = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( + subDevice.getProductKey(), subDevice.getDeviceName()); + // TODO @芋艿:后续要处理,每个设备是否成功 + if (subDeviceDO == null) { + log.error("[addDeviceTopology][子设备({}/{}) 不存在]", + subDevice.getProductKey(), subDevice.getDeviceName()); + return; + } + deviceService.updateDeviceGateway(subDeviceDO.getId(), device.getId()); + log.info("[addDeviceTopology][子设备({}/{}) 添加到网关设备({}) 成功]", + subDevice.getProductKey(), subDevice.getDeviceName(), device); + }); + }); + } + + // 3. 发送设备消息 + IotDeviceMessage message = BeanUtils.toBean(addReqDTO, IotDeviceMessage.class) + .setType(IotDeviceMessageTypeEnum.TOPOLOGY.getType()) + .setIdentifier(IotDeviceMessageIdentifierEnum.TOPOLOGY_ADD.getIdentifier()) + .setData(addReqDTO.getParams()); + sendDeviceMessage(message, device); + } + private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) { // 1. 【异步】记录设备与插件实例的映射 pluginInstanceService.updateDevicePluginInstanceProcessIdAsync(device.getDeviceKey(), reqDTO.getProcessId()); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java index f3934cb0d..ec662510b 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java @@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.upstream; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*; import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -42,6 +39,24 @@ public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi { return doPost(url, reportReqDTO); } + // TODO @芋艿:待实现 + @Override + public CommonResult registerDevice(IotDeviceRegisterReqDTO registerReqDTO) { + return null; + } + + // TODO @芋艿:待实现 + @Override + public CommonResult registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) { + return null; + } + + // TODO @芋艿:待实现 + @Override + public CommonResult addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) { + return null; + } + @Override public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { String url = properties.getUpstreamUrl() + URL_PREFIX + "/report-property"; From d116e5eec1361c74bef04dd001884adb43fb1e26 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 9 Feb 2025 07:26:01 +0800 Subject: [PATCH 163/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E7=BB=B4=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/controller/admin/thingmodel/model/ThingModelEvent.java | 2 +- .../iot/controller/admin/thingmodel/model/ThingModelParam.java | 2 +- .../controller/admin/thingmodel/model/ThingModelProperty.java | 2 +- .../controller/admin/thingmodel/model/ThingModelService.java | 2 +- .../iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index 151d1f571..d3f0d33c5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -21,7 +21,7 @@ public class ThingModelEvent { * 事件标识符 */ @NotEmpty(message = "事件标识符不能为空") - @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "事件标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "事件标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") private String identifier; /** * 事件名称 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java index dc1e7deac..89b162db9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java @@ -22,7 +22,7 @@ public class ThingModelParam { * 参数标识符 */ @NotEmpty(message = "参数标识符不能为空") - @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "参数标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "参数标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") private String identifier; /** * 参数名称 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index 866f25b84..395c8611e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -24,7 +24,7 @@ public class ThingModelProperty { * 属性标识符 */ @NotEmpty(message = "属性标识符不能为空") - @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "属性标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "属性标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") private String identifier; /** * 属性名称 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index 7db2b5f7a..7f97b9402 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -21,7 +21,7 @@ public class ThingModelService { * 服务标识符 */ @NotEmpty(message = "服务标识符不能为空") - @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "服务标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "服务标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") private String identifier; /** * 服务名称 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java index 72565a8c4..15a5b9f95 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java @@ -15,7 +15,7 @@ import java.time.LocalDateTime; @ExcelIgnoreUnannotated public class IotThingModelRespVO { - @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") @ExcelProperty("产品ID") private Long id; From 2ab2e45465b268e288790dad9a742ee47f3f54ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=98=AF=E7=9D=A1=E7=9D=80=E7=9A=84=E6=B0=B4?= <850083043@qq.com> Date: Tue, 11 Feb 2025 06:15:30 +0000 Subject: [PATCH 164/228] =?UTF-8?q?=E6=9B=BF=E6=8D=A2javax=E4=B8=BAjakarta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 冰是睡着的水 <850083043@qq.com> --- .../yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java | 2 +- .../yudao/module/iot/job/plugin/IotPluginInstancesJob.java | 2 +- .../mq/consumer/device/IotDevicePropertyMessageConsumer.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java index 442c6b0ca..699f3dd75 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/IotPluginInstancesJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/IotPluginInstancesJob.java index 1d2441737..ff93dc8db 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/IotPluginInstancesJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/IotPluginInstancesJob.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService; import org.springframework.stereotype.Component; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import java.time.Duration; import java.time.LocalDateTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java index 3f7fe1089..bf9cc5332 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDevicePropertyMessageConsumer.java @@ -10,7 +10,7 @@ import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; -import javax.annotation.Resource; +import jakarta.annotation.Resource; /** * 针对 {@link IotDeviceMessage} 的消费者,记录设备属性 From c27b02beb634aa8c702353efface531d2562d76c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 12 Feb 2025 18:19:53 +0800 Subject: [PATCH 165/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=BE=85=E5=AE=9A=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/dal/dataobject/device/IotDeviceDO.java | 2 ++ .../module/iot/dal/tdengine/IotDevicePropertyMapper.java | 3 ++- .../module/iot/service/product/IotProductServiceImpl.java | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index d99145476..4c52031fe 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -122,6 +122,7 @@ public class IotDeviceDO extends TenantBaseDO { */ private String firmwareId; + // TODO @芋艿:【待定 003】:要不要增加 username?目前 tl 有,阿里云之类的没有 /** * 设备密钥,用于设备认证,需安全存储 */ @@ -144,6 +145,7 @@ public class IotDeviceDO extends TenantBaseDO { // TODO @haohao:是不是要枚举哈 private String authType; + // TODO @芋艿:【待定 002】:1)设备维护的时候,设置位置?类似 tl?;2)设备上传的时候,设置位置,类似 it? /** * 设备位置的纬度 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java index f2d6af97e..e506b49d4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java @@ -32,6 +32,7 @@ public interface IotDevicePropertyMapper { default void alterProductPropertySTable(String productKey, List oldFields, List newFields) { + // TODO @芋艿:需要处理 device_key,重新发布的时候 oldFields.removeIf(field -> StrUtil.equalsAny(field.getField(), TDengineTableField.FIELD_TS, "report_time")); List addFields = newFields.stream().filter( // 新增的字段 @@ -51,7 +52,7 @@ public interface IotDevicePropertyMapper { modifyTypeFields.add(newField); return; } - if (newField.getLength()!= null) { + if (newField.getLength() != null) { if (newField.getLength() > oldField.getLength()) { modifyLengthFields.add(newField); } else if (newField.getLength() < oldField.getLength()) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index fc2300b7c..b77a7e0e1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -121,9 +121,9 @@ public class IotProductServiceImpl implements IotProductService { // 1. 校验存在 validateProductExists(id); - // 2. 产品是发布状态 + // 2. 更新为发布状态,需要创建产品超级表数据模型 + // TODO @芋艿:【待定 001】1)是否需要操作后,在 redis 进行缓存,实现一个“快照”的情况,类似 tl; if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { - // 创建产品超级表数据模型 devicePropertyDataService.defineDevicePropertyData(id); } From 3ab7ad484a2be9ad9d632ea8147d2ba30814d077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 14 Feb 2025 09:34:25 +0800 Subject: [PATCH 166/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E5=A2=9E=E5=BC=BA=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E5=92=8C=E5=81=9C=E6=AD=A2=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= =?UTF-8?q?=EF=BC=8C=E6=9B=B4=E6=96=B0=E9=94=99=E8=AF=AF=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 2 ++ yudao-module-iot/yudao-module-iot-biz/pom.xml | 16 ++++----- .../plugin/IotPluginInstanceServiceImpl.java | 14 ++++++-- .../yudao-module-iot-plugin-http/pom.xml | 34 +++++++++++++++---- .../http/config/IotHttpVertxPlugin.java | 21 ++++-------- 5 files changed, 56 insertions(+), 31 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index e85d4b368..cd065aaf5 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -46,6 +46,8 @@ public interface ErrorCodeConstants { ErrorCode PLUGIN_CONFIG_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件"); ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效"); ErrorCode PLUGIN_CONFIG_KEY_DUPLICATE = new ErrorCode(1_050_006_005, "插件标识已存在"); + ErrorCode PLUGIN_START_FAILED = new ErrorCode(1_050_006_006, "插件启动失败"); + ErrorCode PLUGIN_STOP_FAILED = new ErrorCode(1_050_006_007, "插件停止失败"); // ========== 插件实例 1-050-007-000 ========== diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 6f01e3319..780817848 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -65,16 +65,16 @@ - - io.vertx - vertx-web - + + + + - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - + + + + org.pf4j diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java index 8c9973a70..3c15ff774 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java @@ -191,13 +191,23 @@ public class IotPluginInstanceServiceImpl implements IotPluginInstanceService { // 启动插件 if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) && plugin.getPluginState() != PluginState.STARTED) { - pluginManager.startPlugin(pluginKey); + try { + pluginManager.startPlugin(pluginKey); + } catch (Exception e) { + log.error("[updatePluginStatus][启动插件({}) 失败]", pluginKey, e); + throw exception(ErrorCodeConstants.PLUGIN_START_FAILED, e); + } log.info("已启动插件: {}", pluginKey); } // 停止插件 else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) && plugin.getPluginState() == PluginState.STARTED) { - pluginManager.stopPlugin(pluginKey); + try { + pluginManager.stopPlugin(pluginKey); + } catch (Exception e) { + log.error("[updatePluginStatus][停止插件({}) 失败]", pluginKey, e); + throw exception(ErrorCodeConstants.PLUGIN_STOP_FAILED, e); + } log.info("已停止插件: {}", pluginKey); } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml index 0f7e092f0..88a413ca6 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml @@ -94,6 +94,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -112,12 +140,6 @@ - - maven-deploy-plugin - - true - - diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java index fe789af52..ac9a93340 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java @@ -59,22 +59,13 @@ public class IotHttpVertxPlugin extends SpringPlugin { @Override protected ApplicationContext createApplicationContext() { - // TODO @haohao:这个加 deviceDataApi 的目的是啥呀? - AnnotationConfigApplicationContext pluginContext = new AnnotationConfigApplicationContext() { - - @Override - protected void prepareRefresh() { - // 在刷新容器前注册主程序中的 Bean - ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); - IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class); - beanFactory.registerSingleton("deviceDataApi", deviceDataApi); - super.prepareRefresh(); - } - - }; - + // 创建插件自己的 ApplicationContext + AnnotationConfigApplicationContext pluginContext = new AnnotationConfigApplicationContext(); + // 设置父容器为主应用的 ApplicationContext (确保主应用中提供的类可用) + pluginContext.setParent(SpringUtil.getApplicationContext()); + // 继续使用插件自己的 ClassLoader 以加载插件内部的类 pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); - // TODO @芋艿:枚举 + // 扫描当前插件的自动配置包 pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.http.config"); pluginContext.refresh(); return pluginContext; From 75bca650da7954bac584d46a4cac428dbfbf49ca Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 15 Feb 2025 08:29:50 +0800 Subject: [PATCH 167/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=BE=85=E5=AE=9A=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/service/device/data/IotDevicePropertyServiceImpl.java | 1 + .../upstream/router/IotDevicePropertyReportVertxHandler.java | 1 + 2 files changed, 2 insertions(+) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java index 4bd25a04d..77dde64a6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java @@ -133,6 +133,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } // 2. 根据物模型,拼接合法的属性 + // TODO @芋艿:【待定 004】赋能后,属性到底以 thingModel 为准(ik),还是 db 的表结构为准(tl)? List thingModels = thingModelService.getThingModelListByProductKeyFromCache(device.getProductKey()); Map properties = new HashMap<>(); ((Map) message.getData()).forEach((key, value) -> { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java index c22a6fe99..22fb1be82 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java @@ -20,6 +20,7 @@ import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; +// TODO @芋艿:【待定 005】要不要简化成,解析后,统一处理?只有一个 Handler!!! /** * IoT 设备属性上报的 Vert.x Handler * From add90365df8d863bbbfe5fa0323032f5b0e4aa4d Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 19 Feb 2025 15:51:34 +0800 Subject: [PATCH 168/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20RocketMQConfig=20=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=EF=BC=8C=E5=AE=9E=E7=8E=B0executeRocketMQ=20=E5=8F=91=E9=80=81?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 2 +- .../yudao-spring-boot-starter-mq/pom.xml | 1 - yudao-module-iot/yudao-module-iot-biz/pom.xml | 5 ++ .../dal/dataobject/rule/IotDataBridgeDO.java | 37 ++++++++++ .../action/IotRuleSceneDataBridgeAction.java | 73 +++++++++++++++++++ 5 files changed, 116 insertions(+), 2 deletions(-) diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 05d9aa2b9..efdeddde1 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -34,7 +34,7 @@ 5.1.0 3.3.3 - 2.3.1 + 2.3.2 2.2.7 diff --git a/yudao-framework/yudao-spring-boot-starter-mq/pom.xml b/yudao-framework/yudao-spring-boot-starter-mq/pom.xml index c8972f16b..15bbaa42d 100644 --- a/yudao-framework/yudao-spring-boot-starter-mq/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mq/pom.xml @@ -36,7 +36,6 @@ org.apache.rocketmq rocketmq-spring-boot-starter - true diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 780817848..2a9669c0e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -75,6 +75,11 @@ + + + cn.iocoder.boot + yudao-spring-boot-starter-mq + org.pf4j diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index 568377dd0..b3a863c8b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -136,5 +136,42 @@ public class IotDataBridgeDO extends BaseDO { } + /** + * RocketMQ 配置 + */ + @Data + public static class RocketMQConfig implements Config { + + /** + * RocketMQ 名称服务器地址 + */ + private String nameServer; + + /** + * 生产者/消费者组 + */ + private String group; + + /** + * 主题 + */ + private String topic; + + /** + * 标签 + */ + private String tags; + + /** + * 访问密钥 + */ + private String accessKey; + + /** + * 秘密钥匙 + */ + private String secretKey; + + } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index 82b046714..a70b6e862 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -13,11 +13,17 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; import org.springframework.http.*; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; +import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; @@ -64,6 +70,11 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { executeHttp(message, (IotDataBridgeDO.HttpConfig) dataBridge.getConfig()); return; } + // 2.2 执行 RocketMQ 发送消息 + if (IotDataBridgTypeEnum.ROCKETMQ.getType().equals(dataBridge.getType())) { + executeRocketMQ(message, (IotDataBridgeDO.RocketMQConfig) dataBridge.getConfig()); + return; + } // TODO @芋艿:因为下面的,都是有状态的,所以通过 guava 缓存连接,然后通过 RemovalNotification 实现关闭。例如说,一次新建有效期是 10 分钟; // TODO @芋艿:mq-redis @@ -131,4 +142,66 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { } } + private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { + // 1. 创建生产者实例,指定生产者组名 + DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); + try { + // 2. 设置 NameServer 地址 + producer.setNamesrvAddr(config.getNameServer()); + // 3. 启动生产者 + producer.start(); + // 4. 创建消息对象,指定Topic、Tag和消息体 + Message msg = new Message( + config.getTopic(), + config.getTags(), + message.toString().getBytes(RemotingHelper.DEFAULT_CHARSET) + ); + + // 5. 发送同步消息并处理结果 + SendResult sendResult = producer.send(msg); + // 6. 处理发送结果 + if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { + log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", + message, config, sendResult); + } else { + log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", + message, config, sendResult); + } + } catch (Exception e) { + log.error("[executeRocketMQ][message({}) config({}) 发送异常]", + message, config, e); + } finally { + // 7. 关闭生产者 + producer.shutdown(); + } + } + + public static void main(String[] args) { + // 1. 创建 IotRuleSceneDataBridgeAction 实例 + IotRuleSceneDataBridgeAction action = new IotRuleSceneDataBridgeAction(); + + // 2. 创建测试消息 + IotDeviceMessage message = IotDeviceMessage.builder() + .requestId("TEST-001") + .productKey("testProduct") + .deviceName("testDevice") + .deviceKey("testDeviceKey") + .type("property") + .identifier("temperature") + .data("{\"value\": 60}") + .reportTime(LocalDateTime.now()) + .tenantId(1L) + .build(); + + // 3. 创建 RocketMQ 配置 + IotDataBridgeDO.RocketMQConfig config = new IotDataBridgeDO.RocketMQConfig(); + config.setNameServer("127.0.0.1:9876"); + config.setGroup("test-group"); + config.setTopic("test-topic"); + config.setTags("test-tag"); + + // 4. 执行测试 + action.executeRocketMQ(message, config); + } + } From 8e7bbfe0daed7d598c62396d7db0a771bc5768b4 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 19 Feb 2025 22:42:19 +0800 Subject: [PATCH 169/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9Arocketmq=20=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=A1=A5=E6=8E=A5=E7=9A=84=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/dataobject/rule/IotDataBridgeDO.java | 30 ++++++++----------- .../action/IotRuleSceneDataBridgeAction.java | 27 ++++++++--------- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index b3a863c8b..213b0cda1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -146,32 +146,28 @@ public class IotDataBridgeDO extends BaseDO { * RocketMQ 名称服务器地址 */ private String nameServer; - - /** - * 生产者/消费者组 - */ - private String group; - - /** - * 主题 - */ - private String topic; - - /** - * 标签 - */ - private String tags; - /** * 访问密钥 */ private String accessKey; - /** * 秘密钥匙 */ private String secretKey; + /** + * 生产者组 + */ + private String group; + /** + * 主题 + */ + private String topic; + /** + * 标签 + */ + private String tags; + } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index a70b6e862..7668c05b9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -143,39 +143,38 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { } private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { - // 1. 创建生产者实例,指定生产者组名 + // 1.1 创建生产者实例,指定生产者组名 DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); + // TODO @puhui999:可以考虑,基于 guava 做 cache,使用 config 作为 key,然后假个 listener 超时,销毁 producer try { - // 2. 设置 NameServer 地址 + // 1.2 设置 NameServer 地址 producer.setNamesrvAddr(config.getNameServer()); - // 3. 启动生产者 + // 1.3 启动生产者 producer.start(); - // 4. 创建消息对象,指定Topic、Tag和消息体 + + // 2.1 创建消息对象,指定Topic、Tag和消息体 Message msg = new Message( config.getTopic(), config.getTags(), message.toString().getBytes(RemotingHelper.DEFAULT_CHARSET) ); - - // 5. 发送同步消息并处理结果 + // 2.2 发送同步消息并处理结果 SendResult sendResult = producer.send(msg); - // 6. 处理发送结果 + // 2.3 处理发送结果 if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { - log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", - message, config, sendResult); + log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", message, config, sendResult); } else { - log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", - message, config, sendResult); + log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", message, config, sendResult); } } catch (Exception e) { - log.error("[executeRocketMQ][message({}) config({}) 发送异常]", - message, config, e); + log.error("[executeRocketMQ][message({}) config({}) 发送异常]", message, config, e); } finally { - // 7. 关闭生产者 + // 3. 关闭生产者 producer.shutdown(); } } + // TODO @芋艿:测试代码,后续清理 public static void main(String[] args) { // 1. 创建 IotRuleSceneDataBridgeAction 实例 IotRuleSceneDataBridgeAction action = new IotRuleSceneDataBridgeAction(); From 54381e29a7dd634607d27bbf9ee9d601c9bc0b4d Mon Sep 17 00:00:00 2001 From: Shelly Chan <15732273052@139.com> Date: Thu, 20 Feb 2025 01:05:41 +0800 Subject: [PATCH 170/228] =?UTF-8?q?feat(iot):=20=E6=B7=BB=E5=8A=A0=20OTA?= =?UTF-8?q?=20=E5=9B=BA=E4=BB=B6=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 OTA 固件相关错误码 - 实现 OTA 固件创建、更新和查询接口 - 添加 OTA 升级记录相关功能 - 实现 OTA 固件升级任务定时处理 --- .../module/iot/enums/ErrorCodeConstants.java | 12 + .../admin/ota/IotOtaFirmwareController.java | 62 +++++ .../ota/IotOtaUpgradeRecordController.java | 76 ++++++ .../ota/IotOtaUpgradeTaskController.java | 64 +++++ .../firmware/IotOtaFirmwareCommonReqVO.java | 26 ++ .../firmware/IotOtaFirmwareCreateReqVO.java | 73 ++++++ .../vo/firmware/IotOtaFirmwarePageReqVO.java | 23 ++ .../ota/vo/firmware/IotOtaFirmwareRespVO.java | 85 +++++++ .../firmware/IotOtaFirmwareUpdateReqVO.java | 20 ++ .../record/IotOtaUpgradeRecordPageReqVO.java | 56 +++++ .../record/IotOtaUpgradeRecordRespVO.java | 109 ++++++++ .../task/IotOtaUpgradeTaskPageReqVO.java | 27 ++ .../upgrade/task/IotOtaUpgradeTaskRespVO.java | 84 +++++++ .../task/IotOtaUpgradeTaskSaveReqVO.java | 68 +++++ .../ota/IotOtaUpgradeRecordConvert.java | 34 +++ .../dataobject/ota/IotOtaUpgradeTaskDO.java | 21 +- .../iot/dal/mysql/device/IotDeviceMapper.java | 4 + .../dal/mysql/ota/IotOtaFirmwareMapper.java | 46 ++++ .../mysql/ota/IotOtaUpgradeRecordMapper.java | 133 ++++++++++ .../mysql/ota/IotOtaUpgradeTaskMapper.java | 59 +++++ .../iot/job/ota/IotOtaUpgradeRecordJob.java | 34 +++ .../iot/job/ota/IotOtaUpgradeTaskJob.java | 71 ++++++ .../iot/service/device/IotDeviceService.java | 23 +- .../service/device/IotDeviceServiceImpl.java | 12 +- .../service/ota/IotOtaFirmwareService.java | 57 +++++ .../ota/IotOtaFirmwareServiceImpl.java | 88 +++++++ .../ota/IotOtaUpgradeRecordService.java | 112 +++++++++ .../ota/IotOtaUpgradeRecordServiceImpl.java | 207 +++++++++++++++ .../service/ota/IotOtaUpgradeTaskService.java | 67 +++++ .../ota/IotOtaUpgradeTaskServiceImpl.java | 236 ++++++++++++++++++ .../iot/service/ota/bo/package-info.java | 1 + .../service/ota/bo/upgrade/package-info.java | 1 + .../IotOtaUpgradeRecordCreateReqBO.java | 79 ++++++ .../IotOtaUpgradeRecordUpdateReqBO.java | 45 ++++ .../mapper/ota/IotOtaUpgradeRecordMapper.xml | 22 ++ 35 files changed, 2128 insertions(+), 9 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordCreateReqBO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordUpdateReqBO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index e85d4b368..307730065 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -49,5 +49,17 @@ public interface ErrorCodeConstants { // ========== 插件实例 1-050-007-000 ========== + // ========== 固件相关 1-050-008-000 ========== + ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在"); + ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复"); + + ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_002, "升级任务不存在"); + ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_003, "升级任务名称重复"); + ErrorCode OTA_UPGRADE_TASK_PARAMS_INVALID = new ErrorCode(1_050_008_004, "升级任务参数无效"); + ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_005, "升级任务不能取消"); + + ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_006, "升级记录不存在"); + ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_007, "升级记录重复"); + ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_008, "升级记录不能重试"); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java new file mode 100644 index 000000000..2771e35b5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Validated +@RestController +@Tag(name = "管理后台 - IoT OTA固件") +@RequestMapping("/iot/ota-firmware") +public class IotOtaFirmwareController { + + @Resource + private IotOtaFirmwareService otaFirmwareService; + + @PostMapping("/create") + @Operation(summary = "创建OTA固件") + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:create')") + public CommonResult createOtaFirmware(@Valid @RequestBody IotOtaFirmwareCreateReqVO createReqVO) { + return success(otaFirmwareService.createOtaFirmware(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新OTA固件") + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:update')") + public CommonResult updateOtaFirmware(@Valid @RequestBody IotOtaFirmwareUpdateReqVO updateReqVO) { + otaFirmwareService.updateOtaFirmware(updateReqVO); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得OTA固件") + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')") + public CommonResult getOtaFirmware(@RequestParam("id") Long id) { + IotOtaFirmwareDO otaFirmware = otaFirmwareService.getOtaFirmware(id); + return success(BeanUtils.toBean(otaFirmware, IotOtaFirmwareRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得OTA固件分页") + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')") + public CommonResult> getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO) { + PageResult pageResult = otaFirmwareService.getOtaFirmwarePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotOtaFirmwareRespVO.class)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java new file mode 100644 index 000000000..e28f721c8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordRespVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Validated +@RestController +@Tag(name = "管理后台 - OTA升级记录") +@RequestMapping("/iot/ota-upgrade-record") +public class IotOtaUpgradeRecordController { + + @Resource + private IotOtaUpgradeRecordService upgradeRecordService; + + @GetMapping("/get-count") + @Operation(summary = "获得升级记录 分页 tab count") + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") + public CommonResult> getOtaUpgradeRecordCount( + @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) { + return success(upgradeRecordService.getOtaUpgradeRecordCount(pageReqVO)); + } + + @GetMapping("/get-statistics") + @Operation(summary = "固件升级设备统计") + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") + @Parameter(name = "firmwareId", description = "固件编号", required = true, example = "1024") + public CommonResult> getOtaUpgradeRecordStatistics( + @RequestParam(value = "firmwareId") Long firmwareId) { + return success(upgradeRecordService.getOtaUpgradeRecordStatistics(firmwareId)); + } + + @GetMapping("/page") + @Operation(summary = "获得升级记录分页") + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") + public CommonResult> getUpgradeRecordPage( + @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) { + PageResult pageResult = upgradeRecordService.getUpgradeRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotOtaUpgradeRecordRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得升级记录") + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") + @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024") + public CommonResult getUpgradeRecord(@RequestParam("id") Long id) { + IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordService.getUpgradeRecord(id); + return success(BeanUtils.toBean(upgradeRecord, IotOtaUpgradeRecordRespVO.class)); + } + + @PostMapping("/retry") + @Operation(summary = "重试升级记录") + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:retry')") + @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024") + public CommonResult retryUpgradeRecord(@RequestParam("id") Long id) { + upgradeRecordService.retryUpgradeRecord(id); + return success(true); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java new file mode 100644 index 000000000..20216fecc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeTaskService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Validated +@RestController +@Tag(name = "管理后台 - OTA升级任务") +@RequestMapping("/iot/ota-upgrade-task") +public class IotOtaUpgradeTaskController { + + @Resource + private IotOtaUpgradeTaskService upgradeTaskService; + + @PostMapping("/create") + @Operation(summary = "创建升级任务") + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:create')") + public CommonResult createUpgradeTask(@Valid @RequestBody IotOtaUpgradeTaskSaveReqVO createReqVO) { + return success(upgradeTaskService.createUpgradeTask(createReqVO)); + } + + @PostMapping("/cancel") + @Operation(summary = "取消升级任务") + @Parameter(name = "id", description = "升级任务编号", required = true) + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:cancel')") + public CommonResult cancelUpgradeTask(@RequestParam("id") Long id) { + upgradeTaskService.cancelUpgradeTask(id); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获得升级任务分页") + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')") + public CommonResult> getUpgradeTaskPage(@Valid @RequestBody IotOtaUpgradeTaskPageReqVO pageReqVO) { + PageResult pageResult = upgradeTaskService.getUpgradeTaskPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotOtaUpgradeTaskRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得升级任务") + @Parameter(name = "id", description = "升级任务编号", required = true, example = "1024") + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')") + public CommonResult getUpgradeTask(@RequestParam("id") Long id) { + IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(id); + return success(BeanUtils.toBean(upgradeTask, IotOtaUpgradeTaskRespVO.class)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java new file mode 100644 index 000000000..01f10caa5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "管理后台 - OTA固件信息 Request VO") +public class IotOtaFirmwareCommonReqVO { + + /** + * 固件名称 + */ + @NotEmpty(message = "固件名称不能为空") + @Schema(description = "固件名称", requiredMode = REQUIRED, example = "智能开关固件") + private String name; + + /** + * 固件描述 + */ + @Schema(description = "固件描述", example = "某品牌型号固件,测试用") + private String description; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java new file mode 100644 index 000000000..44d942c63 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "管理后台 - OTA固件创建 Request VO") +public class IotOtaFirmwareCreateReqVO extends IotOtaFirmwareCommonReqVO { + + /** + * 版本号 + */ + @NotEmpty(message = "版本号不能为空") + @Schema(description = "版本号", requiredMode = REQUIRED, example = "1.0.0") + private String version; + + /** + * 产品编号 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} + */ + @NotNull(message = "产品编号不能为空") + @Schema(description = "产品编号", requiredMode = REQUIRED, example = "1024") + private String productId; + + /** + * 产品标识 + *

+ * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()} + */ + @NotEmpty(message = "产品标识不能为空") + @Schema(description = "产品标识", requiredMode = REQUIRED, example = "yudao") + private String productKey; + + /** + * 签名方式 + *

+ * 例如说:MD5、SHA256 + */ + @Schema(description = "签名方式", example = "MD5") + private String signMethod; + + /** + * 固件文件签名 + */ + @Schema(description = "固件文件签名", example = "d41d8cd98f00b204e9800998ecf8427e") + private String fileSign; + + /** + * 固件文件大小 + */ + @NotNull(message = "固件文件大小不能为空") + @Schema(description = "固件文件大小(单位:byte)", example = "1024") + private Long fileSize; + + /** + * 固件文件 URL + */ + @NotEmpty(message = "固件文件 URL 不能为空") + @Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn/yudao-firmware.zip") + private String fileUrl; + + /** + * 自定义信息,建议使用 JSON 格式 + */ + @Schema(description = "自定义信息,建议使用 JSON 格式", example = "{\"key1\":\"value1\",\"key2\":\"value2\"}") + private String information; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java new file mode 100644 index 000000000..8ae3e5199 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "管理后台 - OTA固件分页 Request VO") +public class IotOtaFirmwarePageReqVO extends PageParam { + + /** + * 固件名称 + */ + @Schema(description = "固件名称", example = "智能开关固件") + private String name; + + /** + * 产品标识 + */ + @Schema(description = "产品标识", example = "1024") + private String productId; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java new file mode 100644 index 000000000..767ba7713 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; + +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import com.fhs.core.trans.vo.VO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "管理后台 - OTA固件 Response VO") +public class IotOtaFirmwareRespVO implements VO { + + /** + * 固件编号 + */ + @Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024") + private Long id; + /** + * 固件名称 + */ + @Schema(description = "固件名称", requiredMode = REQUIRED, example = "OTA固件") + private String name; + /** + * 固件描述 + */ + @Schema(description = "固件描述") + private String description; + /** + * 版本号 + */ + @Schema(description = "版本号", requiredMode = REQUIRED, example = "1.0.0") + private String version; + + /** + * 产品编号 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} + */ + @Schema(description = "产品编号", requiredMode = REQUIRED, example = "1024") + @Trans(type = TransType.SIMPLE, target = IotProductDO.class, fields = {"name"}, refs = {"productName"}) + private String productId; + /** + * 产品标识 + *

+ * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()} + */ + @Schema(description = "产品标识", requiredMode = REQUIRED, example = "iot-product-key") + private String productKey; + /** + * 产品名称 + */ + @Schema(description = "产品名称", requiredMode = REQUIRED, example = "OTA产品") + private String productName; + /** + * 签名方式 + *

+ * 例如说:MD5、SHA256 + */ + @Schema(description = "签名方式", example = "MD5") + private String signMethod; + /** + * 固件文件签名 + */ + @Schema(description = "固件文件签名", example = "1024") + private String fileSign; + /** + * 固件文件大小 + */ + @Schema(description = "固件文件大小", requiredMode = REQUIRED, example = "1024") + private Long fileSize; + /** + * 固件文件 URL + */ + @Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn") + private String fileUrl; + /** + * 自定义信息,建议使用 JSON 格式 + */ + @Schema(description = "自定义信息,建议使用 JSON 格式") + private String information; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java new file mode 100644 index 000000000..eacbfd2dd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "管理后台 - OTA固件更新 Request VO") +public class IotOtaFirmwareUpdateReqVO extends IotOtaFirmwareCommonReqVO { + + /** + * 固件编号 + */ + @NotNull(message = "固件编号不能为空") + @Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024") + private Long id; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java new file mode 100644 index 000000000..c7c55e4ca --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "管理后台 - OTA升级记录分页 Request VO") +public class IotOtaUpgradeRecordPageReqVO extends PageParam { + + /** + * 待处理状态 + */ + public static final Integer PENDING = 0; + /** + * 已推送状态 + */ + public static final Integer PUSHED = 10; + /** + * 正在升级状态 + */ + public static final Integer UPGRADING = 20; + /** + * 升级成功状态 + */ + public static final Integer SUCCESS = 30; + /** + * 升级失败状态 + */ + public static final Integer FAILURE = 40; + /** + * 升级已取消状态 + */ + public static final Integer CANCELED = 50; + + /** + * 升级任务编号字段。 + *

+ * 该字段用于标识升级任务的唯一编号,不能为空。 + */ + @NotNull(message = "升级任务编号不能为空") + @Schema(description = "升级任务编号", requiredMode = REQUIRED, example = "1024") + private Long taskId; + + /** + * 设备标识字段。 + *

+ * 该字段用于标识设备的名称,通常用于区分不同的设备。 + */ + @Schema(description = "设备标识", requiredMode = REQUIRED, example = "摄像头A1-1") + private String deviceName; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java new file mode 100644 index 000000000..d717cfd31 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record; + +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import com.fhs.core.trans.anno.Trans; +import com.fhs.core.trans.constant.TransType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "管理后台 - OTA升级记录 Response VO") +public class IotOtaUpgradeRecordRespVO { + + /** + * 升级记录编号 + */ + @Schema(description = "升级记录编号", requiredMode = REQUIRED, example = "1024") + private Long id; + /** + * 固件编号 + *

+ * 关联 {@link IotOtaFirmwareDO#getId()} + */ + @Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024") + @Trans(type = TransType.SIMPLE, target = IotOtaFirmwareDO.class, fields = {"version"}, refs = {"firmwareVersion"}) + private Long firmwareId; + /** + * 固件版本 + */ + @Schema(description = "固件版本", requiredMode = REQUIRED, example = "v1.0.0") + private String firmwareVersion; + /** + * 任务编号 + *

+ * 关联 {@link IotOtaUpgradeTaskDO#getId()} + */ + @Schema(description = "任务编号", requiredMode = REQUIRED, example = "1024") + private Long taskId; + /** + * 产品标识 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} + */ + @Schema(description = "产品标识", requiredMode = REQUIRED, example = "iot") + private String productKey; + /** + * 设备名称 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} + */ + @Schema(description = "设备名称", requiredMode = REQUIRED, example = "iot") + private String deviceName; + /** + * 设备编号 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} + */ + @Schema(description = "设备编号", requiredMode = REQUIRED, example = "1024") + private String deviceId; + /** + * 来源的固件编号 + *

+ * 关联 {@link IotDeviceDO#getFirmwareId()} + */ + @Schema(description = "来源的固件编号", requiredMode = REQUIRED, example = "1024") + @Trans(type = TransType.SIMPLE, target = IotOtaFirmwareDO.class, fields = {"version"}, refs = {"fromFirmwareVersion"}) + private Long fromFirmwareId; + /** + * 来源的固件版本 + */ + @Schema(description = "来源的固件版本", requiredMode = REQUIRED, example = "v1.0.0") + private String fromFirmwareVersion; + /** + * 升级状态 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum} + */ + @Schema(description = "升级状态", requiredMode = REQUIRED, allowableValues = {"0", "10", "20", "30", "40", "50"}) + private Integer status; + /** + * 升级进度,百分比 + */ + @Schema(description = "升级进度,百分比", requiredMode = REQUIRED, example = "10") + private Integer progress; + /** + * 升级进度描述 + *

+ * 注意,只记录设备最后一次的升级进度描述 + * 如果想看历史记录,可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志 + */ + @Schema(description = "升级进度描述", requiredMode = REQUIRED, example = "10") + private String description; + /** + * 升级开始时间 + */ + @Schema(description = "升级开始时间", requiredMode = REQUIRED, example = "2022-07-08 07:30:00") + private LocalDateTime startTime; + /** + * 升级结束时间 + */ + @Schema(description = "升级结束时间", requiredMode = REQUIRED, example = "2022-07-08 07:30:00") + private LocalDateTime endTime; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java new file mode 100644 index 000000000..c1f2816c0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "管理后台 - OTA升级任务分页 Request VO") +public class IotOtaUpgradeTaskPageReqVO extends PageParam { + + /** + * 任务名称字段,用于描述任务的名称 + */ + @Schema(description = "任务名称", example = "升级任务") + private String name; + + /** + * 固件编号字段,用于唯一标识固件,不能为空 + */ + @NotNull(message = "固件编号不能为空") + @Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024") + private Long firmwareId; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java new file mode 100644 index 000000000..f8f5320c9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task; + +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import com.fhs.core.trans.vo.VO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "管理后台 - OTA升级任务 Response VO") +public class IotOtaUpgradeTaskRespVO implements VO { + + /** + * 任务编号 + */ + @Schema(description = "任务编号", requiredMode = REQUIRED, example = "1024") + private Long id; + /** + * 任务名称 + */ + @Schema(description = "任务名称", requiredMode = REQUIRED, example = "升级任务") + private String name; + /** + * 任务描述 + */ + @Schema(description = "任务描述", example = "升级任务") + private String description; + /** + * 固件编号 + *

+ * 关联 {@link IotOtaFirmwareDO#getId()} + */ + @Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024") + private Long firmwareId; + /** + * 任务状态 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum} + */ + @Schema(description = "任务状态", requiredMode = REQUIRED, allowableValues = {"10", "20", "21", "30"}) + private Integer status; + /** + * 任务状态名称 + */ + @Schema(description = "任务状态名称", requiredMode = REQUIRED, example = "进行中") + private String statusName; + /** + * 升级范围 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum} + */ + @Schema(description = "升级范围", requiredMode = REQUIRED, allowableValues = {"1", "2"}) + private Integer scope; + /** + * 设备数量 + */ + @Schema(description = "设备数量", requiredMode = REQUIRED, example = "1024") + private Long deviceCount; + /** + * 选中的设备编号数组 + *

+ * 关联 {@link IotDeviceDO#getId()} + */ + @Schema(description = "选中的设备编号数组", example = "1024") + private List deviceIds; + /** + * 选中的设备名字数组 + *

+ * 关联 {@link IotDeviceDO#getDeviceName()} + */ + @Schema(description = "选中的设备名字数组", example = "1024") + private List deviceNames; + /** + * 创建时间 + */ + @Schema(description = "创建时间", requiredMode = REQUIRED, example = "2022-07-08 07:30:00") + private LocalDateTime createTime; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java new file mode 100644 index 000000000..c7da7565f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Data +@Schema(description = "管理后台 - OTA升级任务创建/修改 Request VO") +public class IotOtaUpgradeTaskSaveReqVO { + + /** + * 任务名称 + */ + @NotEmpty(message = "任务名称不能为空") + @Schema(description = "任务名称", requiredMode = REQUIRED, example = "升级任务") + private String name; + + /** + * 任务描述 + */ + @Schema(description = "任务描述", example = "升级任务") + private String description; + + /** + * 固件编号 + *

+ * 关联 {@link IotOtaFirmwareDO#getId()} + */ + @NotNull(message = "固件编号不能为空") + @Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024") + private Long firmwareId; + + /** + * 升级范围 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum} + */ + @NotNull(message = "升级范围不能为空") + @InEnum(value = IotOtaUpgradeTaskScopeEnum.class) + @Schema(description = "升级范围", requiredMode = REQUIRED, example = "1") + private Integer scope; + + /** + * 选中的设备编号数组 + *

+ * 关联 {@link IotDeviceDO#getId()} + */ + @Schema(description = "选中的设备编号数组", requiredMode = REQUIRED, example = "[1,2,3,4]") + private List deviceIds; + + /** + * 选中的设备名字数组 + *

+ * 关联 {@link IotDeviceDO#getDeviceName()} + */ + @Schema(description = "选中的设备名字数组", requiredMode = REQUIRED, example = "[设备1,设备2,设备3,设备4]") + private List deviceNames; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java new file mode 100644 index 000000000..66ff07e3a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.convert.ota; + +import cn.hutool.core.convert.Convert; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; +import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordCreateReqBO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface IotOtaUpgradeRecordConvert { + + IotOtaUpgradeRecordConvert INSTANCE = Mappers.getMapper(IotOtaUpgradeRecordConvert.class); + + default List convertBOList(IotOtaUpgradeTaskDO upgradeTask, IotOtaFirmwareDO firmware, List deviceList) { + return deviceList.stream().map(device -> { + IotOtaUpgradeRecordCreateReqBO createReqBO = new IotOtaUpgradeRecordCreateReqBO(); + createReqBO.setFirmwareId(firmware.getId()); + createReqBO.setTaskId(upgradeTask.getId()); + createReqBO.setProductKey(device.getProductKey()); + createReqBO.setDeviceName(device.getDeviceName()); + createReqBO.setDeviceId(Convert.toStr(device.getId())); + createReqBO.setFromFirmwareId(Convert.toLong(device.getFirmwareId())); + createReqBO.setStatus(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); + createReqBO.setProgress(0); + return createReqBO; + }).toList(); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java index 7d9e4425d..1f300cfcc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java @@ -41,30 +41,41 @@ public class IotOtaUpgradeTaskDO extends BaseDO { /** * 固件编号 - * + *

* 关联 {@link IotOtaFirmwareDO#getId()} */ private Long firmwareId; /** * 任务状态 - * + *

* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum} */ private Integer status; /** * 升级范围 - * + *

* 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum} */ private Integer scope; + /** + * 设备数量 + */ + private Long deviceCount; + /** + * 选中的设备编号数组 + *

+ * 关联 {@link IotDeviceDO#getId()} + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List deviceIds; /** * 选中的设备名字数组 - * + *

* 关联 {@link IotDeviceDO#getDeviceName()} */ @TableField(typeHandler = JacksonTypeHandler.class) private List deviceNames; -} \ No newline at end of file +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index a3ae4e380..e56efb879 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -60,6 +60,10 @@ public interface IotDeviceMapper extends BaseMapperX { return selectList(IotDeviceDO::getState, state); } + default List selectListByProductId(Long productId) { + return selectList(IotDeviceDO::getProductId, productId); + } + default Long selectCountByGroupId(Long groupId) { return selectCount(new LambdaQueryWrapperX() .apply("FIND_IN_SET(" + groupId + ",group_ids) > 0") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java new file mode 100644 index 000000000..36e7c61cd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * IotOtaFirmwareMapper 接口用于操作 IotOtaFirmwareDO 实体类对应的数据库表。 + * 该接口继承自 BaseMapperX,提供了基本的 CRUD 操作,并扩展了特定查询方法。 + */ +@Mapper +public interface IotOtaFirmwareMapper extends BaseMapperX { + + /** + * 根据产品ID和固件版本号查询固件信息列表。 + * + * @param productId 产品ID,用于筛选固件信息。 + * @param version 固件版本号,用于筛选固件信息。 + * @return 返回符合条件的固件信息列表。 + */ + default List selectByProductIdAndVersion(String productId, String version) { + return selectList(new LambdaQueryWrapperX() + .eq(IotOtaFirmwareDO::getProductId, productId) + .eq(IotOtaFirmwareDO::getVersion, version)); + } + + /** + * 分页查询固件信息,支持根据名称和产品ID进行筛选,并按创建时间降序排列。 + * + * @param pageReqVO 分页查询请求对象,包含分页参数和筛选条件。 + * @return 返回分页查询结果,包含符合条件的固件信息列表。 + */ + default PageResult selectPage(IotOtaFirmwarePageReqVO pageReqVO) { + return selectPage(pageReqVO, + new LambdaQueryWrapperX() + .likeIfPresent(IotOtaFirmwareDO::getName, pageReqVO.getName()) + .eqIfPresent(IotOtaFirmwareDO::getProductId, pageReqVO.getProductId()) + .orderByDesc(IotOtaFirmwareDO::getCreateTime)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java new file mode 100644 index 000000000..4f990fc21 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -0,0 +1,133 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * OTA升级记录 Mapper 接口 + */ +@Mapper +public interface IotOtaUpgradeRecordMapper extends BaseMapperX { + + /** + * 根据条件查询单个OTA升级记录 + * + * @param firmwareId 固件ID,可选参数,用于筛选固件ID匹配的记录 + * @param taskId 任务ID,可选参数,用于筛选任务ID匹配的记录 + * @param deviceId 设备ID,可选参数,用于筛选设备ID匹配的记录 + * @return 返回符合条件的单个OTA升级记录,如果不存在则返回null + */ + default IotOtaUpgradeRecordDO selectByConditions(Long firmwareId, Long taskId, String deviceId) { + // 使用LambdaQueryWrapperX构建查询条件,根据传入的参数动态添加查询条件 + return selectOne(new LambdaQueryWrapperX() + .eqIfPresent(IotOtaUpgradeRecordDO::getFirmwareId, firmwareId) + .eqIfPresent(IotOtaUpgradeRecordDO::getTaskId, taskId) + .eqIfPresent(IotOtaUpgradeRecordDO::getDeviceId, deviceId)); + } + + /** + * 获取OTA升级记录的数量 + * + * @param taskId 任务ID,用于筛选特定任务的升级记录 + * @param deviceName 设备名称,用于筛选特定设备的升级记录 + * @param status 状态,用于筛选特定状态的升级记录 + * @return 返回符合条件的OTA升级记录的数量 + */ + Long getOtaUpgradeRecordCount(@Param("taskId") Long taskId, + @Param("deviceName") String deviceName, + @Param("status") Integer status); + + /** + * 获取OTA升级记录的统计信息 + * + * @param firmwareId 固件ID,用于筛选特定固件的升级记录 + * @param status 状态,用于筛选特定状态的升级记录 + * @return 返回符合条件的OTA升级记录的统计信息 + */ + Long getOtaUpgradeRecordStatistics(@Param("firmwareId") Long firmwareId, + @Param("status") Integer status); + + + /** + * 根据分页查询条件获取IOT OTA升级记录的分页结果 + * + * @param pageReqVO 分页查询请求参数,包含设备名称、任务ID等查询条件 + * @return 返回分页查询结果,包含符合条件的IOT OTA升级记录列表 + */ + default PageResult selectUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { + // 使用LambdaQueryWrapperX构建查询条件,并根据请求参数动态添加查询条件 + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotOtaUpgradeRecordDO::getDeviceName, pageReqVO.getDeviceName()) // 如果设备名称存在,则添加模糊查询条件 + .eqIfPresent(IotOtaUpgradeRecordDO::getTaskId, pageReqVO.getTaskId())); // 如果任务ID存在,则添加等值查询条件 + } + + /** + * 根据任务ID取消升级记录。 + * 该方法通过任务ID查找状态为“待处理”的升级记录,并将其状态更新为“已取消”。 + * + * @param taskId 任务ID,用于查找对应的升级记录。 + */ + default void cancelUpgradeRecordByTaskId(Long taskId) { + // 使用LambdaUpdateWrapper构建更新条件,将状态为“待处理”的记录更新为“已取消” + update(new LambdaUpdateWrapper() + .set(IotOtaUpgradeRecordDO::getStatus, IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()) + .eq(IotOtaUpgradeRecordDO::getTaskId, taskId) + .eq(IotOtaUpgradeRecordDO::getStatus, IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()) + ); + } + + /** + * 根据状态查询符合条件的升级记录列表 + *

+ * 该函数使用LambdaQueryWrapperX构建查询条件,查询指定状态的升级记录。 + * + * @param state 升级记录的状态,用于筛选符合条件的记录 + * @return 返回符合指定状态的升级记录列表,类型为List + */ + default List selectUpgradeRecordListByState(Integer state) { + // 使用LambdaQueryWrapperX构建查询条件,根据状态查询符合条件的升级记录 + return selectList(new LambdaQueryWrapperX() + .eq(IotOtaUpgradeRecordDO::getStatus, state)); + } + + /** + * 更新升级记录状态 + *

+ * 该函数用于批量更新指定ID列表中的升级记录状态。通过传入的ID列表和状态值,使用LambdaUpdateWrapper构建更新条件, + * 并执行更新操作。 + * + * @param ids 需要更新的升级记录ID列表,类型为List。传入的ID列表中的记录将被更新。 + * @param status 要更新的状态值,类型为Integer。该值将被设置到符合条件的升级记录中。 + */ + default void updateUpgradeRecordStatus(List ids, Integer status) { + // 使用LambdaUpdateWrapper构建更新条件,设置状态字段,并根据ID列表进行筛选 + update(new LambdaUpdateWrapper() + .set(IotOtaUpgradeRecordDO::getStatus, status) + .in(IotOtaUpgradeRecordDO::getId, ids) + ); + } + + /** + * 根据任务ID查询升级记录列表 + *

+ * 该函数通过任务ID查询符合条件的升级记录,并返回查询结果列表。 + * + * @param taskId 任务ID,用于筛选升级记录 + * @return 返回符合条件的升级记录列表,若未找到则返回空列表 + */ + default List selectUpgradeRecordListByTaskId(Long taskId) { + // 使用LambdaQueryWrapperX构建查询条件,根据任务ID查询符合条件的升级记录 + return selectList(new LambdaQueryWrapperX() + .eq(IotOtaUpgradeRecordDO::getTaskId, taskId)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java new file mode 100644 index 000000000..9cee6e19a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * IotOtaUpgradeTaskMapper 接口用于操作 IotOtaUpgradeTaskDO 数据库表。 + * 该接口继承自 BaseMapperX,提供了基本的数据库操作方法。 + */ +@Mapper +public interface IotOtaUpgradeTaskMapper extends BaseMapperX { + + /** + * 根据固件ID和任务名称查询升级任务列表。 + * + * @param firmwareId 固件ID,用于筛选升级任务 + * @param name 任务名称,用于筛选升级任务 + * @return 符合条件的升级任务列表 + */ + default List selectByFirmwareIdAndName(Long firmwareId, String name) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(IotOtaUpgradeTaskDO::getFirmwareId, firmwareId) + .eqIfPresent(IotOtaUpgradeTaskDO::getName, name)); + } + + /** + * 分页查询升级任务列表,支持根据固件ID和任务名称进行筛选。 + * + * @param pageReqVO 分页查询请求对象,包含分页参数和筛选条件 + * @return 分页结果,包含符合条件的升级任务列表 + */ + default PageResult selectUpgradeTaskPage(IotOtaUpgradeTaskPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotOtaUpgradeTaskDO::getFirmwareId, pageReqVO.getFirmwareId()) + .likeIfPresent(IotOtaUpgradeTaskDO::getName, pageReqVO.getName())); + } + + /** + * 根据任务状态查询升级任务列表 + *

+ * 该函数通过传入的任务状态,查询数据库中符合条件的升级任务列表。 + * + * @param state 任务状态,用于筛选升级任务的状态值 + * @return 返回符合条件的升级任务列表,列表中的每个元素为 IotOtaUpgradeTaskDO 对象 + */ + default List selectUpgradeTaskByState(Integer state) { + // 使用 LambdaQueryWrapperX 构建查询条件,筛选出状态等于指定值的升级任务 + return selectList(new LambdaQueryWrapperX() + .eq(IotOtaUpgradeTaskDO::getStatus, state)); + } + + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java new file mode 100644 index 000000000..d04818d5c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.job.ota; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; +import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class IotOtaUpgradeRecordJob implements JobHandler { + + @Resource + private IotOtaUpgradeRecordService upgradeRecordService; + + @Override + @TenantJob + public String execute(String param) throws Exception { + // 1.查询待处理的升级记录 + List upgradeRecords = upgradeRecordService + .getUpgradeRecordListByState(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); + + // TODO @芋艿 2.执行升级动作 + + // 3.最终,更新升级记录状态 + List ids = upgradeRecords.stream().map(IotOtaUpgradeRecordDO::getId).toList(); + upgradeRecordService.updateUpgradeRecordStatus(ids, IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus()); + return ""; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java new file mode 100644 index 000000000..8b809c674 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.job.ota; + +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum; +import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService; +import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeTaskService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +public class IotOtaUpgradeTaskJob implements JobHandler { + + @Resource + private IotOtaUpgradeTaskService upgradeTaskService; + @Resource + private IotOtaUpgradeRecordService upgradeRecordService; + + @Override + @TenantJob + public String execute(String param) throws Exception { + // 1.这个任务主要是为了检查并更新升级任务的状态 + List upgradeTasks = upgradeTaskService + .getUpgradeTaskByState(IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus()); + // 2.遍历并且确定升级任务的状态 + upgradeTasks.forEach(this::checkUpgradeTaskState); + // TODO @芋艿: 其他的一些业务逻辑 + return ""; + } + + private void checkUpgradeTaskState(IotOtaUpgradeTaskDO upgradeTask) { + // 1.查询任务所有的升级记录 + List upgradeRecords = + upgradeRecordService.getUpgradeRecordListByTaskId(upgradeTask.getId()); + if (upgradeRecords.stream().anyMatch(upgradeRecord -> + ObjectUtils.equalsAny(upgradeRecord.getStatus(), + IotOtaUpgradeRecordStatusEnum.PENDING.getStatus(), + IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus(), + IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus()))) { + // 如果存在正在升级的升级记录,则升级任务的状态为进行中 + log.debug("升级任务 {} 状态为进行中", upgradeTask.getId()); + } else if (upgradeRecords.stream().allMatch(upgradeRecord -> + ObjectUtils.equalsAny(upgradeRecord.getStatus(), + IotOtaUpgradeRecordStatusEnum.SUCCESS.getStatus()))) { + // 如果全部升级成功,则升级任务的状态为已完成 + upgradeTaskService.updateUpgradeTaskStatus(upgradeTask.getId(), + IotOtaUpgradeTaskStatusEnum.COMPLETED.getStatus()); + } else if (upgradeRecords.stream().noneMatch(upgradeRecord -> + ObjectUtils.equalsAny(upgradeRecord.getStatus(), + IotOtaUpgradeRecordStatusEnum.PENDING.getStatus(), + IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus(), + IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus())) && + upgradeRecords.stream().anyMatch(upgradeRecord -> + ObjectUtils.equalsAny(upgradeRecord.getStatus(), + IotOtaUpgradeRecordStatusEnum.FAILURE.getStatus(), + IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()))) { + // 如果全部升级完毕,但是存在升级失败或者取消的升级记录,则升级任务的状态为失败 + upgradeTaskService.updateUpgradeTaskStatus(upgradeTask.getId(), + IotOtaUpgradeTaskStatusEnum.INCOMPLETE.getStatus()); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 24532d254..cd920d1bf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -34,8 +34,8 @@ public interface IotDeviceService { * @return 设备 */ IotDeviceDO createDevice(@NotEmpty(message = "产品标识不能为空") String productKey, - @NotEmpty(message = "设备名称不能为空") String deviceName, - Long gatewayId); + @NotEmpty(message = "设备名称不能为空") String deviceName, + Long gatewayId); /** * 更新设备 @@ -45,6 +45,7 @@ public interface IotDeviceService { void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO); // TODO @芋艿:先这么实现。未来看情况,要不要自己实现 + /** * 更新设备的所属网关 * @@ -132,6 +133,22 @@ public interface IotDeviceService { */ List getDeviceListByState(Integer state); + /** + * 根据产品ID获取设备列表 + * + * @param productId 产品ID,用于查询特定产品的设备列表 + * @return 返回与指定产品ID关联的设备列表,列表中的每个元素为IotDeviceDO对象 + */ + List getDeviceListByProductId(Long productId); + + /** + * 根据设备ID列表获取设备信息列表 + * + * @param deviceIdList 设备ID列表,包含需要查询的设备ID + * @return 返回与设备ID列表对应的设备信息列表,列表中的每个元素为IotDeviceDO对象 + */ + List getDeviceListByIdList(List deviceIdList); + /** * 基于产品编号,获得设备数量 * @@ -150,7 +167,7 @@ public interface IotDeviceService { /** * 【缓存】根据产品 key 和设备名称,获得设备信息 - * + *

* 注意:该方法会忽略租户信息,所以调用时,需要确认会不会有跨租户访问的风险!!! * * @param productKey 产品 key diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 66854e84b..76d16c538 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -99,7 +99,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { } private void validateCreateDeviceParam(String productKey, String deviceName, String deviceKey, - Long gatewayId, IotProductDO product) { + Long gatewayId, IotProductDO product) { TenantUtils.executeIgnore(() -> { // 校验设备名称在同一产品下是否唯一 if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) { @@ -261,6 +261,16 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectListByState(state); } + @Override + public List getDeviceListByProductId(Long productId) { + return deviceMapper.selectListByProductId(productId); + } + + @Override + public List getDeviceListByIdList(List deviceIdList) { + return deviceMapper.selectByIds(deviceIdList); + } + @Override public void updateDeviceState(Long id, Integer state) { // 1. 校验存在 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java new file mode 100644 index 000000000..659b3039f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.iot.service.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import jakarta.validation.Valid; + +/** + * OTA固件管理服务接口 + * 提供OTA固件的创建、更新和查询等功能 + */ +public interface IotOtaFirmwareService { + + /** + * 创建OTA固件 + * + * @param saveReqVO OTA固件保存请求对象,包含固件的相关信息 + * @return 返回新创建的固件的ID + */ + Long createOtaFirmware(@Valid IotOtaFirmwareCreateReqVO saveReqVO); + + /** + * 更新OTA固件信息 + * + * @param updateReqVO OTA固件保存请求对象,包含需要更新的固件信息 + */ + void updateOtaFirmware(@Valid IotOtaFirmwareUpdateReqVO updateReqVO); + + /** + * 根据ID获取OTA固件信息 + * + * @param id OTA固件的唯一标识符 + * @return 返回OTA固件的详细信息对象 + */ + IotOtaFirmwareDO getOtaFirmware(Long id); + + /** + * 分页查询OTA固件信息 + * + * @param pageReqVO 包含分页查询条件的请求对象 + * @return 返回分页查询结果,包含固件信息列表和分页信息 + */ + PageResult getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO); + + /** + * 验证物联网OTA固件是否存在 + * + * @param id 固件的唯一标识符 + * 该方法用于检查系统中是否存在与给定ID关联的物联网OTA固件信息 + * 主要目的是在进行固件更新操作前,确保目标固件已经存在并可以被访问 + * 如果固件不存在,该方法可能抛出异常或返回错误信息,具体行为未定义 + */ + IotOtaFirmwareDO validateFirmwareExists(Long id); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java new file mode 100644 index 000000000..76930e1dc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.iot.service.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaFirmwareMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_NOT_EXISTS; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE; + +@Slf4j +@Service +@Validated +public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { + + @Resource + private IotOtaFirmwareMapper otaFirmwareMapper; + + @Override + public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) { + // 1.校验固件产品id+版本号不能重复 + validateProductAndVersionDuplicate(saveReqVO.getProductId(), saveReqVO.getVersion()); + // 2.转化数据格式,准备存储到数据库中 + IotOtaFirmwareDO otaFirmware = BeanUtils.toBean(saveReqVO, IotOtaFirmwareDO.class); + otaFirmwareMapper.insert(otaFirmware); + return otaFirmware.getId(); + } + + @Override + public void updateOtaFirmware(IotOtaFirmwareUpdateReqVO updateReqVO) { + // 1.1. 校验存在 + validateFirmwareExists(updateReqVO.getId()); + // 2. 更新数据 + IotOtaFirmwareDO updateObj = BeanUtils.toBean(updateReqVO, IotOtaFirmwareDO.class); + otaFirmwareMapper.updateById(updateObj); + } + + @Override + public IotOtaFirmwareDO getOtaFirmware(Long id) { + return otaFirmwareMapper.selectById(id); + } + + @Override + public PageResult getOtaFirmwarePage(IotOtaFirmwarePageReqVO pageReqVO) { + return otaFirmwareMapper.selectPage(pageReqVO); + } + + @Override + public IotOtaFirmwareDO validateFirmwareExists(Long id) { + IotOtaFirmwareDO otaFirmware = otaFirmwareMapper.selectById(id); + if (otaFirmware == null) { + throw exception(OTA_FIRMWARE_NOT_EXISTS); + } + return otaFirmware; + } + + /** + * 验证产品和版本号是否重复 + *

+ * 该方法用于确保在系统中不存在具有相同产品ID和版本号的固件条目 + * 它通过调用otaFirmwareMapper的selectByProductIdAndVersion方法来查询数据库中是否存在匹配的产品ID和版本号的固件信息 + * 如果查询结果非空且不为null,则抛出异常,提示固件信息已存在,从而避免数据重复 + * + * @param productId 产品ID,用于数据库查询 + * @param version 版本号,用于数据库查询 + * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出异常,提示固件信息已存在 + */ + private void validateProductAndVersionDuplicate(String productId, String version) { + // 查询数据库中是否存在具有相同产品ID和版本号的固件信息 + List list = otaFirmwareMapper.selectByProductIdAndVersion(productId, version); + // 如果查询结果非空且不为null,则抛出异常,提示固件信息已存在 + if (Objects.nonNull(list) && !list.isEmpty()) { + throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java new file mode 100644 index 000000000..18bf63e83 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.module.iot.service.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordCreateReqBO; +import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordUpdateReqBO; +import jakarta.validation.Valid; + +import java.util.List; +import java.util.Map; + +/** + * IotOtaUpgradeRecordService 接口定义了与物联网设备OTA升级记录相关的操作。 + * 该接口提供了创建、更新、查询、统计和重试升级记录的功能。 + */ +public interface IotOtaUpgradeRecordService { + + /** + * 批量创建物联网OTA升级记录 + *

+ * 该函数用于处理一组物联网OTA升级记录的创建请求,并将这些记录批量保存到系统中。 + * + * @param saveList 包含多个物联网OTA升级记录创建请求的列表,每个请求对象都经过校验(@Valid注解确保) + * 列表中的每个元素都是IotOtaUpgradeRecordCreateReqBO类型的对象,表示一个独立的升级记录创建请求。 + */ + void createUpgradeRecordBatch(@Valid List saveList); + + /** + * 更新现有的OTA升级记录。 + * + * @param updateReqBO 包含更新升级记录所需信息的请求对象,必须经过验证。 + */ + void updateUpgradeRecord(@Valid IotOtaUpgradeRecordUpdateReqBO updateReqBO); + + /** + * 获取OTA升级记录的数量统计。 + * + * @return 返回一个Map,其中键为状态码,值为对应状态的升级记录数量。 + */ + Map getOtaUpgradeRecordCount(@Valid IotOtaUpgradeRecordPageReqVO pageReqVO); + + /** + * 获取OTA升级记录的统计信息。 + * + * @return 返回一个Map,其中键为状态码,值为对应状态的升级记录统计信息。 + */ + Map getOtaUpgradeRecordStatistics(Long firmwareId); + + /** + * 重试指定的OTA升级记录。 + * + * @param id 需要重试的升级记录的ID。 + */ + void retryUpgradeRecord(Long id); + + /** + * 获取指定ID的OTA升级记录的详细信息。 + * + * @param id 需要查询的升级记录的ID。 + * @return 返回包含升级记录详细信息的响应对象。 + */ + IotOtaUpgradeRecordDO getUpgradeRecord(Long id); + + /** + * 分页查询OTA升级记录。 + * + * @param pageReqVO 包含分页查询条件的请求对象,必须经过验证。 + * @return 返回包含分页查询结果的响应对象。 + */ + PageResult getUpgradeRecordPage( + @Valid IotOtaUpgradeRecordPageReqVO pageReqVO); + + /** + * 根据任务ID取消升级记录。 + *

+ * 该函数用于根据给定的任务ID,取消与该任务相关的升级记录。通常用于在任务执行失败或用户手动取消时, + * 清理或标记相关的升级记录为取消状态。 + * + * @param taskId 要取消升级记录的任务ID。该ID唯一标识一个任务,通常由任务管理系统生成。 + */ + void cancelUpgradeRecordByTaskId(Long taskId); + + /** + * 根据升级状态获取升级记录列表 + * + * @param state 升级状态,用于筛选符合条件的升级记录 + * @return 返回符合指定状态的升级记录列表,列表中的元素为 {@link IotOtaUpgradeRecordDO} 对象 + */ + List getUpgradeRecordListByState(Integer state); + + /** + * 更新升级记录的状态。 + *

+ * 该函数用于批量更新指定升级记录的状态。通过传入的ID列表和状态值,将对应的升级记录的状态更新为指定的值。 + * + * @param ids 需要更新状态的升级记录的ID列表。列表中的每个元素代表一个升级记录的ID。 + * @param status 要更新的状态值。该值应为有效的状态标识符,通常为整数类型。 + */ + void updateUpgradeRecordStatus(List ids, Integer status); + + /** + * 根据任务ID获取升级记录列表 + *

+ * 该函数通过给定的任务ID,查询并返回与该任务相关的所有升级记录。 + * + * @param taskId 任务ID,用于指定需要查询的任务 + * @return 返回一个包含升级记录的列表,列表中的每个元素为IotOtaUpgradeRecordDO对象 + */ + List getUpgradeRecordListByTaskId(Long taskId); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java new file mode 100644 index 000000000..71168cd2d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java @@ -0,0 +1,207 @@ +package cn.iocoder.yudao.module.iot.service.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeRecordMapper; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; +import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordCreateReqBO; +import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordUpdateReqBO; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; + +@Slf4j +@Service +@Validated +public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordService { + + @Resource + private IotOtaUpgradeRecordMapper upgradeRecordMapper; + + @Override + public void createUpgradeRecordBatch(List saveList) { + // 1. 批量校验参数信息 + saveList.forEach(saveBO -> validateUpgradeRecordDuplicate(saveBO.getFirmwareId(), saveBO.getTaskId(), saveBO.getDeviceId())); + // 2.将数据转化成数据库存储的格式 + List upgradeRecords = BeanUtils.toBean(saveList, IotOtaUpgradeRecordDO.class); + // 3.将数据批量存储到数据库里 + upgradeRecordMapper.insertBatch(upgradeRecords); + } + + @Override + @Transactional + public void updateUpgradeRecord(IotOtaUpgradeRecordUpdateReqBO updateReqBO) { + // 1.校验升级记录信息是否存在 + validateUpgradeRecordExists(updateReqBO.getId()); + // 2.将数据转化成数据库存储的格式 + IotOtaUpgradeRecordDO updateRecord = BeanUtils.toBean(updateReqBO, IotOtaUpgradeRecordDO.class); + upgradeRecordMapper.updateById(updateRecord); + // TODO @芋艿: 更新升级记录触发的其他Action + } + + /** + * 获取OTA升级记录的数量统计。 + * 该方法根据传入的查询条件,统计不同状态的OTA升级记录数量,并返回一个包含各状态数量的映射。 + * + * @param pageReqVO 包含查询条件的请求对象,主要包括任务ID和设备名称等信息。 + * @return 返回一个Map,其中键为状态常量,值为对应状态的记录数量。 + */ + @Override + @Transactional + public Map getOtaUpgradeRecordCount(IotOtaUpgradeRecordPageReqVO pageReqVO) { + // 分别查询不同状态的OTA升级记录数量 + Long pending = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); + Long pushed = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus()); + Long upgrading = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus()); + Long success = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.SUCCESS.getStatus()); + Long failure = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.FAILURE.getStatus()); + Long canceled = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()); + // 将各状态的数量封装到Map中返回 + return Map.of(IotOtaUpgradeRecordPageReqVO.PENDING, pending, + IotOtaUpgradeRecordPageReqVO.PUSHED, pushed, + IotOtaUpgradeRecordPageReqVO.UPGRADING, upgrading, + IotOtaUpgradeRecordPageReqVO.SUCCESS, success, + IotOtaUpgradeRecordPageReqVO.FAILURE, failure, + IotOtaUpgradeRecordPageReqVO.CANCELED, canceled); + } + + /** + * 获取指定固件ID的OTA升级记录统计信息。 + * 该方法通过查询数据库,统计不同状态的OTA升级记录数量,并返回一个包含各状态数量的映射。 + * + * @param firmwareId 固件ID,用于指定需要统计的固件升级记录。 + * @return 返回一个Map,其中键为升级记录状态(如PENDING、PUSHED等),值为对应状态的记录数量。 + */ + @Override + @Transactional + public Map getOtaUpgradeRecordStatistics(Long firmwareId) { + // 查询并统计不同状态的OTA升级记录数量 + Long pending = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); + Long pushed = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus()); + Long upgrading = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus()); + Long success = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.SUCCESS.getStatus()); + Long failure = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.FAILURE.getStatus()); + Long canceled = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()); + // 将统计结果封装为Map并返回 + return Map.of(IotOtaUpgradeRecordPageReqVO.PENDING, pending, + IotOtaUpgradeRecordPageReqVO.PUSHED, pushed, + IotOtaUpgradeRecordPageReqVO.UPGRADING, upgrading, + IotOtaUpgradeRecordPageReqVO.SUCCESS, success, + IotOtaUpgradeRecordPageReqVO.FAILURE, failure, + IotOtaUpgradeRecordPageReqVO.CANCELED, canceled); + } + + @Override + public void retryUpgradeRecord(Long id) { + // 1.1.校验升级记录信息是否存在 + IotOtaUpgradeRecordDO upgradeRecord = validateUpgradeRecordExists(id); + // 1.2.校验升级记录是否可以重新升级 + validateUpgradeRecordCanRetry(upgradeRecord); + // 2.将一些数据重置,这样定时任务轮询就可以重启任务 + upgradeRecordMapper.updateById(new IotOtaUpgradeRecordDO() + .setId(upgradeRecord.getId()).setProgress(0) + .setStatus(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus())); + // TODO @芋艿: 重试升级记录触发的其他Action + // TODO 如果一个升级记录被取消或者已经执行失败,重试成功,是否会对升级任务的状态有影响? + } + + @Override + public IotOtaUpgradeRecordDO getUpgradeRecord(Long id) { + return upgradeRecordMapper.selectById(id); + } + + @Override + public PageResult getUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { + return upgradeRecordMapper.selectUpgradeRecordPage(pageReqVO); + } + + @Override + public void cancelUpgradeRecordByTaskId(Long taskId) { + // 暂定只有待推送的升级记录可以取消 + upgradeRecordMapper.cancelUpgradeRecordByTaskId(taskId); + } + + @Override + public List getUpgradeRecordListByState(Integer state) { + return upgradeRecordMapper.selectUpgradeRecordListByState(state); + } + + @Override + public void updateUpgradeRecordStatus(List ids, Integer status) { + upgradeRecordMapper.updateUpgradeRecordStatus(ids, status); + } + + @Override + public List getUpgradeRecordListByTaskId(Long taskId) { + return upgradeRecordMapper.selectUpgradeRecordListByTaskId(taskId); + } + + /** + * 验证指定的升级记录是否存在。 + *

+ * 该函数通过给定的ID查询升级记录,如果查询结果为空,则抛出异常,表示升级记录不存在。 + * + * @param id 升级记录的唯一标识符,类型为Long。 + * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出异常,异常类型为OTA_UPGRADE_RECORD_NOT_EXISTS。 + */ + private IotOtaUpgradeRecordDO validateUpgradeRecordExists(Long id) { + // 根据ID查询升级记录 + IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordMapper.selectById(id); + // 如果查询结果为空,抛出异常 + if (upgradeRecord == null) { + throw exception(OTA_UPGRADE_RECORD_NOT_EXISTS); + } + return upgradeRecord; + } + + /** + * 验证固件升级记录是否存在。 + *

+ * 该函数通过给定的固件ID、任务ID和设备ID查询升级记录,如果查询结果为空,则抛出异常。 + * + * @param firmwareId 固件ID,用于标识特定的固件版本 + * @param taskId 任务ID,用于标识特定的升级任务 + * @param deviceId 设备ID,用于标识特定的设备 + * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出OTA_UPGRADE_RECORD_NOT_EXISTS异常 + */ + private void validateUpgradeRecordDuplicate(Long firmwareId, Long taskId, String deviceId) { + // 根据条件查询升级记录 + IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); + // 如果查询结果为空,抛出异常 + if (upgradeRecord != null) { + throw exception(OTA_UPGRADE_RECORD_DUPLICATE); + } + } + + /** + * 验证升级记录是否可以重试。 + *

+ * 该方法用于检查给定的升级记录是否处于允许重试的状态。如果升级记录的状态为 + * PENDING、PUSHED 或 UPGRADING,则抛出异常,表示不允许重试。 + * + * @param upgradeRecord 需要验证的升级记录对象,类型为 IotOtaUpgradeRecordDO + * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出 OTA_UPGRADE_RECORD_CANNOT_RETRY 异常 + */ + private void validateUpgradeRecordCanRetry(IotOtaUpgradeRecordDO upgradeRecord) { + // 检查升级记录的状态是否为 PENDING、PUSHED 或 UPGRADING + if (ObjectUtils.equalsAny(upgradeRecord.getStatus(), + IotOtaUpgradeRecordStatusEnum.PENDING.getStatus(), + IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus(), + IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus())) { + // 如果升级记录处于上述状态之一,则抛出异常,表示不允许重试 + throw exception(OTA_UPGRADE_RECORD_CANNOT_RETRY); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java new file mode 100644 index 000000000..5b3444214 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.iot.service.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * IoT OTA升级任务服务接口 + * 提供OTA升级任务的创建、取消和查询功能 + */ +public interface IotOtaUpgradeTaskService { + + /** + * 创建OTA升级任务 + * + * @param createReqVO OTA升级任务的创建请求对象,包含创建任务所需的信息 + * @return 创建成功的OTA升级任务的ID + */ + Long createUpgradeTask(@Valid IotOtaUpgradeTaskSaveReqVO createReqVO); + + /** + * 取消OTA升级任务 + * + * @param id 要取消的OTA升级任务的ID + */ + void cancelUpgradeTask(Long id); + + /** + * 根据ID获取OTA升级任务的详细信息 + * + * @param id OTA升级任务的ID + * @return OTA升级任务的详细信息对象 + */ + IotOtaUpgradeTaskDO getUpgradeTask(Long id); + + /** + * 分页查询OTA升级任务 + * + * @param pageReqVO OTA升级任务的分页查询请求对象,包含查询条件和分页信息 + * @return 分页查询结果,包含OTA升级任务列表和总记录数 + */ + PageResult getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO); + + /** + * 根据任务状态获取升级任务列表 + * + * @param state 任务状态,用于筛选符合条件的升级任务 + * @return 返回符合指定状态的升级任务列表,列表中的元素为 IotOtaUpgradeTaskDO 对象 + */ + List getUpgradeTaskByState(Integer state); + + /** + * 更新升级任务的状态。 + *

+ * 该函数用于根据任务ID更新指定升级任务的状态。通常用于在任务执行过程中 + * 更新任务的状态,例如从“进行中”变为“已完成”或“失败”。 + * + * @param id 升级任务的唯一标识符,类型为Long。不能为null。 + * @param status 要更新的任务状态,类型为Integer。通常表示任务的状态码,如0表示未开始,1表示进行中,2表示已完成等。 + */ + void updateUpgradeTaskStatus(Long id, Integer status); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java new file mode 100644 index 000000000..b66ae402c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java @@ -0,0 +1,236 @@ +package cn.iocoder.yudao.module.iot.service.ota; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.ota.IotOtaUpgradeRecordConvert; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeTaskMapper; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordCreateReqBO; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; + +@Slf4j +@Service +@Validated +public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { + + @Resource + private IotOtaUpgradeTaskMapper upgradeTaskMapper; + @Lazy + @Resource + private IotDeviceService deviceService; + @Lazy + @Resource + private IotOtaFirmwareService firmwareService; + @Lazy + @Resource + private IotOtaUpgradeRecordService upgradeRecordService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO) { + // 1.1.校验同一固件的升级任务名称不重复 + validateFirmwareTaskDuplicate(createReqVO.getFirmwareId(), createReqVO.getName()); + // 1.2.校验固件信息是否存在 + IotOtaFirmwareDO firmware = firmwareService.validateFirmwareExists(createReqVO.getFirmwareId()); + // 1.3.校验升级范围=2(指定设备时),deviceIds deviceNames不为空并且长度相等 + validateScopeAndDevice(createReqVO.getScope(), createReqVO.getDeviceIds(), createReqVO.getDeviceNames()); + // 2.初始化OTA升级任务信息 + IotOtaUpgradeTaskDO upgradeTask = initUpgradeTask(createReqVO, firmware.getProductId()); + // 3.保存OTA升级任务信息到数据库 + upgradeTaskMapper.insert(upgradeTask); + // 4.生成设备升级记录信息并存储,等待定时任务轮询 + List upgradeRecordList = initUpgradeRecordList(upgradeTask, firmware, createReqVO.getDeviceIds()); + upgradeRecordService.createUpgradeRecordBatch(upgradeRecordList); + // TODO @芋艿: 创建任务触发的其他Action + return upgradeTask.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelUpgradeTask(Long id) { + // 1.1.校验升级任务是否存在 + IotOtaUpgradeTaskDO upgradeTask = validateUpgradeTaskExists(id); + // 1.2.校验升级任务是否可以取消 + validateUpgradeTaskCanCancel(upgradeTask); + // 2.更新OTA升级任务状态为已取消 + upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder() + .id(id).status(IotOtaUpgradeTaskStatusEnum.CANCELED.getStatus()) + .build()); + // 3.更新OTA升级记录状态为已取消 + upgradeRecordService.cancelUpgradeRecordByTaskId(id); + // TODO @芋艿: 取消任务触发的其他Action + } + + @Override + public IotOtaUpgradeTaskDO getUpgradeTask(Long id) { + return upgradeTaskMapper.selectById(id); + } + + @Override + public PageResult getUpgradeTaskPage(IotOtaUpgradeTaskPageReqVO pageReqVO) { + return upgradeTaskMapper.selectUpgradeTaskPage(pageReqVO); + } + + @Override + public List getUpgradeTaskByState(Integer state) { + return upgradeTaskMapper.selectUpgradeTaskByState(state); + } + + @Override + public void updateUpgradeTaskStatus(Long id, Integer status) { + upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder() + .id(id).status(status) + .build()); + } + + /** + * 校验固件升级任务是否重复 + *

+ * 该方法用于检查给定固件ID和任务名称组合是否已存在于数据库中,如果存在则抛出异常, + * 表示任务名称对于该固件而言是重复的此检查确保用户不能创建具有相同名称的任务, + * 从而避免数据重复和混淆 + * + * @param firmwareId 固件的唯一标识符,用于区分不同的固件 + * @param taskName 升级任务的名称,用于与固件ID一起检查重复性 + * @throws cn.iocoder.yudao.framework.common.exception.ServerException 则抛出预定义的异常 + */ + private void validateFirmwareTaskDuplicate(Long firmwareId, String taskName) { + // 查询数据库中是否有相同固件ID和任务名称的升级任务存在 + List upgradeTaskList = upgradeTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName); + // 如果查询结果不为空,说明存在重复的任务名称,抛出异常 + if (CollUtil.isNotEmpty(upgradeTaskList)) { + throw exception(OTA_UPGRADE_TASK_NAME_DUPLICATE); + } + } + + /** + * 验证升级任务的范围和设备参数是否有效 + * 当选择特定设备进行升级时,确保提供的设备ID和设备名称列表有效且对应 + * + * @param scope 升级任务的范围,表示是选择特定设备还是其他范围 + * @param deviceIds 设备ID列表,用于标识参与升级的设备 + * @param deviceNames 设备名称列表,与设备ID列表对应 + */ + private void validateScopeAndDevice(Integer scope, List deviceIds, List deviceNames) { + // 当升级任务范围为选择特定设备时 + if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { + // 检查设备ID列表和设备名称列表是否为空或长度不一致,若不符合要求,则抛出异常 + if (CollUtil.isEmpty(deviceIds) || CollUtil.isEmpty(deviceNames) || deviceIds.size() != deviceNames.size()) { + throw exception(OTA_UPGRADE_TASK_PARAMS_INVALID); + } + } + } + + /** + * 验证升级任务是否存在 + *

+ * 通过查询数据库来验证给定ID的升级任务是否存在此方法主要用于确保后续操作所针对的升级任务是有效的 + * + * @param id 升级任务的唯一标识符如果为null或数据库中不存在对应的记录,则认为任务不存在 + * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 如果升级任务不存在,则抛出异常提示任务不存在 + */ + private IotOtaUpgradeTaskDO validateUpgradeTaskExists(Long id) { + // 查询数据库中是否有相同固件ID和任务名称的升级任务存在 + IotOtaUpgradeTaskDO upgradeTask = upgradeTaskMapper.selectById(id); + // 如果查询结果不为空,说明存在重复的任务名称,抛出异常 + if (Objects.isNull(upgradeTask)) { + throw exception(OTA_UPGRADE_TASK_NOT_EXISTS); + } + return upgradeTask; + } + + /** + * 验证升级任务是否可以被取消 + *

+ * 此方法旨在确保只有当升级任务处于进行中状态时,才可以执行取消操作 + * 它通过比较任务的当前状态与预定义的进行中状态来判断是否允许取消操作 + * 如果任务状态不符合条件,则抛出异常,表明该任务无法取消 + * + * @param upgradeTask 待验证的升级任务对象,包含任务的详细信息,如状态等 + * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 如果任务状态不是进行中,则抛出此异常,表明任务无法取消 + */ + private void validateUpgradeTaskCanCancel(IotOtaUpgradeTaskDO upgradeTask) { + // 检查升级任务的状态是否为进行中,只有此状态下的任务才允许取消 + if (!Objects.equals(upgradeTask.getStatus(), IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus())) { + // 只有进行中的任务才可以取消 + throw exception(OTA_UPGRADE_TASK_CANNOT_CANCEL); + } + } + + /** + * 初始化升级任务 + *

+ * 根据请求参数创建升级任务对象,并根据选择的范围初始化设备数量 + * 如果选择特定设备进行升级,则设备数量为所选设备的总数 + * 如果选择全部设备进行升级,则设备数量为该固件对应产品下的所有设备总数 + * + * @param createReqVO 升级任务保存请求对象,包含创建升级任务所需的信息 + * @return 返回初始化后的升级任务对象 + */ + private IotOtaUpgradeTaskDO initUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, String productId) { + // 配置各项参数 + IotOtaUpgradeTaskDO upgradeTask = IotOtaUpgradeTaskDO.builder() + .name(createReqVO.getName()) + .description(createReqVO.getDescription()) + .firmwareId(createReqVO.getFirmwareId()) + .scope(createReqVO.getScope()) + .deviceIds(createReqVO.getDeviceIds()) + .deviceNames(createReqVO.getDeviceNames()) + .deviceCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds()))) + .status(IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus()) + .build(); + // 如果选择全选,则需要查询设备数量 + if (Objects.equals(createReqVO.getScope(), IotOtaUpgradeTaskScopeEnum.ALL.getScope())) { + // 根据产品ID查询设备数量 + Long deviceCount = deviceService.getDeviceCountByProductId(Convert.toLong(productId)); + // 设置升级任务的设备数量 + upgradeTask.setDeviceCount(deviceCount); + } + // 返回初始化后的升级任务对象 + return upgradeTask; + } + + /** + * 初始化升级记录列表 + *

+ * 根据升级任务的范围(选择设备或按产品ID)获取设备列表,并将其转换为升级记录请求对象列表。 + * + * @param upgradeTask 升级任务对象,包含升级任务的相关信息 + * @param firmware 固件对象,包含固件的相关信息 + * @param deviceIds 设备ID列表,仅在升级任务范围为选择设备时使用 + * @return 升级记录请求对象列表,包含每个设备的升级记录信息 + */ + private List initUpgradeRecordList(IotOtaUpgradeTaskDO upgradeTask, IotOtaFirmwareDO firmware, List deviceIds) { + // 根据升级任务的范围确定设备列表 + List deviceList; + if (Objects.equals(upgradeTask.getScope(), IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { + // 如果升级任务范围为选择设备,则根据设备ID列表获取设备信息 + deviceList = deviceService.getDeviceListByIdList(deviceIds); + } else { + // 如果升级任务范围为按产品ID,则根据固件的产品ID获取设备信息 + deviceList = deviceService.getDeviceListByProductId(Convert.toLong(firmware.getProductId())); + } + // 将升级任务、固件和设备列表转换为升级记录请求对象列表 + return IotOtaUpgradeRecordConvert.INSTANCE.convertBOList(upgradeTask, firmware, deviceList); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/package-info.java new file mode 100644 index 000000000..fbed390ae --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.iot.service.ota.bo; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/package-info.java new file mode 100644 index 000000000..af729fae3 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.iot.service.ota.bo.upgrade; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordCreateReqBO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordCreateReqBO.java new file mode 100644 index 000000000..e3accc427 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordCreateReqBO.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record; + +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class IotOtaUpgradeRecordCreateReqBO { + + /** + * 固件编号 + *

+ * 关联 {@link IotOtaFirmwareDO#getId()} + */ + @NotNull(message = "固件编号不能为空") + private Long firmwareId; + /** + * 任务编号 + *

+ * 关联 {@link IotOtaUpgradeTaskDO#getId()} + */ + @NotNull(message = "任务编号不能为空") + private Long taskId; + /** + * 产品标识 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} + */ + private String productKey; + /** + * 设备名称 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} + */ + private String deviceName; + /** + * 设备编号 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} + */ + @NotNull(message = "设备编号不能为空") + private String deviceId; + /** + * 来源的固件编号 + *

+ * 关联 {@link IotDeviceDO#getFirmwareId()} + */ + private Long fromFirmwareId; + /** + * 升级状态 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum} + */ + private Integer status; + /** + * 升级进度,百分比 + */ + private Integer progress; + /** + * 升级进度描述 + *

+ * 注意,只记录设备最后一次的升级进度描述 + * 如果想看历史记录,可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志 + */ + private String description; + /** + * 升级开始时间 + */ + private LocalDateTime startTime; + /** + * 升级结束时间 + */ + private LocalDateTime endTime; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordUpdateReqBO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordUpdateReqBO.java new file mode 100644 index 000000000..e0e71097c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordUpdateReqBO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Range; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Data +public class IotOtaUpgradeRecordUpdateReqBO { + + /** + * 升级记录编号 + */ + @NotNull(message = "升级记录编号不能为空") + private Long id; + /** + * 升级状态 + *

+ * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum} + */ + @InEnum(IotOtaUpgradeRecordStatusEnum.class) + private Integer status; + /** + * 升级进度,百分比 + */ + @Range(min = 0, max = 100, message = "升级进度必须介于 0-100 之间") + private Integer progress; + /** + * 升级开始时间 + */ + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime startTime; + /** + * 升级结束时间 + */ + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime endTime; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml new file mode 100644 index 000000000..0dac6efb5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + \ No newline at end of file From 0400932260d5ba33f7e813a1daef8be9b0512506 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Thu, 20 Feb 2025 17:44:06 +0800 Subject: [PATCH 171/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=E7=9A=84=E6=89=A7=E8=A1=8C=E5=99=A8=E6=8A=BD=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao-spring-boot-starter-mq/pom.xml | 1 + yudao-module-iot/yudao-module-iot-biz/pom.xml | 7 +- .../action/IotRuleSceneDataBridgeAction.java | 157 +----------------- .../rule/execute/IotDataBridgeExecute.java | 32 ++++ .../execute/IotHttpDataBridgeExecute.java | 93 +++++++++++ .../execute/IotRocketMQDataBridgeExecute.java | 96 +++++++++++ 6 files changed, 232 insertions(+), 154 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotDataBridgeExecute.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotHttpDataBridgeExecute.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java diff --git a/yudao-framework/yudao-spring-boot-starter-mq/pom.xml b/yudao-framework/yudao-spring-boot-starter-mq/pom.xml index 15bbaa42d..c8972f16b 100644 --- a/yudao-framework/yudao-spring-boot-starter-mq/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mq/pom.xml @@ -36,6 +36,7 @@ org.apache.rocketmq rocketmq-spring-boot-starter + true diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 2a9669c0e..ea1dde86f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -75,10 +75,11 @@ - + - cn.iocoder.boot - yudao-spring-boot-starter-mq + org.apache.rocketmq + rocketmq-spring-boot-starter + true diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index 7668c05b9..f87cd6001 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -1,33 +1,18 @@ package cn.iocoder.yudao.module.iot.service.rule.action; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.util.http.HttpUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; +import cn.iocoder.yudao.module.iot.service.rule.execute.IotDataBridgeExecute; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; -import org.apache.rocketmq.client.producer.DefaultMQProducer; -import org.apache.rocketmq.client.producer.SendResult; -import org.apache.rocketmq.client.producer.SendStatus; -import org.apache.rocketmq.common.message.Message; -import org.apache.rocketmq.remoting.common.RemotingHelper; -import org.springframework.http.*; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; - -import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; +import java.util.List; /** * IoT 数据桥梁的 {@link IotRuleSceneAction} 实现类 @@ -41,11 +26,10 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ @Slf4j public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { - @Resource - private RestTemplate restTemplate; - @Resource private IotDataBridgeService dataBridgeService; + @Resource + private List dataBridgeExecutes; @Override public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { @@ -65,26 +49,8 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { return; } - // 2.1 执行 HTTP 请求 - if (IotDataBridgTypeEnum.HTTP.getType().equals(dataBridge.getType())) { - executeHttp(message, (IotDataBridgeDO.HttpConfig) dataBridge.getConfig()); - return; - } - // 2.2 执行 RocketMQ 发送消息 - if (IotDataBridgTypeEnum.ROCKETMQ.getType().equals(dataBridge.getType())) { - executeRocketMQ(message, (IotDataBridgeDO.RocketMQConfig) dataBridge.getConfig()); - return; - } - - // TODO @芋艿:因为下面的,都是有状态的,所以通过 guava 缓存连接,然后通过 RemovalNotification 实现关闭。例如说,一次新建有效期是 10 分钟; - // TODO @芋艿:mq-redis - // TODO @芋艿:mq-数据库 - // TODO @芋艿:kafka - // TODO @芋艿:rocketmq - // TODO @芋艿:rabbitmq - // TODO @芋艿:mqtt - // TODO @芋艿:tcp - // TODO @芋艿:websocket + // 2.1 执行数据桥接操作 + dataBridgeExecutes.forEach(execute -> execute.execute(message, dataBridge)); } @Override @@ -92,115 +58,4 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { return IotRuleSceneActionTypeEnum.DATA_BRIDGE; } - @SuppressWarnings({"unchecked", "deprecation"}) - private void executeHttp(IotDeviceMessage message, IotDataBridgeDO.HttpConfig config) { - String url = null; - HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase()); - HttpEntity requestEntity = null; - ResponseEntity responseEntity = null; - try { - // 1.1 构建 Header - HttpHeaders headers = new HttpHeaders(); - if (CollUtil.isNotEmpty(config.getHeaders())) { - config.getHeaders().putAll(config.getHeaders()); - } - headers.add(HEADER_TENANT_ID, message.getTenantId().toString()); - // 1.2 构建 URL - UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(config.getUrl()); - if (CollUtil.isNotEmpty(config.getQuery())) { - config.getQuery().forEach(uriBuilder::queryParam); - } - // 1.3 构建请求体 - if (method == HttpMethod.GET) { - uriBuilder.queryParam("message", HttpUtils.encodeUtf8(JsonUtils.toJsonString(message))); - url = uriBuilder.build().toUriString(); - requestEntity = new HttpEntity<>(headers); - } else { - url = uriBuilder.build().toUriString(); - Map requestBody = JsonUtils.parseObject(config.getBody(), Map.class); - if (requestBody == null) { - requestBody = new HashMap<>(); - } - requestBody.put("message", message); - headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE); - requestEntity = new HttpEntity<>(JsonUtils.toJsonString(requestBody), headers); - } - - // 2.1 发送请求 - responseEntity = restTemplate.exchange(url, method, requestEntity, String.class); - // 2.2 记录日志 - if (responseEntity.getStatusCode().is2xxSuccessful()) { - log.info("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求成功({})]", - message, config, url, method, requestEntity, responseEntity); - } else { - log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求失败({})]", - message, config, url, method, requestEntity, responseEntity); - } - } catch (Exception e) { - log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求异常({})]", - message, config, url, method, requestEntity, responseEntity, e); - } - } - - private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { - // 1.1 创建生产者实例,指定生产者组名 - DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); - // TODO @puhui999:可以考虑,基于 guava 做 cache,使用 config 作为 key,然后假个 listener 超时,销毁 producer - try { - // 1.2 设置 NameServer 地址 - producer.setNamesrvAddr(config.getNameServer()); - // 1.3 启动生产者 - producer.start(); - - // 2.1 创建消息对象,指定Topic、Tag和消息体 - Message msg = new Message( - config.getTopic(), - config.getTags(), - message.toString().getBytes(RemotingHelper.DEFAULT_CHARSET) - ); - // 2.2 发送同步消息并处理结果 - SendResult sendResult = producer.send(msg); - // 2.3 处理发送结果 - if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { - log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", message, config, sendResult); - } else { - log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", message, config, sendResult); - } - } catch (Exception e) { - log.error("[executeRocketMQ][message({}) config({}) 发送异常]", message, config, e); - } finally { - // 3. 关闭生产者 - producer.shutdown(); - } - } - - // TODO @芋艿:测试代码,后续清理 - public static void main(String[] args) { - // 1. 创建 IotRuleSceneDataBridgeAction 实例 - IotRuleSceneDataBridgeAction action = new IotRuleSceneDataBridgeAction(); - - // 2. 创建测试消息 - IotDeviceMessage message = IotDeviceMessage.builder() - .requestId("TEST-001") - .productKey("testProduct") - .deviceName("testDevice") - .deviceKey("testDeviceKey") - .type("property") - .identifier("temperature") - .data("{\"value\": 60}") - .reportTime(LocalDateTime.now()) - .tenantId(1L) - .build(); - - // 3. 创建 RocketMQ 配置 - IotDataBridgeDO.RocketMQConfig config = new IotDataBridgeDO.RocketMQConfig(); - config.setNameServer("127.0.0.1:9876"); - config.setGroup("test-group"); - config.setTopic("test-topic"); - config.setTags("test-tag"); - - // 4. 执行测试 - action.executeRocketMQ(message, config); - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotDataBridgeExecute.java new file mode 100644 index 000000000..8979d2115 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotDataBridgeExecute.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.iot.service.rule.execute; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; + + +/** + * IoT 数据桥梁的执行器 execute 接口 + * + * @author HUIHUI + */ +public interface IotDataBridgeExecute { + + /** + * 执行数据桥接操作 + * + * @param message 设备消息 + * @param dataBridge 数据桥梁 + */ + void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge); + + // TODO @芋艿:因为下面的,都是有状态的,所以通过 guava 缓存连接,然后通过 RemovalNotification 实现关闭。例如说,一次新建有效期是 10 分钟; + // TODO @芋艿:mq-redis + // TODO @芋艿:mq-数据库 + // TODO @芋艿:kafka + // TODO @芋艿:rocketmq + // TODO @芋艿:rabbitmq + // TODO @芋艿:mqtt + // TODO @芋艿:tcp + // TODO @芋艿:websocket + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotHttpDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotHttpDataBridgeExecute.java new file mode 100644 index 000000000..861fadd6c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotHttpDataBridgeExecute.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.iot.service.rule.execute; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.HashMap; +import java.util.Map; + +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + +/** + * Http 的 {@link IotDataBridgeExecute} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { + + @Resource + private RestTemplate restTemplate; + + @Override + public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { + // 1.1 校验数据桥接的类型 == HTTP + if (!IotDataBridgTypeEnum.HTTP.getType().equals(dataBridge.getType())) { + return; + } + // 1.2 执行 HTTP 请求 + executeHttp(message, (IotDataBridgeDO.HttpConfig) dataBridge.getConfig()); + } + + @SuppressWarnings({"unchecked", "deprecation"}) + private void executeHttp(IotDeviceMessage message, IotDataBridgeDO.HttpConfig config) { + String url = null; + HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase()); + HttpEntity requestEntity = null; + ResponseEntity responseEntity = null; + try { + // 1.1 构建 Header + HttpHeaders headers = new HttpHeaders(); + if (CollUtil.isNotEmpty(config.getHeaders())) { + config.getHeaders().putAll(config.getHeaders()); + } + headers.add(HEADER_TENANT_ID, message.getTenantId().toString()); + // 1.2 构建 URL + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(config.getUrl()); + if (CollUtil.isNotEmpty(config.getQuery())) { + config.getQuery().forEach(uriBuilder::queryParam); + } + // 1.3 构建请求体 + if (method == HttpMethod.GET) { + uriBuilder.queryParam("message", HttpUtils.encodeUtf8(JsonUtils.toJsonString(message))); + url = uriBuilder.build().toUriString(); + requestEntity = new HttpEntity<>(headers); + } else { + url = uriBuilder.build().toUriString(); + Map requestBody = JsonUtils.parseObject(config.getBody(), Map.class); + if (requestBody == null) { + requestBody = new HashMap<>(); + } + requestBody.put("message", message); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE); + requestEntity = new HttpEntity<>(JsonUtils.toJsonString(requestBody), headers); + } + + // 2.1 发送请求 + responseEntity = restTemplate.exchange(url, method, requestEntity, String.class); + // 2.2 记录日志 + if (responseEntity.getStatusCode().is2xxSuccessful()) { + log.info("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求成功({})]", + message, config, url, method, requestEntity, responseEntity); + } else { + log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求失败({})]", + message, config, url, method, requestEntity, responseEntity); + } + } catch (Exception e) { + log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求异常({})]", + message, config, url, method, requestEntity, responseEntity, e); + } + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java new file mode 100644 index 000000000..3e02e6960 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.iot.service.rule.execute; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.SendResult; +import org.apache.rocketmq.client.producer.SendStatus; +import org.apache.rocketmq.common.message.Message; +import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * RocketMQ 的 {@link IotDataBridgeExecute} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { + + @Override + public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { + // 1.1 校验数据桥接的类型 == ROCKETMQ + if (!IotDataBridgTypeEnum.ROCKETMQ.getType().equals(dataBridge.getType())) { + return; + } + // 1.2 执行 RocketMQ 发送消息 + executeRocketMQ(message, (IotDataBridgeDO.RocketMQConfig) dataBridge.getConfig()); + } + + private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { + // 1.1 创建生产者实例,指定生产者组名 + DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); + // TODO @puhui999:可以考虑,基于 guava 做 cache,使用 config 作为 key,然后假个 listener 超时,销毁 producer + try { + // 1.2 设置 NameServer 地址 + producer.setNamesrvAddr(config.getNameServer()); + // 1.3 启动生产者 + producer.start(); + + // 2.1 创建消息对象,指定Topic、Tag和消息体 + Message msg = new Message( + config.getTopic(), + config.getTags(), + message.toString().getBytes(RemotingHelper.DEFAULT_CHARSET) + ); + // 2.2 发送同步消息并处理结果 + SendResult sendResult = producer.send(msg); + // 2.3 处理发送结果 + if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { + log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", message, config, sendResult); + } else { + log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", message, config, sendResult); + } + } catch (Exception e) { + log.error("[executeRocketMQ][message({}) config({}) 发送异常]", message, config, e); + } finally { + // 3. 关闭生产者 + producer.shutdown(); + } + } + + // TODO @芋艿:测试代码,后续清理 + public static void main(String[] args) { + // 1. 创建 IotRocketMQDataBridgeExecute 实例 + IotRocketMQDataBridgeExecute action = new IotRocketMQDataBridgeExecute(); + + // 2. 创建测试消息 + IotDeviceMessage message = IotDeviceMessage.builder() + .requestId("TEST-001") + .productKey("testProduct") + .deviceName("testDevice") + .deviceKey("testDeviceKey") + .type("property") + .identifier("temperature") + .data("{\"value\": 60}") + .reportTime(LocalDateTime.now()) + .tenantId(1L) + .build(); + + // 3. 创建 RocketMQ 配置 + IotDataBridgeDO.RocketMQConfig config = new IotDataBridgeDO.RocketMQConfig(); + config.setNameServer("127.0.0.1:9876"); + config.setGroup("test-group"); + config.setTopic("test-topic"); + config.setTags("test-tag"); + + // 4. 执行测试 + action.executeRocketMQ(message, config); + } + +} From 4be18af236ac036741c6adba23fa58d06f17a73c Mon Sep 17 00:00:00 2001 From: puhui999 Date: Thu, 20 Feb 2025 18:21:52 +0800 Subject: [PATCH 172/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E5=9F=BA=E4=BA=8E=20guava=20=E5=AF=B9?= =?UTF-8?q?=20producer=20=E5=81=9A=20cache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../execute/IotRocketMQDataBridgeExecute.java | 69 ++++++++++++++----- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java index 3e02e6960..11ca2339c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java @@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.iot.service.rule.execute; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.client.producer.SendResult; @@ -11,7 +14,9 @@ import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.springframework.stereotype.Component; +import java.time.Duration; import java.time.LocalDateTime; +import java.util.concurrent.Executors; /** * RocketMQ 的 {@link IotDataBridgeExecute} 实现类 @@ -22,6 +27,36 @@ import java.time.LocalDateTime; @Slf4j public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { + /** + * 针对 {@link IotDataBridgeDO.RocketMQConfig} 的 DefaultMQProducer 缓存 + */ + private final LoadingCache PRODUCER_CACHE = CacheBuilder.newBuilder() + // 只阻塞当前数据加载线程,其他线程返回旧值 + .refreshAfterWrite(Duration.ofMinutes(10)) + // 增加移除监听器,自动关闭 producer + .removalListener(notification -> { + DefaultMQProducer producer = (DefaultMQProducer) notification.getValue(); + if (producer != null) { + try { + producer.shutdown(); + log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已关闭]", notification.getKey()); + } catch (Exception e) { + log.error("[PRODUCER_CACHE][配置({}) 对应的 producer 关闭失败]", notification.getKey(), e); + } + } + }) + // 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程 + .build(CacheLoader.asyncReloading(new CacheLoader() { + @Override + public DefaultMQProducer load(IotDataBridgeDO.RocketMQConfig config) throws Exception { + DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); + producer.setNamesrvAddr(config.getNameServer()); + producer.start(); + log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config); + return producer; + } + }, Executors.newCachedThreadPool())); + @Override public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { // 1.1 校验数据桥接的类型 == ROCKETMQ @@ -33,14 +68,9 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { } private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { - // 1.1 创建生产者实例,指定生产者组名 - DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); - // TODO @puhui999:可以考虑,基于 guava 做 cache,使用 config 作为 key,然后假个 listener 超时,销毁 producer try { - // 1.2 设置 NameServer 地址 - producer.setNamesrvAddr(config.getNameServer()); - // 1.3 启动生产者 - producer.start(); + // 1. 获取或创建 Producer + DefaultMQProducer producer = PRODUCER_CACHE.get(config); // 2.1 创建消息对象,指定Topic、Tag和消息体 Message msg = new Message( @@ -58,18 +88,22 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { } } catch (Exception e) { log.error("[executeRocketMQ][message({}) config({}) 发送异常]", message, config, e); - } finally { - // 3. 关闭生产者 - producer.shutdown(); } } // TODO @芋艿:测试代码,后续清理 public static void main(String[] args) { - // 1. 创建 IotRocketMQDataBridgeExecute 实例 + // 1. 创建一个共享的实例 IotRocketMQDataBridgeExecute action = new IotRocketMQDataBridgeExecute(); - // 2. 创建测试消息 + // 2. 创建共享的配置 + IotDataBridgeDO.RocketMQConfig config = new IotDataBridgeDO.RocketMQConfig(); + config.setNameServer("127.0.0.1:9876"); + config.setGroup("test-group"); + config.setTopic("test-topic"); + config.setTags("test-tag"); + + // 3. 创建共享的消息 IotDeviceMessage message = IotDeviceMessage.builder() .requestId("TEST-001") .productKey("testProduct") @@ -82,14 +116,11 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { .tenantId(1L) .build(); - // 3. 创建 RocketMQ 配置 - IotDataBridgeDO.RocketMQConfig config = new IotDataBridgeDO.RocketMQConfig(); - config.setNameServer("127.0.0.1:9876"); - config.setGroup("test-group"); - config.setTopic("test-topic"); - config.setTags("test-tag"); + // 4. 执行两次测试,验证缓存 + log.info("[main][第一次执行,应该会创建新的 producer]"); + action.executeRocketMQ(message, config); - // 4. 执行测试 + log.info("[main][第二次执行,应该会复用缓存的 producer]"); action.executeRocketMQ(message, config); } From ca9575226637284b00fc07545b0b1082267aa743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Thu, 20 Feb 2025 18:30:57 +0800 Subject: [PATCH 173/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT:=20=E6=B7=BB=E5=8A=A0=20EMQX=20=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E6=94=AF=E6=8C=81=E8=AE=BE=E5=A4=87=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E8=AE=A4=E8=AF=81=E5=92=8C=20MQTT=20=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E5=8F=82=E6=95=B0=E8=8E=B7=E5=8F=96=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/api/device/IotDeviceUpstreamApi.java | 8 ++ .../upstream/IotDeviceEmqxAuthReqDTO.java | 32 +++++ .../api/device/IoTDeviceUpstreamApiImpl.java | 11 +- .../admin/device/IotDeviceController.java | 9 +- .../iot/service/device/IotDeviceService.java | 8 ++ .../service/device/IotDeviceServiceImpl.java | 48 +++---- .../control/IotDeviceUpstreamService.java | 7 ++ .../control/IotDeviceUpstreamServiceImpl.java | 54 ++++++-- .../yudao/module/iot/util/MqttSignUtils.java | 96 ++++++++++++++ .../IotPluginCommonAutoConfiguration.java | 4 +- .../config/IotPluginCommonProperties.java | 11 ++ .../IotDeviceConfigSetVertxHandler.java | 2 +- .../IotDeviceOtaUpgradeVertxHandler.java | 7 +- .../IotDevicePropertyGetVertxHandler.java | 2 +- .../IotDevicePropertySetVertxHandler.java | 2 +- .../IotDeviceServiceInvokeVertxHandler.java | 5 +- .../IotPluginInstanceHeartbeatJob.java | 5 +- .../upstream/IotDeviceUpstreamClient.java | 6 + .../common/util/IotPluginCommonUtils.java | 8 ++ .../plugin.properties | 8 +- .../yudao-module-iot-plugin-emqx/pom.xml | 118 +++++++++--------- .../yudao/module/iot/plugin/EmqxPlugin.java | 42 ------- .../plugin/emqx/IotEmqxPluginApplication.java | 22 ++++ .../iot/plugin/emqx/config/IotEmqxPlugin.java | 57 +++++++++ .../IotPluginEmqxAutoConfiguration.java | 35 ++++++ .../emqx/config/IotPluginEmqxProperties.java | 42 +++++++ .../IotDeviceDownstreamHandlerImpl.java | 42 +++++++ .../upstream/IotDeviceUpstreamServer.java | 83 ++++++++++++ .../router/IotDeviceAuthVertxHandler.java | 54 ++++++++ .../src/main/resources/application.yml | 17 +++ .../IotDeviceEventReportVertxHandler.java | 2 +- .../src/main/resources/application.yml | 1 + 32 files changed, 685 insertions(+), 163 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/IotEmqxPluginApplication.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/resources/application.yml diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java index 7d198eba3..c43a0f2b2 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java @@ -71,6 +71,14 @@ public interface IotDeviceUpstreamApi { @PostMapping(PREFIX + "/add-topology") CommonResult addDeviceTopology(@Valid @RequestBody IotDeviceTopologyAddReqDTO addReqDTO); + /** + * 认证 Emqx 连接 + * + * @param authReqDTO 认证 Emqx 连接 DTO + */ + @PostMapping(PREFIX + "/authenticate-emqx-connection") + CommonResult authenticateEmqxConnection(@Valid @RequestBody IotDeviceEmqxAuthReqDTO authReqDTO); + // ========== 插件相关 ========== /** diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java new file mode 100644 index 000000000..365552db0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +/** + * IoT 认证 Emqx 连接 Request DTO + * + * @author 芋道源码 + */ +@Data +public class IotDeviceEmqxAuthReqDTO { + + /** + * 客户端 ID + */ + @NotEmpty(message = "客户端 ID 不能为空") + private String clientId; + + /** + * 用户名 + */ + @NotEmpty(message = "用户名不能为空") + private String username; + + /** + * 密码 + */ + @NotEmpty(message = "密码不能为空") + private String password; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java index 699f3dd75..61df8e43e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java @@ -4,15 +4,14 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*; import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService; import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService; +import jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; -import jakarta.annotation.Resource; - import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; /** - * * 设备数据 Upstream 上行 API 实现类 + * * 设备数据 Upstream 上行 API 实现类 */ @RestController @Validated @@ -61,6 +60,12 @@ public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi { return success(true); } + @Override + public CommonResult authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) { + Boolean result = deviceUpstreamService.authenticateEmqxConnection(authReqDTO); + return success(result); + } + // ========== 插件相关 ========== @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index ac2c6ebd8..18aa5a34f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -7,8 +7,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService; @@ -177,4 +177,11 @@ public class IotDeviceController { return success(true); } + @GetMapping("/mqtt-connection-params") + @Operation(summary = "获取 MQTT 连接参数") + @PreAuthorize("@ss.hasPermission('iot:device:mqtt-connection-params')") + public CommonResult getMqttConnectionParams(@RequestParam("deviceId") Long deviceId) { + return success(deviceService.getMqttConnectionParams(deviceId)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 24532d254..1d73c6aed 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -168,4 +168,12 @@ public interface IotDeviceService { */ IotDeviceImportRespVO importDevice(List importDevices, boolean updateSupport); + /** + * 获取 MQTT 连接参数 + * + * @param deviceId 设备 ID + * @return MQTT 连接参数 + */ + IotDeviceMqttConnectionParamsRespVO getMqttConnectionParams(Long deviceId); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 66854e84b..847581512 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -20,6 +20,8 @@ import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import cn.iocoder.yudao.module.iot.service.product.IotProductService; +import cn.iocoder.yudao.module.iot.util.MqttSignUtils; +import cn.iocoder.yudao.module.iot.util.MqttSignUtils.MqttSignResult; import jakarta.annotation.Resource; import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; @@ -123,10 +125,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { .setDeviceType(product.getDeviceType()); // 生成并设置必要的字段 // TODO @芋艿:各种 mqtt 是不是可以简化! - device.setDeviceSecret(generateDeviceSecret()) - .setMqttClientId(generateMqttClientId()) - .setMqttUsername(generateMqttUsername(device.getDeviceName(), device.getProductKey())) - .setMqttPassword(generateMqttPassword()); + // clientId、username、password 根据规则实时生成 + device.setDeviceSecret(generateDeviceSecret()); // 设置设备状态为未激活 device.setState(IotDeviceStateEnum.INACTIVE.getState()); } @@ -318,35 +318,6 @@ public class IotDeviceServiceImpl implements IotDeviceService { return IdUtil.fastSimpleUUID(); } - /** - * 生成 MQTT Client ID - * - * @return 生成的 MQTT Client ID - */ - private String generateMqttClientId() { - return IdUtil.fastSimpleUUID(); - } - - /** - * 生成 MQTT Username - * - * @param deviceName 设备名称 - * @param productKey 产品 Key - * @return 生成的 MQTT Username - */ - private String generateMqttUsername(String deviceName, String productKey) { - return deviceName + "&" + productKey; - } - - /** - * 生成 MQTT Password - * - * @return 生成的 MQTT Password - */ - private String generateMqttPassword() { - return RandomUtil.randomString(32); - } - @Override @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入 public IotDeviceImportRespVO importDevice(List importDevices, boolean updateSupport) { @@ -417,6 +388,17 @@ public class IotDeviceServiceImpl implements IotDeviceService { return respVO; } + @Override + public IotDeviceMqttConnectionParamsRespVO getMqttConnectionParams(Long deviceId) { + IotDeviceDO device = validateDeviceExists(deviceId); + MqttSignResult mqttSignResult = MqttSignUtils.calculate(device.getProductKey(), device.getDeviceName(), + device.getDeviceSecret()); + return new IotDeviceMqttConnectionParamsRespVO() + .setMqttClientId(mqttSignResult.getClientId()) + .setMqttUsername(mqttSignResult.getUsername()) + .setMqttPassword(mqttSignResult.getPassword()); + } + private void deleteDeviceCache(IotDeviceDO device) { // 保证 Spring AOP 触发 getSelf().deleteDeviceCache0(device); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java index 39b0d19c0..cb2e5b400 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java @@ -62,4 +62,11 @@ public interface IotDeviceUpstreamService { */ void addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO); + /** + * Emqx 连接认证 + * + * @param authReqDTO Emqx 连接认证 DTO + */ + Boolean authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index ad065f930..93b4ea388 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -20,6 +20,8 @@ import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService; +import cn.iocoder.yudao.module.iot.util.MqttSignUtils; +import cn.iocoder.yudao.module.iot.util.MqttSignUtils.MqttSignResult; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -58,25 +60,26 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { // 2.1 情况一:属性上报 String requestId = IdUtil.fastSimpleUUID(); if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) { - reportDeviceProperty(((IotDevicePropertyReportReqDTO) - new IotDevicePropertyReportReqDTO().setRequestId(requestId).setReportTime(LocalDateTime.now()) - .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) + reportDeviceProperty(((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO() + .setRequestId(requestId).setReportTime(LocalDateTime.now()) + .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) .setProperties((Map) simulatorReqVO.getData())); return; } // 2.2 情况二:事件上报 if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.EVENT.getType())) { - reportDeviceEvent(((IotDeviceEventReportReqDTO) - new IotDeviceEventReportReqDTO().setRequestId(requestId).setReportTime(LocalDateTime.now()) - .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) - .setIdentifier(simulatorReqVO.getIdentifier()).setParams((Map) simulatorReqVO.getData())); + reportDeviceEvent(((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId) + .setReportTime(LocalDateTime.now()) + .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) + .setIdentifier(simulatorReqVO.getIdentifier()) + .setParams((Map) simulatorReqVO.getData())); return; } // 2.3 情况三:状态变更 if (Objects.equals(simulatorReqVO.getType(), IotDeviceMessageTypeEnum.STATE.getType())) { - updateDeviceState(((IotDeviceStateUpdateReqDTO) - new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()).setReportTime(LocalDateTime.now()) - .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) + updateDeviceState(((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO() + .setRequestId(IdUtil.fastSimpleUUID()).setReportTime(LocalDateTime.now()) + .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) .setState((Integer) simulatorReqVO.getData())); return; } @@ -277,6 +280,37 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { sendDeviceMessage(message, device); } + @Override + public Boolean authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) { + log.info("[authenticateEmqxConnection][认证 Emqx 连接: {}]", authReqDTO); + // 1. 校验设备是否存在 + // username 格式:${DeviceName}&${ProductKey} + String[] usernameParts = authReqDTO.getUsername().split("&"); + if (usernameParts.length != 2) { + log.error("[authenticateEmqxConnection][认证失败,username 格式不正确]"); + return Boolean.FALSE; + } + String deviceName = usernameParts[0]; + String productKey = usernameParts[1]; + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( + productKey, deviceName); + if (device == null) { + log.error("[authenticateEmqxConnection][设备({}/{}) 不存在]", + productKey, deviceName); + return Boolean.FALSE; + } + // 2. 校验密码 + String deviceSecret = device.getDeviceSecret(); + String clientId = authReqDTO.getClientId(); + MqttSignResult sign = MqttSignUtils.calculate(productKey, deviceName, deviceSecret, clientId); + if (!StrUtil.equals(sign.getPassword(), authReqDTO.getPassword())) { + log.error("[authenticateEmqxConnection][认证失败,密码不正确]"); + return Boolean.FALSE; + } + log.info("[authenticateEmqxConnection][认证成功]"); + return Boolean.TRUE; + } + private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) { // 1. 【异步】记录设备与插件实例的映射 pluginInstanceService.updateDevicePluginInstanceProcessIdAsync(device.getDeviceKey(), reqDTO.getProcessId()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java new file mode 100644 index 000000000..40213e3ae --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.module.iot.util; + +import lombok.Getter; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; + +/** + * MQTT 签名工具类 + * 提供静态方法来计算 MQTT 连接参数。 + */ +public class MqttSignUtils { + + private static final String SIGN_METHOD = "hmacsha256"; + + /** + * 计算 MQTT 连接参数 + * + * @param productKey 产品密钥 + * @param deviceName 设备名称 + * @param deviceSecret 设备密钥 + * @return 包含 clientId, username, password 的结果对象 + */ + public static MqttSignResult calculate(String productKey, String deviceName, String deviceSecret) { + String clientId = productKey + "." + deviceName; + String username = deviceName + "&" + productKey; + String signContent = String.format("clientId%sdeviceName%sdeviceSecret%sproductKey%s", + clientId, deviceName, deviceSecret, productKey); + + String password = sign(signContent, deviceSecret); + + return new MqttSignResult(clientId, username, password); + } + + /** + * 计算 MQTT 连接参数 + * + * @param productKey 产品密钥 + * @param deviceName 设备名称 + * @param deviceSecret 设备密钥 + * @param clientId 客户端 ID + * @return 包含 clientId, username, password 的结果对象 + */ + public static MqttSignResult calculate(String productKey, String deviceName, String deviceSecret, String clientId) { + String username = deviceName + "&" + productKey; + String signContentBuilder = "clientId" + clientId + + "deviceName" + deviceName + + "deviceSecret" + deviceSecret + + "productKey" + productKey; + + String password = sign(signContentBuilder, deviceSecret); + + return new MqttSignResult(clientId, username, password); + } + + private static String sign(String content, String key) { + try { + Mac mac = Mac.getInstance(SIGN_METHOD); + mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), SIGN_METHOD)); + byte[] signData = mac.doFinal(content.getBytes(StandardCharsets.UTF_8)); + return bytesToHex(signData); + } catch (Exception e) { + throw new RuntimeException("Failed to sign content with HmacSHA256", e); + } + } + + private static String bytesToHex(byte[] bytes) { + StringBuilder hexString = new StringBuilder(bytes.length * 2); + for (byte b : bytes) { + String hex = Integer.toHexString(0xFF & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } + + /** + * MQTT 签名结果类 + */ + @Getter + public static class MqttSignResult { + private final String clientId; + private final String username; + private final String password; + + public MqttSignResult(String clientId, String username, String password) { + this.clientId = clientId; + this.username = username; + this.password = password; + } + + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java index 7e3d669f2..111189875 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java @@ -44,8 +44,8 @@ public class IotPluginCommonAutoConfiguration { @Bean(initMethod = "init", destroyMethod = "stop") public IotPluginInstanceHeartbeatJob pluginInstanceHeartbeatJob( - IotDeviceUpstreamApi deviceDataApi, IotDeviceDownstreamServer deviceDownstreamServer) { - return new IotPluginInstanceHeartbeatJob(deviceDataApi, deviceDownstreamServer); + IotDeviceUpstreamApi deviceDataApi, IotDeviceDownstreamServer deviceDownstreamServer, IotPluginCommonProperties commonProperties) { + return new IotPluginInstanceHeartbeatJob(deviceDataApi, deviceDownstreamServer, commonProperties); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonProperties.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonProperties.java index 556786507..03d42c288 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonProperties.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonProperties.java @@ -7,6 +7,11 @@ import org.springframework.validation.annotation.Validated; import java.time.Duration; +/** + * IoT 插件的通用配置类 + * + * @author haohao + */ @ConfigurationProperties(prefix = "yudao.iot.plugin.common") @Validated @Data @@ -45,4 +50,10 @@ public class IotPluginCommonProperties { */ private Integer downstreamPort = DOWNSTREAM_PORT_RANDOM; + /** + * 插件包标识符 + */ + @NotEmpty(message = "插件包标识符不能为空") + private String pluginKey; + } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java index 337db248f..5051965b2 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java @@ -16,7 +16,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; /** - * IOT 设备配置设置 Vertx Handler + * IoT 设备配置设置 Vertx Handler * * 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java index f81d385dc..0d52dad49 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java @@ -5,14 +5,19 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceOt import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import io.vertx.core.json.JsonObject; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; +/** + * IoT 设备 OTA 升级 Vertx Handler + *

+ * 芋道源码 + */ @Slf4j @RequiredArgsConstructor public class IotDeviceOtaUpgradeVertxHandler implements Handler { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java index 5f9906fdc..2e99a1b62 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java @@ -16,7 +16,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; /** - * IOT 设备服务获取 Vertx Handler + * IoT 设备服务获取 Vertx Handler * * 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java index c8a60c770..c3a71ff80 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java @@ -16,7 +16,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; /** - * IOT 设备服务设置 Vertx Handler + * IoT 设备服务设置 Vertx Handler * * 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java index 421fe7484..c4fd2e504 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java @@ -5,17 +5,18 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceSe import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import io.vertx.core.json.JsonObject; + import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; /** - * IOT 设备服务调用 Vertx Handler + * IoT 设备服务调用 Vertx Handler * * 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeat/IotPluginInstanceHeartbeatJob.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeat/IotPluginInstanceHeartbeatJob.java index 238d34f98..f272468c5 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeat/IotPluginInstanceHeartbeatJob.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/heartbeat/IotPluginInstanceHeartbeatJob.java @@ -4,6 +4,7 @@ import cn.hutool.system.SystemUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO; +import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamServer; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import lombok.RequiredArgsConstructor; @@ -23,6 +24,7 @@ public class IotPluginInstanceHeartbeatJob { private final IotDeviceUpstreamApi deviceUpstreamApi; private final IotDeviceDownstreamServer deviceDownstreamServer; + private final IotPluginCommonProperties commonProperties; public void init() { CommonResult result = deviceUpstreamApi.heartbeatPluginInstance(buildPluginInstanceHeartbeatReqDTO(true)); @@ -41,9 +43,8 @@ public class IotPluginInstanceHeartbeatJob { } private IotPluginInstanceHeartbeatReqDTO buildPluginInstanceHeartbeatReqDTO(Boolean online) { - // TODO @haohao:pluginKey 的获取??? return new IotPluginInstanceHeartbeatReqDTO() - .setPluginKey("yudao-module-iot-plugin-http").setProcessId(IotPluginCommonUtils.getProcessId()) + .setPluginKey(commonProperties.getPluginKey()).setProcessId(IotPluginCommonUtils.getProcessId()) .setHostIp(SystemUtil.getHostInfo().getAddress()).setDownstreamPort(deviceDownstreamServer.getPort()) .setOnline(online); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java index ec662510b..1bf4d676c 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java @@ -57,6 +57,12 @@ public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi { return null; } + @Override + public CommonResult authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) { + String url = properties.getUpstreamUrl() + URL_PREFIX + "/authenticate-emqx-connection"; + return doPost(url, authReqDTO); + } + @Override public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { String url = properties.getUpstreamUrl() + URL_PREFIX + "/report-property"; diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java index f93717386..a632c73c7 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java @@ -41,4 +41,12 @@ public class IotPluginCommonUtils { .end(JsonUtils.toJsonString(result)); } + @SuppressWarnings("deprecation") + public static void writeJson(RoutingContext routingContext, String result) { + routingContext.response() + .setStatusCode(200) + .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .end(result); + } + } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties index 7f565b75e..565e81eb0 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties @@ -1,6 +1,6 @@ -plugin.id=plugin-emqx -plugin.class=cn.iocoder.yudao.module.iot.plugin.EmqxPlugin +plugin.id=yudao-module-iot-plugin-emqx +plugin.class=cn.iocoder.yudao.module.iot.plugin.emqx.config.IotEmqxPlugin plugin.version=1.0.0 -plugin.provider=ahh +plugin.provider=yudao plugin.dependencies= -plugin.description=plugin-emqx-1.0.0 +plugin.description=yudao-module-iot-plugin-emqx-1.0.0 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml index cd8974321..34cb91d54 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml @@ -12,6 +12,7 @@ jar yudao-module-iot-plugin-emqx + 1.0.0 ${project.artifactId} @@ -21,36 +22,16 @@ emqx-plugin - cn.iocoder.yudao.module.iot.plugin.EmqxPlugin - 0.0.1 - ahh - emqx-plugin-0.0.1 + cn.iocoder.yudao.module.iot.plugin.emqx.config.IotEmqxPlugin + ${project.version} + yudao + ${project.artifactId}-${project.version} - - + org.apache.maven.plugins maven-antrun-plugin @@ -94,6 +75,7 @@ + org.apache.maven.plugins maven-jar-plugin @@ -111,54 +93,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - maven-deploy-plugin - - true - + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + -standalone + + + + - + + cn.iocoder.boot + yudao-module-iot-plugin-common + ${revision} + + + org.springframework.boot spring-boot-starter-web - - - org.pf4j - pf4j-spring - provided - - - - cn.iocoder.boot - yudao-module-iot-api - ${revision} - - - org.projectlombok - lombok - ${lombok.version} - provided - - - - io.vertx - vertx-core - - + + io.vertx vertx-web - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java deleted file mode 100644 index b5fed5518..000000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java +++ /dev/null @@ -1,42 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - -import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.Plugin; -import org.pf4j.PluginWrapper; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -@Slf4j -public class EmqxPlugin extends Plugin { - - private ExecutorService executorService; - - public EmqxPlugin(PluginWrapper wrapper) { - super(wrapper); - this.executorService = Executors.newSingleThreadExecutor(); - } - - @Override - public void start() { - log.info("EmqxPlugin.start()"); - - if (executorService.isShutdown() || executorService.isTerminated()) { - executorService = Executors.newSingleThreadExecutor(); - } - - IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class); - if (deviceDataApi == null) { - log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); - return; - } - - } - - @Override - public void stop() { - log.info("EmqxPlugin.stop()"); - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/IotEmqxPluginApplication.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/IotEmqxPluginApplication.java new file mode 100644 index 000000000..178038417 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/IotEmqxPluginApplication.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.plugin.emqx; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * IoT Emqx 插件的独立运行入口 + */ +@Slf4j +@SpringBootApplication +public class IotEmqxPluginApplication { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(IotEmqxPluginApplication.class); + application.setWebApplicationType(WebApplicationType.NONE); + application.run(args); + log.info("[main][独立模式启动完成]"); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java new file mode 100644 index 000000000..af2e56862 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.iot.plugin.emqx.config; + +import cn.hutool.extra.spring.SpringUtil; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.PluginWrapper; +import org.pf4j.spring.SpringPlugin; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +// TODO @芋艿:完善注释 + +/** + * 负责插件的启动和停止 + */ +@Slf4j +public class IotEmqxPlugin extends SpringPlugin { + + public IotEmqxPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + log.info("[EmqxPlugin][EmqxPlugin 插件启动开始...]"); + try { + + log.info("[EmqxPlugin][EmqxPlugin 插件启动成功...]"); + } catch (Exception e) { + log.error("[EmqxPlugin][EmqxPlugin 插件开启动异常...]", e); + } + } + + @Override + public void stop() { + log.info("[EmqxPlugin][EmqxPlugin 插件停止开始...]"); + try { + log.info("[EmqxPlugin][EmqxPlugin 插件停止成功...]"); + } catch (Exception e) { + log.error("[EmqxPlugin][EmqxPlugin 插件停止异常...]", e); + } + } + + @Override + protected ApplicationContext createApplicationContext() { + // 创建插件自己的 ApplicationContext + AnnotationConfigApplicationContext pluginContext = new AnnotationConfigApplicationContext(); + // 设置父容器为主应用的 ApplicationContext (确保主应用中提供的类可用) + pluginContext.setParent(SpringUtil.getApplicationContext()); + // 继续使用插件自己的 ClassLoader 以加载插件内部的类 + pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); + // 扫描当前插件的自动配置包 + pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.emqx.config"); + pluginContext.refresh(); + return pluginContext; + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java new file mode 100644 index 000000000..4b9b104aa --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.plugin.emqx.config; + +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamServer; +import cn.iocoder.yudao.module.iot.plugin.emqx.downstream.IotDeviceDownstreamHandlerImpl; +import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.IotDeviceUpstreamServer; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * IoT 插件 Emqx 的专用自动配置类 + * + * @author haohao + */ +@Configuration +@EnableConfigurationProperties(IotPluginEmqxProperties.class) +public class IotPluginEmqxAutoConfiguration { + + @Bean(initMethod = "start", destroyMethod = "stop") + public IotDeviceUpstreamServer deviceUpstreamServer(IotDeviceUpstreamApi deviceUpstreamApi, + IotPluginCommonProperties commonProperties, + IotPluginEmqxProperties emqxProperties, + IotDeviceDownstreamServer deviceDownstreamServer) { + return new IotDeviceUpstreamServer(commonProperties, emqxProperties, deviceUpstreamApi, deviceDownstreamServer); + } + + @Bean + public IotDeviceDownstreamHandler deviceDownstreamHandler() { + return new IotDeviceDownstreamHandlerImpl(); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java new file mode 100644 index 000000000..9004e864e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.iot.plugin.emqx.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +/** + * 物联网插件 - EMQX 配置 + * + * @author 芋道源码 + */ +@ConfigurationProperties(prefix = "yudao.iot.plugin.emqx") +@Validated +@Data +public class IotPluginEmqxProperties { + + /** + * 服务主机 + */ + private String host; + + /** + * 服务端口 + */ + private int port; + + /** + * 是否启用 SSL + */ + private boolean ssl; + + /** + * 订阅的主题 + */ + private String topics; + + /** + * 认证端口 + */ + private int authPort; + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java new file mode 100644 index 000000000..1d3ccba3a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.iot.plugin.emqx.downstream; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; + +/** + * EMQX 插件的 {@link IotDeviceDownstreamHandler} 实现类 + *

+ * 但是:由于设备通过 HTTP 短链接接入,导致其实无法下行指导给 device 设备,所以基本都是直接返回失败!!! + * 类似 MQTT、WebSocket、TCP 插件,是可以实现下行指令的。 + * + * @author 芋道源码 + */ +public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandler { + + @Override + public CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO) { + return CommonResult.success(true); + } + + @Override + public CommonResult getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO) { + return CommonResult.success(true); + } + + @Override + public CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO) { + return CommonResult.success(true); + } + + @Override + public CommonResult setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO) { + return CommonResult.success(true); + } + + @Override + public CommonResult upgradeDeviceOta(IotDeviceOtaUpgradeReqDTO upgradeReqDTO) { + return CommonResult.success(true); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java new file mode 100644 index 000000000..49fdbe499 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.iot.plugin.emqx.upstream; + +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamServer; +import cn.iocoder.yudao.module.iot.plugin.emqx.config.IotPluginEmqxProperties; +import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router.IotDeviceAuthVertxHandler; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpServer; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.handler.BodyHandler; +import lombok.extern.slf4j.Slf4j; + +/** + * IoT 设备下行服务端,接收来自 device 设备的请求,转发给 server 服务器 + *

+ * 协议:HTTP + * + * @author haohao + */ +@Slf4j +public class IotDeviceUpstreamServer { + + private final Vertx vertx; + private final HttpServer server; + private final IotPluginEmqxProperties emqxProperties; + + public IotDeviceUpstreamServer(IotPluginCommonProperties commonProperties, + IotPluginEmqxProperties emqxProperties, + IotDeviceUpstreamApi deviceUpstreamApi, + IotDeviceDownstreamServer deviceDownstreamServer) { + this.emqxProperties = emqxProperties; + // 创建 Vertx 实例 + this.vertx = Vertx.vertx(); + // 创建 Router 实例 + Router router = Router.router(vertx); + router.route().handler(BodyHandler.create()); // 处理 Body + router.post(IotDeviceAuthVertxHandler.PATH) + .handler(new IotDeviceAuthVertxHandler(deviceUpstreamApi)); + // 创建 HttpServer 实例 + this.server = vertx.createHttpServer().requestHandler(router); + } + + /** + * 启动 HTTP 服务器 + */ + public void start() { + log.info("[start][开始启动]"); + server.listen(emqxProperties.getAuthPort()) + .toCompletionStage() + .toCompletableFuture() + .join(); + log.info("[start][启动完成,端口({})]", this.server.actualPort()); + } + + /** + * 停止所有 + */ + public void stop() { + log.info("[stop][开始关闭]"); + try { + // 关闭 HTTP 服务器 + if (server != null) { + server.close() + .toCompletionStage() + .toCompletableFuture() + .join(); + } + + // 关闭 Vertx 实例 + if (vertx != null) { + vertx.close() + .toCompletionStage() + .toCompletableFuture() + .join(); + } + log.info("[stop][关闭完成]"); + } catch (Exception e) { + log.error("[stop][关闭异常]", e); + throw new RuntimeException(e); + } + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java new file mode 100644 index 000000000..794949c28 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEmqxAuthReqDTO; +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * IoT Emqx 连接认证的 Vert.x Handler + * ... + * + * @author haohao + */ +@RequiredArgsConstructor +@Slf4j +public class IotDeviceAuthVertxHandler implements Handler { + + public static final String PATH = "/mqtt/auth"; + + private final IotDeviceUpstreamApi deviceUpstreamApi; + + @Override + @SuppressWarnings("unchecked") + public void handle(RoutingContext routingContext) { + + JsonObject json = routingContext.body().asJsonObject(); + String clientId = json.getString("clientid"); + String username = json.getString("username"); + String password = json.getString("password"); + + IotDeviceEmqxAuthReqDTO authReqDTO = buildDeviceEmqxAuthReqDTO(clientId, username, password); + + CommonResult authResult = deviceUpstreamApi.authenticateEmqxConnection(authReqDTO); + if (authResult.getCode() != 0 || !authResult.getData()) { + denyAccess(routingContext); + return; + } + IotPluginCommonUtils.writeJson(routingContext, "{\"result\": \"allow\"}"); + } + + private void denyAccess(RoutingContext routingContext) { + IotPluginCommonUtils.writeJson(routingContext, "{\"result\": \"deny\"}"); + } + + private IotDeviceEmqxAuthReqDTO buildDeviceEmqxAuthReqDTO(String clientId, String username, String password) { + return new IotDeviceEmqxAuthReqDTO().setClientId(clientId).setUsername(username).setPassword(password); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/resources/application.yml new file mode 100644 index 000000000..f31880f24 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/resources/application.yml @@ -0,0 +1,17 @@ +spring: + application: + name: yudao-module-iot-plugin-emqx + +yudao: + iot: + plugin: + common: + upstream-url: http://127.0.0.1:48080 + downstream-port: 8100 + plugin-key: yudao-module-iot-plugin-emqx + emqx: + host: 127.0.0.1 + port: 1883 + ssl: false + topics: "/sys/#" + auth-port: 8101 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java index 4e0a2ef44..bdb92b6ee 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java @@ -21,7 +21,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; /** - * IoT 设备设备上报的 Vert.x Handler + * IoT 设备事件上报的 Vert.x Handler */ @RequiredArgsConstructor @Slf4j diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml index 4afeb4f26..f195628a6 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml @@ -8,5 +8,6 @@ yudao: common: upstream-url: http://127.0.0.1:48080 downstream-port: 8093 + plugin-key: yudao-module-iot-plugin-http http: server-port: 8092 From 8043ce612fd9e2429c7a1d67efbf630fbd98f5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Thu, 20 Feb 2025 18:31:34 +0800 Subject: [PATCH 174/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT:=20=E6=B7=BB=E5=8A=A0=20IoT=20=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=20MQTT=20=E8=BF=9E=E6=8E=A5=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=93=8D=E5=BA=94=20VO=EF=BC=8C=E5=8C=85=E5=90=AB=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=20ID=E3=80=81=E7=94=A8=E6=88=B7=E5=90=8D?= =?UTF-8?q?=E5=92=8C=E5=AF=86=E7=A0=81=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotDeviceMqttConnectionParamsRespVO.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceMqttConnectionParamsRespVO.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceMqttConnectionParamsRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceMqttConnectionParamsRespVO.java new file mode 100644 index 000000000..5ce68c0fe --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceMqttConnectionParamsRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 设备 MQTT 连接参数 Response VO") +@Data +@ExcelIgnoreUnannotated +public class IotDeviceMqttConnectionParamsRespVO { + + @Schema(description = "MQTT 客户端 ID", example = "24602") + @ExcelProperty("MQTT 客户端 ID") + private String mqttClientId; + + @Schema(description = "MQTT 用户名", example = "芋艿") + @ExcelProperty("MQTT 用户名") + private String mqttUsername; + + @Schema(description = "MQTT 密码") + @ExcelProperty("MQTT 密码") + private String mqttPassword; + +} \ No newline at end of file From 6d059eae61f1ff74ea43dd45aabd5a55de01a7f0 Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Sat, 22 Feb 2025 16:58:47 +0800 Subject: [PATCH 175/228] =?UTF-8?q?[fix]=EF=BC=9Astatistics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../statistics/IotStatisticsController.java | 55 +++++++++++++ .../statistics/vo/IotStatisticsRespVO.java | 78 +++++++++++++++++++ .../iot/dal/mysql/device/IotDeviceMapper.java | 23 ++++++ .../product/IotProductCategoryMapper.java | 13 ++++ .../dal/mysql/product/IotProductMapper.java | 26 +++++++ .../mysql/thingmodel/IotThingModelMapper.java | 12 +++ .../iot/service/device/IotDeviceService.java | 26 ++++++- .../service/device/IotDeviceServiceImpl.java | 15 ++++ .../product/IotProductCategoryService.java | 17 ++++ .../IotProductCategoryServiceImpl.java | 59 +++++++++++++- .../service/product/IotProductService.java | 17 ++++ .../product/IotProductServiceImpl.java | 11 +++ .../thingmodel/IotThingModelService.java | 9 +++ .../thingmodel/IotThingModelServiceImpl.java | 6 ++ .../src/main/resources/application-local.yaml | 6 +- 15 files changed, 368 insertions(+), 5 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java new file mode 100644 index 000000000..4262f31cc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.iot.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.product.IotProductCategoryService; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.List; + + +@Tag(name = "管理后台 - IoT 数据统计") +@RestController +@RequestMapping("/iot/statistics") +@Validated +public class IotStatisticsController { + + @Resource + private IotDeviceService iotDeviceService; + + @Resource + private IotProductCategoryService iotProductCategoryService; + + @Resource + private IotProductService iotProductService; + + + @GetMapping("/count") + @Operation(summary = "获取IOT首页的数据统计", description = "主要用于IOT首页的数据统计") + public CommonResult getSimpleProductList(){ + IotStatisticsRespVO iotStatisticsRespVO = new IotStatisticsRespVO(); + // 获取总数 + iotStatisticsRespVO.setCategoryTotal(iotProductCategoryService.getProductCategoryCount(null)); + iotStatisticsRespVO.setProductTotal(iotProductService.getProductCount(null)); + iotStatisticsRespVO.setDeviceTotal(iotDeviceService.getDeviceCount(null)); + + // 获取今日新增数量 + LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0); + iotStatisticsRespVO.setCategoryTodayTotal(iotProductCategoryService.getProductCategoryCount(todayStart)); + iotStatisticsRespVO.setProductTodayTotal(iotProductService.getProductCount(todayStart)); + iotStatisticsRespVO.setDeviceTodayTotal(iotDeviceService.getDeviceCount(todayStart)); + + return CommonResult.success(iotStatisticsRespVO); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java new file mode 100644 index 000000000..a72c0536e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - Iot统计 Response VO") +@Data +public class IotStatisticsRespVO { + + @Schema(description = "品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private long categoryTotal; + + @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private long productTotal; + + @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private long deviceTotal; + + @Schema(description = "上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private long reportTotal; + + @Schema(description = "今日新增品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private long categoryTodayTotal; + + @Schema(description = "今日新增产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private long productTodayTotal; + + @Schema(description = "今日新增设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private long deviceTodayTotal; + + @Schema(description = "今日新增上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private long reportTodayTotal; + + @Schema(description = "在线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") + private long onlineTotal; + + @Schema(description = "离线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15") + private long offlineTotal; + + @Schema(description = "待激活设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + private long neverOnlineTotal; + + @Schema(description = "上报数据数量统计") + private List reportDataStats; + + @Schema(description = "上行数据数量统计") + private List deviceUpMessageStats; + + @Schema(description = "下行数据数量统计") + private List deviceDownMessageStats; + + @Schema(description = "按品类统计的设备数量") + private List deviceStatsOfCategory; + + @Schema(description = "时间数据") + @Data + public static class TimeData { + + @Schema(description = "时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1646092800000") + private long time; + + @Schema(description = "数据值", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + private Object data; + } + + @Schema(description = "数据项") + @Data + public static class DataItem { + + @Schema(description = "数据项名", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能家居") + private String name; + + @Schema(description = "数据项值", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + private Object value; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index a3ae4e380..e57eb8f7c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; +import java.time.LocalDateTime; import java.util.List; /** @@ -66,4 +67,26 @@ public interface IotDeviceMapper extends BaseMapperX { .orderByDesc(IotDeviceDO::getId)); } + /** + * 统计设备数量 + * + * @param createTime 创建时间,如果为空,则统计所有设备数量 + * @return 设备数量 + */ + default Long selectCountByCreateTime(LocalDateTime createTime) { + return selectCount(new LambdaQueryWrapperX() + .geIfPresent(IotDeviceDO::getCreateTime, createTime)); + } + + /** + * 统计指定状态的设备数量 + * + * @param state 状态 + * @return 设备数量 + */ + default Long selectCountByState(Integer state) { + return selectCount(new LambdaQueryWrapperX() + .eqIfPresent(IotDeviceDO::getState, state)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java index 70ad56da8..6e9deb4eb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java @@ -6,7 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import java.time.LocalDateTime; import java.util.List; /** @@ -28,4 +30,15 @@ public interface IotProductCategoryMapper extends BaseMapperX() + .geIfPresent(IotProductCategoryDO::getCreateTime, createTime)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index 0f5625100..11a255161 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -8,6 +8,9 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; +import java.time.LocalDateTime; +import java.util.List; + /** * IoT 产品 Mapper * @@ -28,4 +31,27 @@ public interface IotProductMapper extends BaseMapperX { .apply("LOWER(product_key) = {0}", productKey.toLowerCase())); } + /** + * 统计产品数量 + * + * @param createTime 创建时间,如果为空,则统计所有产品数量 + * @return 产品数量 + */ + default Long selectCountByCreateTime(LocalDateTime createTime) { + return selectCount(new LambdaQueryWrapperX() + .geIfPresent(IotProductDO::getCreateTime, createTime)); + } + + /** + * 获得产品列表,基于分类编号 + * + * @param categoryId 分类编号 + * @return 产品列表 + */ + default List selectListByCategoryId(Long categoryId) { + return selectList(new LambdaQueryWrapperX() + .eq(IotProductDO::getCategoryId, categoryId) + .orderByDesc(IotProductDO::getId)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java index 4c563c65e..21972343f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelP import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import org.apache.ibatis.annotations.Mapper; +import java.time.LocalDateTime; import java.util.List; /** @@ -72,4 +73,15 @@ public interface IotThingModelMapper extends BaseMapperX { IotThingModelDO::getName, name); } + /** + * 统计物模型数量 + * + * @param createTime 创建时间,如果为空,则统计所有物模型数量 + * @return 物模型数量 + */ + default Long selectCountByCreateTime(LocalDateTime createTime) { + return selectCount(new LambdaQueryWrapperX() + .geIfPresent(IotThingModelDO::getCreateTime, createTime)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 24532d254..fff1368c6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -7,6 +7,7 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import javax.annotation.Nullable; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; @@ -109,7 +110,7 @@ public interface IotDeviceService { IotDeviceDO getDeviceByDeviceKey(String deviceKey); /** - * ��得设备分页 + * 获得设备分页 * * @param pageReqVO 分页查询 * @return IoT 设备分页 @@ -168,4 +169,27 @@ public interface IotDeviceService { */ IotDeviceImportRespVO importDevice(List importDevices, boolean updateSupport); + /** + * 获得设备数量 + * + * @param createTime 创建时间,如果为空,则统计所有设备数量 + * @return 设备数量 + */ + Long getDeviceCount(LocalDateTime createTime); + + /** + * 获得设备数量,基于状态 + * + * @param state 状态 + * @return 设备数量 + */ + Long getDeviceCountByState(Integer state); + + /** + * 获得所有设备列表 + * + * @return 设备列表 + */ + List getDeviceList(); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 66854e84b..52766d37a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -434,4 +434,19 @@ public class IotDeviceServiceImpl implements IotDeviceService { return SpringUtil.getBean(getClass()); } + @Override + public Long getDeviceCount(LocalDateTime createTime) { + return deviceMapper.selectCountByCreateTime(createTime); + } + + @Override + public Long getDeviceCountByState(Integer state) { + return deviceMapper.selectCountByState(state); + } + + @Override + public List getDeviceList() { + return deviceMapper.selectList(); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java index e44b6d487..546c0231a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProdu import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import jakarta.validation.Valid; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; import java.util.Map; @@ -83,4 +84,20 @@ public interface IotProductCategoryService { */ List getProductCategoryListByStatus(Integer status); + /** + * 获得产品分类数量 + * + * @param createTime 创建时间,如果为空,则统计所有分类数量 + * @return 产品分类数量 + */ + Long getProductCategoryCount(LocalDateTime createTime); + + + /** + * 获得各产品分类下属的设备总数 + * + * @return 产品分类名称和各产品分类下属的设备总数 + */ + Map getDeviceCountsOfProductCategoryMap(); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java index c531b1450..683dad1b7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java @@ -5,14 +5,20 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductCategoryMapper; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.time.LocalDateTime; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS; @@ -29,7 +35,12 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService @Resource private IotProductCategoryMapper productCategoryMapper; - @Override + @Resource + private IotProductService productService; + + @Resource + private IotDeviceService deviceService; + public Long createProductCategory(IotProductCategorySaveReqVO createReqVO) { // 插入 IotProductCategoryDO productCategory = BeanUtils.toBean(createReqVO, IotProductCategoryDO.class); @@ -84,4 +95,50 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService return productCategoryMapper.selectListByStatus(status); } + @Override + public Long getProductCategoryCount(LocalDateTime createTime) { + return productCategoryMapper.selectCountByCreateTime(createTime); + } + + @Override + public Map getDeviceCountsOfProductCategoryMap() { + // 1. 获取所有数据 + List categoryList = productCategoryMapper.selectList(); + List productList = productService.getProductList(); + List deviceList = deviceService.getDeviceList(); + + // 2. 统计每个分类下的设备数量 + Map categoryDeviceCountMap = new HashMap<>(); + + // 2.1 初始化所有分类的计数为0 + for (IotProductCategoryDO category : categoryList) { + categoryDeviceCountMap.put(category.getName(), 0); + } + + // 2.2 构建产品ID到分类的映射 + Map productCategoryMap = new HashMap<>(); + for (IotProductDO product : productList) { + Long categoryId = product.getCategoryId(); + IotProductCategoryDO category = categoryList.stream() + .filter(c -> c.getId().equals(categoryId)) + .findFirst() + .orElse(null); + if (category != null) { + productCategoryMap.put(product.getId(), category); + } + } + + // 2.3 统计每个分类下的设备数量 + for (IotDeviceDO device : deviceList) { + Long productId = device.getProductId(); + IotProductCategoryDO category = productCategoryMap.get(productId); + if (category != null) { + String categoryName = category.getName(); + categoryDeviceCountMap.merge(categoryName, 1, Integer::sum); + } + } + + return categoryDeviceCountMap; + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index a317cacae..590db15a8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import jakarta.validation.Valid; +import java.time.LocalDateTime; import java.util.List; /** @@ -92,4 +93,20 @@ public interface IotProductService { */ List getProductList(); + /** + * 获得产品数量 + * + * @param createTime 创建时间,如果为空,则统计所有产品数量 + * @return 产品数量 + */ + Long getProductCount(LocalDateTime createTime); + + /** + * 获得产品列表,基于分类编号 + * + * @param categoryId 分类编号 + * @return 产品列表 + */ + List getProductListByCategoryId(Long categoryId); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index b77a7e0e1..848da74d6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -15,6 +15,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.time.LocalDateTime; import java.util.List; import java.util.Objects; @@ -137,4 +138,14 @@ public class IotProductServiceImpl implements IotProductService { return productMapper.selectList(); } + @Override + public Long getProductCount(LocalDateTime createTime) { + return productMapper.selectCountByCreateTime(createTime); + } + + @Override + public List getProductListByCategoryId(Long categoryId) { + return productMapper.selectListByCategoryId(categoryId); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java index 92aa5978c..6eb8bb346 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelS import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import jakarta.validation.Valid; +import java.time.LocalDateTime; import java.util.List; /** @@ -80,4 +81,12 @@ public interface IotThingModelService { */ List getThingModelList(IotThingModelListReqVO reqVO); + /** + * 获得物模型数量 + * + * @param createTime 创建时间,如果为空,则统计所有物模型数量 + * @return 物模型数量 + */ + Long getThingModelCount(LocalDateTime createTime); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index b9167e4ef..813b5ea58 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -29,6 +29,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.time.LocalDateTime; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -363,4 +364,9 @@ public class IotThingModelServiceImpl implements IotThingModelService { return SpringUtil.getBean(getClass()); } + @Override + public Long getThingModelCount(LocalDateTime createTime) { + return thingModelMapper.selectCountByCreateTime(createTime); + } + } diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index bbb94772c..047238dd2 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -78,10 +78,10 @@ spring: # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: redis: - host: 127.0.0.1 # 地址 + host: chaojiniu.top # 地址 port: 6379 # 端口 - database: 1 # 数据库索引 - # password: 123456 # 密码,建议生产环境开启 + database: 15 # 数据库索引 + password: fsknKD7UvQYZsyf2hXXn # 密码,建议生产环境开启 --- #################### 定时任务相关配置 #################### From fa40ae1dbd368628a9e8a0ef0b6e0636be61ee45 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 22 Feb 2025 18:21:18 +0800 Subject: [PATCH 176/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9AMQTT=20=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/api/device/IotDeviceUpstreamApi.java | 1 + .../control/upstream/IotDeviceEmqxAuthReqDTO.java | 1 + .../controller/admin/device/IotDeviceController.java | 1 + .../iot/service/device/IotDeviceServiceImpl.java | 4 +--- .../device/control/IotDeviceUpstreamServiceImpl.java | 2 ++ .../iocoder/yudao/module/iot/util/MqttSignUtils.java | 12 +++++++++--- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java index c43a0f2b2..e88706ac5 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java @@ -71,6 +71,7 @@ public interface IotDeviceUpstreamApi { @PostMapping(PREFIX + "/add-topology") CommonResult addDeviceTopology(@Valid @RequestBody IotDeviceTopologyAddReqDTO addReqDTO); + // TODO @芋艿:考虑 http 认证 /** * 认证 Emqx 连接 * diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java index 365552db0..2fb10a076 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; import jakarta.validation.constraints.NotEmpty; import lombok.Data; +// TODO @芋艿:要不要继承 IotDeviceUpstreamAbstractReqDTO /** * IoT 认证 Emqx 连接 Request DTO * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 18aa5a34f..2add4ee13 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -177,6 +177,7 @@ public class IotDeviceController { return success(true); } + // TODO @haohao:是不是默认详情接口,不返回 secret,然后这个接口,用于统一返回。然后接口名可以更通用一点。 @GetMapping("/mqtt-connection-params") @Operation(summary = "获取 MQTT 连接参数") @PreAuthorize("@ss.hasPermission('iot:device:mqtt-connection-params')") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 847581512..66d3cf861 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -123,9 +123,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { private void initDevice(IotDeviceDO device, IotProductDO product) { device.setProductId(product.getId()).setProductKey(product.getProductKey()) .setDeviceType(product.getDeviceType()); - // 生成并设置必要的字段 - // TODO @芋艿:各种 mqtt 是不是可以简化! - // clientId、username、password 根据规则实时生成 + // 生成密钥 device.setDeviceSecret(generateDeviceSecret()); // 设置设备状态为未激活 device.setState(IotDeviceStateEnum.INACTIVE.getState()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index 93b4ea388..9ce0efbb1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -280,6 +280,7 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { sendDeviceMessage(message, device); } + // TODO @haohao:建议返回 boolean; @Override public Boolean authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) { log.info("[authenticateEmqxConnection][认证 Emqx 连接: {}]", authReqDTO); @@ -303,6 +304,7 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { String deviceSecret = device.getDeviceSecret(); String clientId = authReqDTO.getClientId(); MqttSignResult sign = MqttSignUtils.calculate(productKey, deviceName, deviceSecret, clientId); + // TODO @haohao:notEquals,尽量不走取反逻辑哈 if (!StrUtil.equals(sign.getPassword(), authReqDTO.getPassword())) { log.error("[authenticateEmqxConnection][认证失败,密码不正确]"); return Boolean.FALSE; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java index 40213e3ae..bf364c53e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java @@ -8,12 +8,15 @@ import java.nio.charset.StandardCharsets; /** * MQTT 签名工具类 - * 提供静态方法来计算 MQTT 连接参数。 + * + * 提供静态方法来计算 MQTT 连接参数 */ public class MqttSignUtils { private static final String SIGN_METHOD = "hmacsha256"; + // TODO @haohao:calculate 方法,可以融合么? + /** * 计算 MQTT 连接参数 * @@ -25,11 +28,11 @@ public class MqttSignUtils { public static MqttSignResult calculate(String productKey, String deviceName, String deviceSecret) { String clientId = productKey + "." + deviceName; String username = deviceName + "&" + productKey; + // 生成 password + // TODO @haohao:signContent 和 signContentBuilder 风格保持统一的实现哈 String signContent = String.format("clientId%sdeviceName%sdeviceSecret%sproductKey%s", clientId, deviceName, deviceSecret, productKey); - String password = sign(signContent, deviceSecret); - return new MqttSignResult(clientId, username, password); } @@ -54,6 +57,7 @@ public class MqttSignUtils { return new MqttSignResult(clientId, username, password); } + // TODO @haohao:hutool 貌似有工具类可以用哈。 private static String sign(String content, String key) { try { Mac mac = Mac.getInstance(SIGN_METHOD); @@ -81,7 +85,9 @@ public class MqttSignUtils { * MQTT 签名结果类 */ @Getter + // TODO @haohao:可以用 lombok 哈 public static class MqttSignResult { + private final String clientId; private final String username; private final String password; From f76843573ee25546b829b5a1209bba9b2ffcb12f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 22 Feb 2025 18:31:09 +0800 Subject: [PATCH 177/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=95=B0=E6=8D=AE=E6=A1=A5?= =?UTF-8?q?=E6=A2=81=E7=9A=84=E6=89=A7=E8=A1=8C=E5=99=A8=E6=8A=BD=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rule/action/IotRuleSceneDataBridgeAction.java | 7 ++----- .../databridge}/IotDataBridgeExecute.java | 2 +- .../databridge}/IotHttpDataBridgeExecute.java | 2 +- .../databridge}/IotRocketMQDataBridgeExecute.java | 12 ++++++++---- 4 files changed, 12 insertions(+), 11 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{execute => action/databridge}/IotDataBridgeExecute.java (92%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{execute => action/databridge}/IotHttpDataBridgeExecute.java (98%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{execute => action/databridge}/IotRocketMQDataBridgeExecute.java (92%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index f87cd6001..6733331cb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; -import cn.iocoder.yudao.module.iot.service.rule.execute.IotDataBridgeExecute; +import cn.iocoder.yudao.module.iot.service.rule.action.databridge.IotDataBridgeExecute; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -19,9 +19,6 @@ import java.util.List; * * @author 芋道源码 */ -// TODO @芋艿:【优化】因为 bridge 会比较多,所以可以考虑在 rule 下,新建一个 bridge 的 package,然后定义一个 bridgehandler,它有: -// 1. input 方法、output 方法 -// 2. build 方法,用于有状态的连接,例如说 mq、tcp、websocket @Component @Slf4j public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { @@ -49,7 +46,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { return; } - // 2.1 执行数据桥接操作 + // 2. 执行数据桥接操作 dataBridgeExecutes.forEach(execute -> execute.execute(message, dataBridge)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java similarity index 92% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java index 8979d2115..cd00f4f3e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.service.rule.execute; +package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotHttpDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java similarity index 98% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotHttpDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java index 861fadd6c..76f1b793f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotHttpDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.service.rule.execute; +package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.http.HttpUtils; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java similarity index 92% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index 11ca2339c..626208e18 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/execute/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.service.rule.execute; +package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; @@ -30,12 +30,13 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { /** * 针对 {@link IotDataBridgeDO.RocketMQConfig} 的 DefaultMQProducer 缓存 */ + // TODO @puhui999:因为 kafka 之类也存在这个情况,是不是得搞个抽象类。提供一个 initProducer,和 closeProducer 方法 private final LoadingCache PRODUCER_CACHE = CacheBuilder.newBuilder() - // 只阻塞当前数据加载线程,其他线程返回旧值 - .refreshAfterWrite(Duration.ofMinutes(10)) + .refreshAfterWrite(Duration.ofMinutes(10)) // TODO puhui999:应该是 read 30 分钟哈 // 增加移除监听器,自动关闭 producer .removalListener(notification -> { DefaultMQProducer producer = (DefaultMQProducer) notification.getValue(); + // TODO puhui999:if return,更简短哈 if (producer != null) { try { producer.shutdown(); @@ -45,8 +46,10 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { } } }) + // TODO @puhui999:就同步哈,不用异步处理。 // 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程 .build(CacheLoader.asyncReloading(new CacheLoader() { + @Override public DefaultMQProducer load(IotDataBridgeDO.RocketMQConfig config) throws Exception { DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); @@ -55,6 +58,7 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config); return producer; } + }, Executors.newCachedThreadPool())); @Override @@ -120,7 +124,7 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { log.info("[main][第一次执行,应该会创建新的 producer]"); action.executeRocketMQ(message, config); - log.info("[main][第二次执行,应该会复用缓存的 producer]"); + log.info("[main][第二次执行,应该会复用缓存的 producer]"); action.executeRocketMQ(message, config); } From 8cf8af1f6d2dc490da99e386afc4775f3d36c36d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 22 Feb 2025 19:51:13 +0800 Subject: [PATCH 178/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E5=9B=BA=E4=BB=B6=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 3 ++ .../admin/ota/IotOtaFirmwareController.java | 10 ++--- .../ota/IotOtaUpgradeRecordController.java | 19 ++++---- .../ota/IotOtaUpgradeTaskController.java | 1 + .../firmware/IotOtaFirmwareCommonReqVO.java | 1 + .../firmware/IotOtaFirmwareCreateReqVO.java | 8 +++- .../vo/firmware/IotOtaFirmwarePageReqVO.java | 2 +- .../ota/vo/firmware/IotOtaFirmwareRespVO.java | 2 +- .../record/IotOtaUpgradeRecordPageReqVO.java | 1 + .../task/IotOtaUpgradeTaskSaveReqVO.java | 1 + .../ota/IotOtaUpgradeRecordConvert.java | 3 +- .../dataobject/ota/IotOtaUpgradeTaskDO.java | 2 + .../iot/dal/mysql/device/IotDeviceMapper.java | 3 +- .../dal/mysql/ota/IotOtaFirmwareMapper.java | 15 +++---- .../mysql/ota/IotOtaUpgradeRecordMapper.java | 4 +- .../mysql/ota/IotOtaUpgradeTaskMapper.java | 9 ++-- .../iot/job/ota/IotOtaUpgradeRecordJob.java | 5 ++- .../iot/job/ota/IotOtaUpgradeTaskJob.java | 1 + .../service/ota/IotOtaFirmwareService.java | 1 + .../ota/IotOtaFirmwareServiceImpl.java | 19 +++++--- .../ota/IotOtaUpgradeRecordService.java | 22 ++++----- .../ota/IotOtaUpgradeRecordServiceImpl.java | 23 ++++++---- .../service/ota/IotOtaUpgradeTaskService.java | 1 + .../ota/IotOtaUpgradeTaskServiceImpl.java | 45 ++++++++++++------- .../IotOtaUpgradeRecordCreateReqBO.java | 2 +- .../IotOtaUpgradeRecordUpdateReqBO.java | 3 +- .../iot/service/ota/bo/package-info.java | 1 - .../service/ota/bo/upgrade/package-info.java | 1 - .../mapper/ota/IotOtaUpgradeRecordMapper.xml | 2 + 29 files changed, 128 insertions(+), 82 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/{upgrade/record => }/IotOtaUpgradeRecordCreateReqBO.java (96%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/{upgrade/record => }/IotOtaUpgradeRecordUpdateReqBO.java (93%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/package-info.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/package-info.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 96e01394a..74fbb8b2e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -52,14 +52,17 @@ public interface ErrorCodeConstants { // ========== 插件实例 1-050-007-000 ========== // ========== 固件相关 1-050-008-000 ========== + ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在"); ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复"); + // TODO @li:1_050_008_100,这样有点间隔? ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_002, "升级任务不存在"); ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_003, "升级任务名称重复"); ErrorCode OTA_UPGRADE_TASK_PARAMS_INVALID = new ErrorCode(1_050_008_004, "升级任务参数无效"); ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_005, "升级任务不能取消"); + // TODO @li:1_050_008_200 ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_006, "升级记录不存在"); ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_007, "升级记录重复"); ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_008, "升级记录不能重试"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java index 2771e35b5..344a1e3fc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java @@ -21,7 +21,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Validated @RestController -@Tag(name = "管理后台 - IoT OTA固件") +@Tag(name = "管理后台 - IoT OTA 固件") @RequestMapping("/iot/ota-firmware") public class IotOtaFirmwareController { @@ -29,14 +29,14 @@ public class IotOtaFirmwareController { private IotOtaFirmwareService otaFirmwareService; @PostMapping("/create") - @Operation(summary = "创建OTA固件") + @Operation(summary = "创建 OTA 固件") @PreAuthorize("@ss.hasPermission('iot:ota-firmware:create')") public CommonResult createOtaFirmware(@Valid @RequestBody IotOtaFirmwareCreateReqVO createReqVO) { return success(otaFirmwareService.createOtaFirmware(createReqVO)); } @PutMapping("/update") - @Operation(summary = "更新OTA固件") + @Operation(summary = "更新 OTA 固件") @PreAuthorize("@ss.hasPermission('iot:ota-firmware:update')") public CommonResult updateOtaFirmware(@Valid @RequestBody IotOtaFirmwareUpdateReqVO updateReqVO) { otaFirmwareService.updateOtaFirmware(updateReqVO); @@ -44,7 +44,7 @@ public class IotOtaFirmwareController { } @GetMapping("/get") - @Operation(summary = "获得OTA固件") + @Operation(summary = "获得 OTA 固件") @PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')") public CommonResult getOtaFirmware(@RequestParam("id") Long id) { IotOtaFirmwareDO otaFirmware = otaFirmwareService.getOtaFirmware(id); @@ -52,7 +52,7 @@ public class IotOtaFirmwareController { } @GetMapping("/page") - @Operation(summary = "获得OTA固件分页") + @Operation(summary = "获得 OTA 固件分页") @PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')") public CommonResult> getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO) { PageResult pageResult = otaFirmwareService.getOtaFirmwarePage(pageReqVO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java index e28f721c8..dcff39648 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java @@ -22,21 +22,13 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Validated @RestController -@Tag(name = "管理后台 - OTA升级记录") +@Tag(name = "管理后台 - OTA 升级记录") @RequestMapping("/iot/ota-upgrade-record") public class IotOtaUpgradeRecordController { @Resource private IotOtaUpgradeRecordService upgradeRecordService; - @GetMapping("/get-count") - @Operation(summary = "获得升级记录 分页 tab count") - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") - public CommonResult> getOtaUpgradeRecordCount( - @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) { - return success(upgradeRecordService.getOtaUpgradeRecordCount(pageReqVO)); - } - @GetMapping("/get-statistics") @Operation(summary = "固件升级设备统计") @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") @@ -46,6 +38,14 @@ public class IotOtaUpgradeRecordController { return success(upgradeRecordService.getOtaUpgradeRecordStatistics(firmwareId)); } + @GetMapping("/get-count") + @Operation(summary = "获得升级记录分页 tab 数量") + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") + public CommonResult> getOtaUpgradeRecordCount( + @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) { + return success(upgradeRecordService.getOtaUpgradeRecordCount(pageReqVO)); + } + @GetMapping("/page") @Operation(summary = "获得升级记录分页") @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") @@ -64,6 +64,7 @@ public class IotOtaUpgradeRecordController { return success(BeanUtils.toBean(upgradeRecord, IotOtaUpgradeRecordRespVO.class)); } + // TODO @li:使用 Putmapping @PostMapping("/retry") @Operation(summary = "重试升级记录") @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:retry')") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java index 20216fecc..4f560d5b5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java @@ -44,6 +44,7 @@ public class IotOtaUpgradeTaskController { return success(true); } + // TODO @li:get 接口,不是 @RequestBody 哈 @GetMapping("/page") @Operation(summary = "获得升级任务分页") @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java index 01f10caa5..2799907ce 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java @@ -6,6 +6,7 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; +// TODO @li:因为 create 和 update 可以公用的字段比较少,建议不用 IotOtaFirmwareCommonReqVO @Data @Schema(description = "管理后台 - OTA固件信息 Request VO") public class IotOtaFirmwareCommonReqVO { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java index 44d942c63..b194cde77 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java @@ -7,10 +7,13 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; -@Data +// TODO @li:中英文之间,有个空格。中文写作习惯哈。 @Schema(description = "管理后台 - OTA固件创建 Request VO") +@Data public class IotOtaFirmwareCreateReqVO extends IotOtaFirmwareCommonReqVO { + // TODO @li:因为有了注解,注释可以不写哈 + // TODO @li:swagger 注解,写在 validator 注解之前,保持项目统一哈。 /** * 版本号 */ @@ -27,6 +30,7 @@ public class IotOtaFirmwareCreateReqVO extends IotOtaFirmwareCommonReqVO { @Schema(description = "产品编号", requiredMode = REQUIRED, example = "1024") private String productId; + // TODO @li:productId 即可,而 productKey 通过 productId 查询 /** * 产品标识 *

@@ -44,6 +48,8 @@ public class IotOtaFirmwareCreateReqVO extends IotOtaFirmwareCommonReqVO { @Schema(description = "签名方式", example = "MD5") private String signMethod; + // TODO @li:fileSign、fileSize 通过后端下载文件,计算出来。对前端屏蔽这个细节。 + /** * 固件文件签名 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java index 8ae3e5199..24304202c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java @@ -5,7 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data -@Schema(description = "管理后台 - OTA固件分页 Request VO") +@Schema(description = "管理后台 - OTA 固件分页 Request VO") public class IotOtaFirmwarePageReqVO extends PageParam { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java index 767ba7713..f9aa25cca 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java @@ -10,7 +10,7 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Data -@Schema(description = "管理后台 - OTA固件 Response VO") +@Schema(description = "管理后台 - OTA 固件 Response VO") public class IotOtaFirmwareRespVO implements VO { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java index c7c55e4ca..6e083a332 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java @@ -11,6 +11,7 @@ import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Schema(description = "管理后台 - OTA升级记录分页 Request VO") public class IotOtaUpgradeRecordPageReqVO extends PageParam { + // TODO @li:使用 IotOtaUpgradeRecordStatusEnum 枚举哈 /** * 待处理状态 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java index c7da7565f..7cb25299f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java @@ -57,6 +57,7 @@ public class IotOtaUpgradeTaskSaveReqVO { @Schema(description = "选中的设备编号数组", requiredMode = REQUIRED, example = "[1,2,3,4]") private List deviceIds; + // TODO @li:通过 deviceIds 查询 deviceNames,前端不传递哈 /** * 选中的设备名字数组 *

diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java index 66ff07e3a..2da9315f7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; -import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordCreateReqBO; +import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordCreateReqBO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -16,6 +16,7 @@ public interface IotOtaUpgradeRecordConvert { IotOtaUpgradeRecordConvert INSTANCE = Mappers.getMapper(IotOtaUpgradeRecordConvert.class); + // TODO @li:一般情况下,这种 convert 直接写 service 就好啦。不用特别写一个哈 default List convertBOList(IotOtaUpgradeTaskDO upgradeTask, IotOtaFirmwareDO firmware, List deviceList) { return deviceList.stream().map(device -> { IotOtaUpgradeRecordCreateReqBO createReqBO = new IotOtaUpgradeRecordCreateReqBO(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java index 1f300cfcc..e98e6c15c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java @@ -70,6 +70,8 @@ public class IotOtaUpgradeTaskDO extends BaseDO { */ @TableField(typeHandler = JacksonTypeHandler.class) private List deviceIds; + + // TODO @li:这个通过查询,不用冗余 /** * 选中的设备名字数组 *

diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index e56efb879..cd7d157a8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -66,8 +66,7 @@ public interface IotDeviceMapper extends BaseMapperX { default Long selectCountByGroupId(Long groupId) { return selectCount(new LambdaQueryWrapperX() - .apply("FIND_IN_SET(" + groupId + ",group_ids) > 0") - .orderByDesc(IotDeviceDO::getId)); + .apply("FIND_IN_SET(" + groupId + ",group_ids) > 0")); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java index 36e7c61cd..9bd461916 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java @@ -9,6 +9,7 @@ import org.apache.ibatis.annotations.Mapper; import java.util.List; +// TODO @li:这里的注释,可以去掉哈,多了点点 /** * IotOtaFirmwareMapper 接口用于操作 IotOtaFirmwareDO 实体类对应的数据库表。 * 该接口继承自 BaseMapperX,提供了基本的 CRUD 操作,并扩展了特定查询方法。 @@ -24,9 +25,8 @@ public interface IotOtaFirmwareMapper extends BaseMapperX { * @return 返回符合条件的固件信息列表。 */ default List selectByProductIdAndVersion(String productId, String version) { - return selectList(new LambdaQueryWrapperX() - .eq(IotOtaFirmwareDO::getProductId, productId) - .eq(IotOtaFirmwareDO::getVersion, version)); + return selectList(IotOtaFirmwareDO::getProductId, productId, + IotOtaFirmwareDO::getVersion, version); } /** @@ -36,11 +36,10 @@ public interface IotOtaFirmwareMapper extends BaseMapperX { * @return 返回分页查询结果,包含符合条件的固件信息列表。 */ default PageResult selectPage(IotOtaFirmwarePageReqVO pageReqVO) { - return selectPage(pageReqVO, - new LambdaQueryWrapperX() - .likeIfPresent(IotOtaFirmwareDO::getName, pageReqVO.getName()) - .eqIfPresent(IotOtaFirmwareDO::getProductId, pageReqVO.getProductId()) - .orderByDesc(IotOtaFirmwareDO::getCreateTime)); + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotOtaFirmwareDO::getName, pageReqVO.getName()) + .eqIfPresent(IotOtaFirmwareDO::getProductId, pageReqVO.getProductId()) + .orderByDesc(IotOtaFirmwareDO::getCreateTime)); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java index 4f990fc21..35a164ca2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -12,8 +12,9 @@ import org.apache.ibatis.annotations.Param; import java.util.List; +// TODO @li:这里的注释,可以去掉哈,多了点点 /** - * OTA升级记录 Mapper 接口 + * OTA 升级记录 Mapper 接口 */ @Mapper public interface IotOtaUpgradeRecordMapper extends BaseMapperX { @@ -78,6 +79,7 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX() .set(IotOtaUpgradeRecordDO::getStatus, IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()) .eq(IotOtaUpgradeRecordDO::getTaskId, taskId) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java index 9cee6e19a..80c3ff565 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java @@ -9,6 +9,7 @@ import org.apache.ibatis.annotations.Mapper; import java.util.List; +// TODO @li:这里的注释,可以去掉哈,多了点点 /** * IotOtaUpgradeTaskMapper 接口用于操作 IotOtaUpgradeTaskDO 数据库表。 * 该接口继承自 BaseMapperX,提供了基本的数据库操作方法。 @@ -46,13 +47,11 @@ public interface IotOtaUpgradeTaskMapper extends BaseMapperX * 该函数通过传入的任务状态,查询数据库中符合条件的升级任务列表。 * - * @param state 任务状态,用于筛选升级任务的状态值 + * @param status 任务状态,用于筛选升级任务的状态值 * @return 返回符合条件的升级任务列表,列表中的每个元素为 IotOtaUpgradeTaskDO 对象 */ - default List selectUpgradeTaskByState(Integer state) { - // 使用 LambdaQueryWrapperX 构建查询条件,筛选出状态等于指定值的升级任务 - return selectList(new LambdaQueryWrapperX() - .eq(IotOtaUpgradeTaskDO::getStatus, state)); + default List selectUpgradeTaskByState(Integer status) { + return selectList(IotOtaUpgradeTaskDO::getStatus, status); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java index d04818d5c..86c44db8b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java @@ -19,13 +19,14 @@ public class IotOtaUpgradeRecordJob implements JobHandler { @Override @TenantJob public String execute(String param) throws Exception { - // 1.查询待处理的升级记录 + // 1. 查询待处理的升级记录 List upgradeRecords = upgradeRecordService .getUpgradeRecordListByState(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); // TODO @芋艿 2.执行升级动作 + // TODO @li:应该是逐条 push,逐条更新。不用批量哈 - // 3.最终,更新升级记录状态 + // 3. 最终,更新升级记录状态 List ids = upgradeRecords.stream().map(IotOtaUpgradeRecordDO::getId).toList(); upgradeRecordService.updateUpgradeRecordStatus(ids, IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus()); return ""; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java index 8b809c674..5465161f9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java @@ -15,6 +15,7 @@ import org.springframework.stereotype.Component; import java.util.List; +// TODO @li:也不用通过 job 去统计。可以通过 record update status 后,主动去更新 task 的状态。 @Slf4j @Component public class IotOtaUpgradeTaskJob implements JobHandler { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java index 659b3039f..67e14ce6a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import jakarta.validation.Valid; +// TODO @li:类、方法注释有点冗余,可以参考别的模块哈 /** * OTA固件管理服务接口 * 提供OTA固件的创建、更新和查询等功能 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java index 76930e1dc..56a830b91 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java @@ -29,18 +29,22 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @Override public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) { - // 1.校验固件产品id+版本号不能重复 + // 1. 校验固件产品 + 版本号不能重复 + // TODO @li:需要考虑设备也存在 validateProductAndVersionDuplicate(saveReqVO.getProductId(), saveReqVO.getVersion()); + // 2.转化数据格式,准备存储到数据库中 - IotOtaFirmwareDO otaFirmware = BeanUtils.toBean(saveReqVO, IotOtaFirmwareDO.class); - otaFirmwareMapper.insert(otaFirmware); - return otaFirmware.getId(); + IotOtaFirmwareDO firmware = BeanUtils.toBean(saveReqVO, IotOtaFirmwareDO.class); + otaFirmwareMapper.insert(firmware); + return firmware.getId(); } @Override public void updateOtaFirmware(IotOtaFirmwareUpdateReqVO updateReqVO) { + // TODO @li:如果序号只有一个,直接写 1. 更好哈 // 1.1. 校验存在 validateFirmwareExists(updateReqVO.getId()); + // 2. 更新数据 IotOtaFirmwareDO updateObj = BeanUtils.toBean(updateReqVO, IotOtaFirmwareDO.class); otaFirmwareMapper.updateById(updateObj); @@ -58,11 +62,11 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @Override public IotOtaFirmwareDO validateFirmwareExists(Long id) { - IotOtaFirmwareDO otaFirmware = otaFirmwareMapper.selectById(id); - if (otaFirmware == null) { + IotOtaFirmwareDO firmware = otaFirmwareMapper.selectById(id); + if (firmware == null) { throw exception(OTA_FIRMWARE_NOT_EXISTS); } - return otaFirmware; + return firmware; } /** @@ -80,6 +84,7 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { // 查询数据库中是否存在具有相同产品ID和版本号的固件信息 List list = otaFirmwareMapper.selectByProductIdAndVersion(productId, version); // 如果查询结果非空且不为null,则抛出异常,提示固件信息已存在 + // TODO @li:使用 isNotEmpty 这种 方法,简化 if (Objects.nonNull(list) && !list.isEmpty()) { throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java index 18bf63e83..ea5de4a42 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; -import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordCreateReqBO; -import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordUpdateReqBO; +import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordCreateReqBO; +import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordUpdateReqBO; import jakarta.validation.Valid; import java.util.List; @@ -16,18 +16,21 @@ import java.util.Map; */ public interface IotOtaUpgradeRecordService { + // TODO @createOtaUpgradeRecordBatch 哈,需要补充方法里,缺少 Ota 关键字的 + /** * 批量创建物联网OTA升级记录 *

* 该函数用于处理一组物联网OTA升级记录的创建请求,并将这些记录批量保存到系统中。 * - * @param saveList 包含多个物联网OTA升级记录创建请求的列表,每个请求对象都经过校验(@Valid注解确保) + * @param createList 包含多个物联网OTA升级记录创建请求的列表,每个请求对象都经过校验(@Valid注解确保) * 列表中的每个元素都是IotOtaUpgradeRecordCreateReqBO类型的对象,表示一个独立的升级记录创建请求。 */ - void createUpgradeRecordBatch(@Valid List saveList); + void createUpgradeRecordBatch(@Valid List createList); + // TODO @li:尽量避免写比较大的通用 update。而是根据场景提供,这样才能收敛 /** - * 更新现有的OTA升级记录。 + * 更新现有的 OTA 升级记录 * * @param updateReqBO 包含更新升级记录所需信息的请求对象,必须经过验证。 */ @@ -36,14 +39,14 @@ public interface IotOtaUpgradeRecordService { /** * 获取OTA升级记录的数量统计。 * - * @return 返回一个Map,其中键为状态码,值为对应状态的升级记录数量。 + * @return 返回一个 Map,其中键为状态码,值为对应状态的升级记录数量 */ Map getOtaUpgradeRecordCount(@Valid IotOtaUpgradeRecordPageReqVO pageReqVO); /** - * 获取OTA升级记录的统计信息。 + * 获取 OTA 升级记录的统计信息。 * - * @return 返回一个Map,其中键为状态码,值为对应状态的升级记录统计信息。 + * @return 返回一个 Map,其中键为状态码,值为对应状态的升级记录统计信息 */ Map getOtaUpgradeRecordStatistics(Long firmwareId); @@ -68,8 +71,7 @@ public interface IotOtaUpgradeRecordService { * @param pageReqVO 包含分页查询条件的请求对象,必须经过验证。 * @return 返回包含分页查询结果的响应对象。 */ - PageResult getUpgradeRecordPage( - @Valid IotOtaUpgradeRecordPageReqVO pageReqVO); + PageResult getUpgradeRecordPage(@Valid IotOtaUpgradeRecordPageReqVO pageReqVO); /** * 根据任务ID取消升级记录。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java index 71168cd2d..ae2b68273 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java @@ -7,8 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOta import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeRecordMapper; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; -import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordCreateReqBO; -import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordUpdateReqBO; +import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordCreateReqBO; +import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordUpdateReqBO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -30,21 +30,22 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic private IotOtaUpgradeRecordMapper upgradeRecordMapper; @Override - public void createUpgradeRecordBatch(List saveList) { + public void createUpgradeRecordBatch(List createList) { // 1. 批量校验参数信息 - saveList.forEach(saveBO -> validateUpgradeRecordDuplicate(saveBO.getFirmwareId(), saveBO.getTaskId(), saveBO.getDeviceId())); - // 2.将数据转化成数据库存储的格式 - List upgradeRecords = BeanUtils.toBean(saveList, IotOtaUpgradeRecordDO.class); - // 3.将数据批量存储到数据库里 + createList.forEach(saveBO -> validateUpgradeRecordDuplicate(saveBO.getFirmwareId(), saveBO.getTaskId(), saveBO.getDeviceId())); + + // 2. 将数据批量存储到数据库里 + List upgradeRecords = BeanUtils.toBean(createList, IotOtaUpgradeRecordDO.class); upgradeRecordMapper.insertBatch(upgradeRecords); } @Override @Transactional public void updateUpgradeRecord(IotOtaUpgradeRecordUpdateReqBO updateReqBO) { - // 1.校验升级记录信息是否存在 + // 1. 校验升级记录信息是否存在 validateUpgradeRecordExists(updateReqBO.getId()); - // 2.将数据转化成数据库存储的格式 + + // 2. 将数据转化成数据库存储的格式 IotOtaUpgradeRecordDO updateRecord = BeanUtils.toBean(updateReqBO, IotOtaUpgradeRecordDO.class); upgradeRecordMapper.updateById(updateRecord); // TODO @芋艿: 更新升级记录触发的其他Action @@ -61,6 +62,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Transactional public Map getOtaUpgradeRecordCount(IotOtaUpgradeRecordPageReqVO pageReqVO) { // 分别查询不同状态的OTA升级记录数量 + // TODO @li: 通过 groupby 统计下; Long pending = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); Long pushed = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus()); Long upgrading = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus()); @@ -68,6 +70,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic Long failure = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.FAILURE.getStatus()); Long canceled = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()); // 将各状态的数量封装到Map中返回 + // TODO @li:使用 MapUtil,因为 Map.of 是 jdk9 才有,后续不好同步到 master 的 jdk8; return Map.of(IotOtaUpgradeRecordPageReqVO.PENDING, pending, IotOtaUpgradeRecordPageReqVO.PUSHED, pushed, IotOtaUpgradeRecordPageReqVO.UPGRADING, upgrading, @@ -87,6 +90,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Transactional public Map getOtaUpgradeRecordStatistics(Long firmwareId) { // 查询并统计不同状态的OTA升级记录数量 + // TODO @li: 通过 groupby 统计下; Long pending = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); Long pushed = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus()); Long upgrading = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus()); @@ -108,6 +112,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic IotOtaUpgradeRecordDO upgradeRecord = validateUpgradeRecordExists(id); // 1.2.校验升级记录是否可以重新升级 validateUpgradeRecordCanRetry(upgradeRecord); + // 2.将一些数据重置,这样定时任务轮询就可以重启任务 upgradeRecordMapper.updateById(new IotOtaUpgradeRecordDO() .setId(upgradeRecord.getId()).setProgress(0) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java index 5b3444214..1f5476df1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java @@ -8,6 +8,7 @@ import jakarta.validation.Valid; import java.util.List; +// TODO @li:类、方法注释有点冗余,可以参考别的模块哈 /** * IoT OTA升级任务服务接口 * 提供OTA升级任务的创建、取消和查询功能 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java index b66ae402c..cef1448e9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java @@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeTaskMapper; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record.IotOtaUpgradeRecordCreateReqBO; +import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordCreateReqBO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; @@ -34,31 +34,37 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { @Resource private IotOtaUpgradeTaskMapper upgradeTaskMapper; - @Lazy + @Resource + @Lazy private IotDeviceService deviceService; - @Lazy @Resource + @Lazy private IotOtaFirmwareService firmwareService; - @Lazy @Resource + @Lazy private IotOtaUpgradeRecordService upgradeRecordService; @Override @Transactional(rollbackFor = Exception.class) public Long createUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO) { - // 1.1.校验同一固件的升级任务名称不重复 + // 1.1 校验同一固件的升级任务名称不重复 validateFirmwareTaskDuplicate(createReqVO.getFirmwareId(), createReqVO.getName()); - // 1.2.校验固件信息是否存在 + // 1.2 校验固件信息是否存在 IotOtaFirmwareDO firmware = firmwareService.validateFirmwareExists(createReqVO.getFirmwareId()); - // 1.3.校验升级范围=2(指定设备时),deviceIds deviceNames不为空并且长度相等 + // 1.3 校验升级范围=2(指定设备时),deviceIds deviceNames不为空并且长度相等 + // TODO @li:deviceNames 应该后端查询 validateScopeAndDevice(createReqVO.getScope(), createReqVO.getDeviceIds(), createReqVO.getDeviceNames()); - // 2.初始化OTA升级任务信息 + // TODO @li:如果全部范围,但是没设备可以升级,需要报错 + + // 2. 保存 OTA 升级任务信息到数据库 IotOtaUpgradeTaskDO upgradeTask = initUpgradeTask(createReqVO, firmware.getProductId()); - // 3.保存OTA升级任务信息到数据库 upgradeTaskMapper.insert(upgradeTask); - // 4.生成设备升级记录信息并存储,等待定时任务轮询 - List upgradeRecordList = initUpgradeRecordList(upgradeTask, firmware, createReqVO.getDeviceIds()); + + // 3. 生成设备升级记录信息并存储,等待定时任务轮询 + List upgradeRecordList = initUpgradeRecordList( + upgradeTask, firmware, createReqVO.getDeviceIds()); + // TODO @li:只需要传递 deviceIds、firewareId、剩余的 upgradeRecordService 里面自己处理;这样,后续 record 加字段,都不需要透传太多;解耦 upgradeRecordService.createUpgradeRecordBatch(upgradeRecordList); // TODO @芋艿: 创建任务触发的其他Action return upgradeTask.getId(); @@ -67,15 +73,17 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { @Override @Transactional(rollbackFor = Exception.class) public void cancelUpgradeTask(Long id) { - // 1.1.校验升级任务是否存在 + // 1.1 校验升级任务是否存在 IotOtaUpgradeTaskDO upgradeTask = validateUpgradeTaskExists(id); - // 1.2.校验升级任务是否可以取消 + // 1.2 校验升级任务是否可以取消 + // TODO @li:这种一次性的,可以不考虑拆分方法 validateUpgradeTaskCanCancel(upgradeTask); - // 2.更新OTA升级任务状态为已取消 + + // 2. 更新 OTA 升级任务状态为已取消 upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder() .id(id).status(IotOtaUpgradeTaskStatusEnum.CANCELED.getStatus()) .build()); - // 3.更新OTA升级记录状态为已取消 + // 3. 更新 OTA 升级记录状态为已取消 upgradeRecordService.cancelUpgradeRecordByTaskId(id); // TODO @芋艿: 取消任务触发的其他Action } @@ -176,6 +184,7 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { } } + // TODO @li:一次性,不复用的,可以直接写在对应的逻辑里; /** * 初始化升级任务 *

@@ -189,6 +198,7 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { private IotOtaUpgradeTaskDO initUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, String productId) { // 配置各项参数 IotOtaUpgradeTaskDO upgradeTask = IotOtaUpgradeTaskDO.builder() + // TODO @li:不用每个占一行。最好相同类型的,放在一行里; .name(createReqVO.getName()) .description(createReqVO.getDescription()) .firmwareId(createReqVO.getFirmwareId()) @@ -219,7 +229,10 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { * @param deviceIds 设备ID列表,仅在升级任务范围为选择设备时使用 * @return 升级记录请求对象列表,包含每个设备的升级记录信息 */ - private List initUpgradeRecordList(IotOtaUpgradeTaskDO upgradeTask, IotOtaFirmwareDO firmware, List deviceIds) { + private List initUpgradeRecordList( + IotOtaUpgradeTaskDO upgradeTask, IotOtaFirmwareDO firmware, List deviceIds) { + // TODO @li:需要考虑,如果创建多个任务,相互之间不能重复; + // 1)指定设备的时候,进行校验;2)如果是全部,则过滤其它已经发起的;;;;;另外,需要排除掉 cancel 的哈。因为 cancal 之后,还可以发起 // 根据升级任务的范围确定设备列表 List deviceList; if (Objects.equals(upgradeTask.getScope(), IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordCreateReqBO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordCreateReqBO.java similarity index 96% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordCreateReqBO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordCreateReqBO.java index e3accc427..2567be529 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordCreateReqBO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordCreateReqBO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record; +package cn.iocoder.yudao.module.iot.service.ota.bo; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordUpdateReqBO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordUpdateReqBO.java similarity index 93% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordUpdateReqBO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordUpdateReqBO.java index e0e71097c..ac73aa884 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/record/IotOtaUpgradeRecordUpdateReqBO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordUpdateReqBO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.service.ota.bo.upgrade.record; +package cn.iocoder.yudao.module.iot.service.ota.bo; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; @@ -11,6 +11,7 @@ import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +// TODO @li:这个类,貌似没用? @Data public class IotOtaUpgradeRecordUpdateReqBO { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/package-info.java deleted file mode 100644 index fbed390ae..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.ota.bo; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/package-info.java deleted file mode 100644 index af729fae3..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/upgrade/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.ota.bo.upgrade; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml index 0dac6efb5..ea86ba5c4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml @@ -4,6 +4,7 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + + + + + + + + \ No newline at end of file From 006ef40c4b325b32e1aad54f55d7176e23554ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 26 Feb 2025 22:54:44 +0800 Subject: [PATCH 185/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=B7=BB=E5=8A=A0=20MQTT=20=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E9=9D=9E=E6=B3=95=E9=94=99=E8=AF=AF=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E8=AE=BE=E5=A4=87=E6=9C=8D=E5=8A=A1=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E5=92=8C=E5=B1=9E=E6=80=A7=E8=AE=BE=E7=BD=AE=E9=80=BB?= =?UTF-8?q?=E8=BE=91=EF=BC=8C=E4=BC=98=E5=8C=96=20MQTT=20=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E5=A4=84=E7=90=86=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 3 + .../IotPluginEmqxAutoConfiguration.java | 37 +++- .../IotDeviceDownstreamHandlerImpl.java | 157 ++++++++++++- .../upstream/IotDeviceUpstreamServer.java | 195 ++++++++++------ .../router/IotDeviceMqttMessageHandler.java | 208 ++++++++++++------ 5 files changed, 450 insertions(+), 150 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 74fbb8b2e..3d12c4b59 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -67,4 +67,7 @@ public interface ErrorCodeConstants { ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_007, "升级记录重复"); ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_008, "升级记录不能重试"); + // ========== MQTT 通信相关 1-050-009-000 ========== + ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal"); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java index d504e5704..382bb9ecf 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java @@ -1,9 +1,14 @@ package cn.iocoder.yudao.module.iot.plugin.emqx.config; +import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; import cn.iocoder.yudao.module.iot.plugin.emqx.downstream.IotDeviceDownstreamHandlerImpl; import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.IotDeviceUpstreamServer; +import io.vertx.core.Vertx; +import io.vertx.mqtt.MqttClient; +import io.vertx.mqtt.MqttClientOptions; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -13,19 +18,37 @@ import org.springframework.context.annotation.Configuration; * * @author haohao */ +@Slf4j @Configuration @EnableConfigurationProperties(IotPluginEmqxProperties.class) public class IotPluginEmqxAutoConfiguration { - @Bean(initMethod = "start", destroyMethod = "stop") - public IotDeviceUpstreamServer deviceUpstreamServer(IotDeviceUpstreamApi deviceUpstreamApi, - IotPluginEmqxProperties emqxProperties) { - return new IotDeviceUpstreamServer(emqxProperties, deviceUpstreamApi); + @Bean + public Vertx vertx() { + return Vertx.vertx(); } @Bean - public IotDeviceDownstreamHandler deviceDownstreamHandler() { - return new IotDeviceDownstreamHandlerImpl(); + public MqttClient mqttClient(Vertx vertx, IotPluginEmqxProperties emqxProperties) { + MqttClientOptions options = new MqttClientOptions() + .setClientId("yudao-iot-downstream-" + IdUtil.fastSimpleUUID()) + .setUsername(emqxProperties.getMqttUsername()) + .setPassword(emqxProperties.getMqttPassword()) + .setSsl(emqxProperties.isMqttSsl()); + return MqttClient.create(vertx, options); } -} + @Bean(initMethod = "start", destroyMethod = "stop") + public IotDeviceUpstreamServer deviceUpstreamServer(IotDeviceUpstreamApi deviceUpstreamApi, + IotPluginEmqxProperties emqxProperties, + Vertx vertx, + MqttClient mqttClient) { + return new IotDeviceUpstreamServer(emqxProperties, deviceUpstreamApi, vertx, mqttClient); + } + + @Bean + public IotDeviceDownstreamHandler deviceDownstreamHandler(MqttClient mqttClient) { + return new IotDeviceDownstreamHandlerImpl(mqttClient); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java index b1a8eebbf..57445e5ad 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java @@ -1,8 +1,19 @@ package cn.iocoder.yudao.module.iot.plugin.emqx.downstream; +import cn.hutool.core.util.IdUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import io.netty.handler.codec.mqtt.MqttQoS; +import io.vertx.core.buffer.Buffer; +import io.vertx.mqtt.MqttClient; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.MQTT_TOPIC_ILLEGAL; /** * EMQX 插件的 {@link IotDeviceDownstreamHandler} 实现类 @@ -10,14 +21,61 @@ import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamH * * @author 芋道源码 */ +@Slf4j public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandler { + private static final String SYS_TOPIC_PREFIX = "/sys/"; + + // 设备服务调用 标准 JSON + // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} + // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}_reply + private static final String SERVICE_TOPIC_PREFIX = "/thing/service/"; + + // 设置设备属性 标准 JSON + // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/set + // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply + private static final String PROPERTY_SET_TOPIC = "/thing/service/property/set"; + + private final MqttClient mqttClient; + + /** + * 构造函数 + * + * @param mqttClient MQTT客户端 + */ + public IotDeviceDownstreamHandlerImpl(MqttClient mqttClient) { + this.mqttClient = mqttClient; + } + @Override - public CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO) { - // 设备服务调用 - // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} - // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}_reply - return CommonResult.success(true); + public CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO reqDTO) { + log.info("[invokeService][开始调用设备服务][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); + + // 验证参数 + if (reqDTO.getProductKey() == null || reqDTO.getDeviceName() == null || reqDTO.getIdentifier() == null) { + log.error("[invokeService][参数不完整][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); + return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); + } + + try { + // 构建请求主题 + String topic = buildServiceTopic(reqDTO.getProductKey(), reqDTO.getDeviceName(), reqDTO.getIdentifier()); + + // 生成请求ID(如果没有提供) + String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); + + // 构建请求消息 + JSONObject request = buildServiceRequest(requestId, reqDTO.getIdentifier(), reqDTO.getParams()); + + // 发送消息 + publishMessage(topic, request); + + log.info("[invokeService][调用设备服务成功][requestId: {}][topic: {}]", requestId, topic); + return CommonResult.success(true); + } catch (Exception e) { + log.error("[invokeService][调用设备服务异常][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO), e); + return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); + } } @Override @@ -26,11 +84,34 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle } @Override - public CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO) { - // 设置设备属性 标准 JSON - // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/set - // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply - return CommonResult.success(true); + public CommonResult setDeviceProperty(IotDevicePropertySetReqDTO reqDTO) { + log.info("[setProperty][开始设置设备属性][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); + + // 验证参数 + if (reqDTO.getProductKey() == null || reqDTO.getDeviceName() == null) { + log.error("[setProperty][参数不完整][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); + return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); + } + + try { + // 构建请求主题 + String topic = buildPropertySetTopic(reqDTO.getProductKey(), reqDTO.getDeviceName()); + + // 生成请求ID(如果没有提供) + String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); + + // 构建请求消息 + JSONObject request = buildPropertySetRequest(requestId, reqDTO.getProperties()); + + // 发送消息 + publishMessage(topic, request); + + log.info("[setProperty][设置设备属性成功][requestId: {}][topic: {}]", requestId, topic); + return CommonResult.success(true); + } catch (Exception e) { + log.error("[setProperty][设置设备属性异常][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO), e); + return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); + } } @Override @@ -43,4 +124,60 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle return CommonResult.success(true); } + /** + * 构建服务调用主题 + */ + private String buildServiceTopic(String productKey, String deviceName, String serviceIdentifier) { + return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + SERVICE_TOPIC_PREFIX + serviceIdentifier; + } + + /** + * 构建属性设置主题 + */ + private String buildPropertySetTopic(String productKey, String deviceName) { + return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + PROPERTY_SET_TOPIC; + } + + /** + * 构建服务调用请求 + */ + private JSONObject buildServiceRequest(String requestId, String serviceIdentifier, Map params) { + return new JSONObject() + .set("id", requestId) + .set("version", "1.0") + .set("method", "thing.service." + serviceIdentifier) + .set("params", params != null ? params : new JSONObject()); + } + + /** + * 构建属性设置请求 + */ + private JSONObject buildPropertySetRequest(String requestId, Map properties) { + return new JSONObject() + .set("id", requestId) + .set("version", "1.0") + .set("method", "thing.service.property.set") + .set("params", properties); + } + + /** + * 发布MQTT消息 + */ + private void publishMessage(String topic, JSONObject payload) { + mqttClient.publish( + topic, + Buffer.buffer(payload.toString()), + MqttQoS.AT_LEAST_ONCE, + false, + false); + log.info("[publishMessage][发送消息成功][topic: {}][payload: {}]", topic, payload); + } + + /** + * 生成请求ID + */ + private String generateRequestId() { + return IdUtil.fastSimpleUUID(); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java index baeddcb15..738860361 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java @@ -1,19 +1,21 @@ package cn.iocoder.yudao.module.iot.plugin.emqx.upstream; -import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.plugin.emqx.config.IotPluginEmqxProperties; import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router.IotDeviceAuthVertxHandler; import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router.IotDeviceMqttMessageHandler; import io.netty.handler.codec.mqtt.MqttQoS; +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.http.HttpServer; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; import io.vertx.mqtt.MqttClient; -import io.vertx.mqtt.MqttClientOptions; import lombok.extern.slf4j.Slf4j; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + /** * IoT 设备下行服务端,接收来自 device 设备的请求,转发给 server 服务器 *

@@ -24,20 +26,26 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class IotDeviceUpstreamServer { - private static final int RECONNECT_DELAY = 5000; // 重连延迟时间(毫秒) + private static final int RECONNECT_DELAY_MS = 5000; // 重连延迟时间(毫秒) + private static final int CONNECTION_TIMEOUT_MS = 10000; // 连接超时时间(毫秒) + private static final String TOPIC_SEPARATOR = ","; // 主题分隔符 + private static final MqttQoS DEFAULT_QOS = MqttQoS.AT_LEAST_ONCE; // 默认QoS级别 private final Vertx vertx; private final HttpServer server; private final MqttClient client; private final IotPluginEmqxProperties emqxProperties; private final IotDeviceMqttMessageHandler mqttMessageHandler; + private volatile boolean isRunning = false; // 服务运行状态标志 public IotDeviceUpstreamServer(IotPluginEmqxProperties emqxProperties, - IotDeviceUpstreamApi deviceUpstreamApi) { + IotDeviceUpstreamApi deviceUpstreamApi, + Vertx vertx, + MqttClient client) { + this.vertx = vertx; this.emqxProperties = emqxProperties; + this.client = client; - // 创建 Vertx 实例 - this.vertx = Vertx.vertx(); // 创建 Router 实例 Router router = Router.router(vertx); router.route().handler(BodyHandler.create()); // 处理 Body @@ -45,14 +53,6 @@ public class IotDeviceUpstreamServer { .handler(new IotDeviceAuthVertxHandler(deviceUpstreamApi)); // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); - - // 创建 MQTT 客户端 - MqttClientOptions options = new MqttClientOptions() - .setClientId("yudao-iot-server-" + IdUtil.fastSimpleUUID()) - .setUsername(emqxProperties.getMqttUsername()) - .setPassword(emqxProperties.getMqttPassword()) - .setSsl(emqxProperties.isMqttSsl()); - client = MqttClient.create(vertx, options); this.mqttMessageHandler = new IotDeviceMqttMessageHandler(deviceUpstreamApi, client); } @@ -60,25 +60,45 @@ public class IotDeviceUpstreamServer { * 启动 HTTP 服务器、MQTT 客户端 */ public void start() { + if (isRunning) { + log.warn("服务已经在运行中,请勿重复启动"); + return; + } + + log.info("[start] 开始启动服务"); + // 1. 启动 HTTP 服务器 - log.info("[start][开始启动]"); - server.listen(emqxProperties.getAuthPort()) + CompletableFuture httpFuture = server.listen(emqxProperties.getAuthPort()) .toCompletionStage() .toCompletableFuture() - .join(); - log.info("[start][HTTP服务器启动完成,端口({})]", this.server.actualPort()); + .thenAccept(v -> log.info("[start] HTTP服务器启动完成,端口: {}", server.actualPort())); // 2. 连接 MQTT Broker - connectMqtt(); + CompletableFuture mqttFuture = connectMqtt() + .toCompletionStage() + .toCompletableFuture() + .thenAccept(v -> { + // 3. 添加 MQTT 断开重连监听器 + client.closeHandler(closeEvent -> { + log.warn("[closeHandler] MQTT连接已断开,准备重连"); + reconnectWithDelay(); + }); - // 3. 添加 MQTT 断开重连监听器 - client.closeHandler(v -> { - log.warn("[closeHandler][MQTT 连接已断开,准备重连]"); - reconnectWithDelay(); - }); + // 4. 设置 MQTT 消息处理器 + setupMessageHandler(); + }); - // 4. 设置 MQTT 消息处理器 - setupMessageHandler(); + // 等待所有服务启动完成 + CompletableFuture.allOf(httpFuture, mqttFuture) + .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) + .whenComplete((result, error) -> { + if (error != null) { + log.error("[start] 服务启动失败", error); + } else { + isRunning = true; + log.info("[start] 所有服务启动完成"); + } + }); } /** @@ -86,79 +106,118 @@ public class IotDeviceUpstreamServer { */ private void setupMessageHandler() { client.publishHandler(mqttMessageHandler::handle); + log.debug("[setupMessageHandler] MQTT消息处理器设置完成"); } /** * 重连 MQTT 客户端 */ private void reconnectWithDelay() { - vertx.setTimer(RECONNECT_DELAY, id -> { - log.info("[reconnectWithDelay][开始重新连接 MQTT]"); + if (!isRunning) { + log.info("[reconnectWithDelay] 服务已停止,不再尝试重连"); + return; + } + + vertx.setTimer(RECONNECT_DELAY_MS, id -> { + log.info("[reconnectWithDelay] 开始重新连接MQTT"); connectMqtt(); }); } /** * 连接 MQTT Broker 并订阅主题 + * + * @return 连接结果的Future */ - private void connectMqtt() { - client.connect(emqxProperties.getMqttPort(), emqxProperties.getMqttHost()) - .onSuccess(connAck -> { - log.info("[connectMqtt][MQTT客户端连接成功]"); - subscribeToTopics(); + private Future connectMqtt() { + return client.connect(emqxProperties.getMqttPort(), emqxProperties.getMqttHost()) + .compose(connAck -> { + log.info("[connectMqtt] MQTT客户端连接成功"); + return subscribeToTopics(); }) - .onFailure(err -> { - log.error("[connectMqtt][连接 MQTT Broker 失败]", err); + .recover(err -> { + log.error("[connectMqtt] 连接MQTT Broker失败: {}", err.getMessage()); reconnectWithDelay(); + return Future.failedFuture(err); }); } /** * 订阅设备上行消息主题 + * + * @return 订阅结果的Future */ - private void subscribeToTopics() { - String[] topics = emqxProperties.getMqttTopics().split(","); - for (String topic : topics) { - client.subscribe(topic, MqttQoS.AT_LEAST_ONCE.value()) - .onSuccess(v -> log.info("[subscribeToTopics][成功订阅主题: {}]", topic)) - .onFailure(err -> log.error("[subscribeToTopics][订阅主题失败: {}]", topic, err)); + private Future subscribeToTopics() { + String topicsStr = emqxProperties.getMqttTopics(); + if (topicsStr == null || topicsStr.trim().isEmpty()) { + log.warn("[subscribeToTopics] 未配置MQTT主题,跳过订阅"); + return Future.succeededFuture(); } - log.info("[subscribeToTopics][开始订阅设备上行消息主题]"); + + log.info("[subscribeToTopics] 开始订阅设备上行消息主题"); + + String[] topics = topicsStr.split(TOPIC_SEPARATOR); + Future compositeFuture = Future.succeededFuture(); + + for (String topic : topics) { + String trimmedTopic = topic.trim(); + if (trimmedTopic.isEmpty()) { + continue; + } + + compositeFuture = compositeFuture.compose(v -> client.subscribe(trimmedTopic, DEFAULT_QOS.value()) + .map(ack -> { + log.info("[subscribeToTopics] 成功订阅主题: {}", trimmedTopic); + return null; + }) + .recover(err -> { + log.error("[subscribeToTopics] 订阅主题失败: {}, 原因: {}", + trimmedTopic, err.getMessage()); + return Future.succeededFuture(); // 继续订阅其他主题 + })); + } + + return compositeFuture; } /** - * 停止所有 + * 停止所有服务 */ public void stop() { - log.info("[stop][开始关闭]"); + if (!isRunning) { + log.warn("[stop] 服务未运行,无需停止"); + return; + } + + log.info("[stop] 开始关闭服务"); + isRunning = false; + try { - // 关闭 HTTP 服务器 - if (server != null) { - server.close() - .toCompletionStage() - .toCompletableFuture() - .join(); - } + CompletableFuture serverFuture = server != null + ? server.close().toCompletionStage().toCompletableFuture() + : CompletableFuture.completedFuture(null); - // 关闭 MQTT 客户端 - if (client != null) { - client.disconnect() - .toCompletionStage() - .toCompletableFuture() - .join(); - } + CompletableFuture clientFuture = client != null + ? client.disconnect().toCompletionStage().toCompletableFuture() + : CompletableFuture.completedFuture(null); - // 关闭 Vertx 实例 - if (vertx != null) { - vertx.close() - .toCompletionStage() - .toCompletableFuture() - .join(); - } - log.info("[stop][关闭完成]"); + CompletableFuture vertxFuture = vertx != null + ? vertx.close().toCompletionStage().toCompletableFuture() + : CompletableFuture.completedFuture(null); + + // 等待所有资源关闭 + CompletableFuture.allOf(serverFuture, clientFuture, vertxFuture) + .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) + .whenComplete((result, error) -> { + if (error != null) { + log.error("[stop] 服务关闭过程中发生异常", error); + } else { + log.info("[stop] 所有服务关闭完成"); + } + }); } catch (Exception e) { - log.error("[stop][关闭异常]", e); - throw new RuntimeException(e); + log.error("[stop] 关闭服务异常", e); + throw new RuntimeException("关闭IoT设备上行服务失败", e); } } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java index 6b99d781a..83e9d1bfd 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java @@ -13,13 +13,15 @@ import io.vertx.mqtt.messages.MqttPublishMessage; import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; +import java.util.Arrays; /** * IoT 设备 MQTT 消息处理器 *

* 参考: *

- * "..."> + * "..."> */ @Slf4j public class IotDeviceMqttMessageHandler { @@ -35,6 +37,12 @@ public class IotDeviceMqttMessageHandler { private static final String PROPERTY_POST_TOPIC = "/thing/event/property/post"; private static final String EVENT_POST_TOPIC_PREFIX = "/thing/event/"; private static final String EVENT_POST_TOPIC_SUFFIX = "/post"; + private static final String REPLY_SUFFIX = "_reply"; + private static final int SUCCESS_CODE = 200; + private static final String SUCCESS_MESSAGE = "success"; + private static final String PROPERTY_METHOD = "thing.event.property.post"; + private static final String EVENT_METHOD_PREFIX = "thing.event."; + private static final String EVENT_METHOD_SUFFIX = ".post"; private final IotDeviceUpstreamApi deviceUpstreamApi; private final MqttClient mqttClient; @@ -44,18 +52,33 @@ public class IotDeviceMqttMessageHandler { this.mqttClient = mqttClient; } + /** + * 处理MQTT消息 + * + * @param message MQTT发布消息 + */ public void handle(MqttPublishMessage message) { String topic = message.topicName(); String payload = message.payload().toString(); log.info("[messageHandler][接收到消息][topic: {}][payload: {}]", topic, payload); try { + if (payload == null || payload.isEmpty()) { + log.warn("[messageHandler][消息内容为空][topic: {}]", topic); + return; + } handleMessage(topic, payload); } catch (Exception e) { log.error("[messageHandler][处理消息失败][topic: {}][payload: {}]", topic, payload, e); } } + /** + * 根据主题类型处理消息 + * + * @param topic 主题 + * @param payload 消息内容 + */ private void handleMessage(String topic, String payload) { // 校验前缀 if (!topic.startsWith(SYS_TOPIC_PREFIX)) { @@ -88,34 +111,26 @@ public class IotDeviceMqttMessageHandler { * @param payload 消息内容 */ private void handlePropertyPost(String topic, String payload) { - // 解析消息内容 - JSONObject jsonObject = JSONUtil.parseObj(payload); - String[] topicParts = topic.split("/"); + try { + // 解析消息内容 + JSONObject jsonObject = JSONUtil.parseObj(payload); + String[] topicParts = parseTopic(topic); + if (topicParts == null) { + return; + } - // 构建设备属性上报请求对象 - IotDevicePropertyReportReqDTO reportReqDTO = buildPropertyReportDTO(jsonObject, topicParts); + // 构建设备属性上报请求对象 + IotDevicePropertyReportReqDTO reportReqDTO = buildPropertyReportDTO(jsonObject, topicParts); - // 调用上游 API 处理设备上报数据 - deviceUpstreamApi.reportDeviceProperty(reportReqDTO); - log.info("[handlePropertyPost][处理设备上行消息成功][topic: {}][reportReqDTO: {}]", - topic, JSONUtil.toJsonStr(reportReqDTO)); + // 调用上游 API 处理设备上报数据 + deviceUpstreamApi.reportDeviceProperty(reportReqDTO); + log.info("[handlePropertyPost][处理设备属性上报成功][topic: {}]", topic); - // 发送响应消息 - String replyTopic = topic + "_reply"; - JSONObject response = new JSONObject() - .set("id", jsonObject.getStr("id")) - .set("code", 200) - .set("data", new JSONObject()) - .set("message", "success") - .set("method", "thing.event.property.post"); - - mqttClient.publish(replyTopic, - Buffer.buffer(response.toString()), - MqttQoS.AT_LEAST_ONCE, - false, - false); - log.info("[handlePropertyPost][发送响应消息成功][topic: {}][response: {}]", - replyTopic, response.toString()); + // 发送响应消息 + sendResponse(topic, jsonObject, PROPERTY_METHOD, null); + } catch (Exception e) { + log.error("[handlePropertyPost][处理设备属性上报失败][topic: {}][payload: {}]", topic, payload, e); + } } /** @@ -125,35 +140,97 @@ public class IotDeviceMqttMessageHandler { * @param payload 消息内容 */ private void handleEventPost(String topic, String payload) { - // 解析消息内容 - JSONObject jsonObject = JSONUtil.parseObj(payload); + try { + // 解析消息内容 + JSONObject jsonObject = JSONUtil.parseObj(payload); + String[] topicParts = parseTopic(topic); + if (topicParts == null) { + return; + } + + // 构建设备事件上报请求对象 + IotDeviceEventReportReqDTO reportReqDTO = buildEventReportDTO(jsonObject, topicParts); + + // 调用上游 API 处理设备上报数据 + deviceUpstreamApi.reportDeviceEvent(reportReqDTO); + log.info("[handleEventPost][处理设备事件上报成功][topic: {}]", topic); + + // 从 topic 中获取事件标识符 + String eventIdentifier = getEventIdentifier(topicParts, topic); + if (eventIdentifier == null) { + return; + } + + // 发送响应消息 + String method = EVENT_METHOD_PREFIX + eventIdentifier + EVENT_METHOD_SUFFIX; + sendResponse(topic, jsonObject, method, null); + } catch (Exception e) { + log.error("[handleEventPost][处理设备事件上报失败][topic: {}][payload: {}]", topic, payload, e); + } + } + + /** + * 解析主题,获取主题各部分 + * + * @param topic 主题 + * @return 主题各部分数组,如果解析失败返回null + */ + private String[] parseTopic(String topic) { String[] topicParts = topic.split("/"); + if (topicParts.length < 7) { + log.warn("[parseTopic][主题格式不正确][topic: {}]", topic); + return null; + } + return topicParts; + } - // 构建设备事件上报请求对象 - IotDeviceEventReportReqDTO reportReqDTO = buildEventReportDTO(jsonObject, topicParts); + /** + * 从主题部分中获取事件标识符 + * + * @param topicParts 主题各部分 + * @param topic 原始主题,用于日志 + * @return 事件标识符,如果获取失败返回null + */ + private String getEventIdentifier(String[] topicParts, String topic) { + try { + return topicParts[6]; + } catch (ArrayIndexOutOfBoundsException e) { + log.warn("[getEventIdentifier][无法从主题中获取事件标识符][topic: {}][topicParts: {}]", + topic, Arrays.toString(topicParts)); + return null; + } + } - // 调用上游 API 处理设备上报数据 - deviceUpstreamApi.reportDeviceEvent(reportReqDTO); - log.info("[handleEventPost][处理设备上行消息成功][topic: {}][reportReqDTO: {}]", - topic, JSONUtil.toJsonStr(reportReqDTO)); + /** + * 发送响应消息 + * + * @param topic 原始主题 + * @param jsonObject 原始消息JSON对象 + * @param method 响应方法 + * @param customData 自定义数据,可为null + */ + private void sendResponse(String topic, JSONObject jsonObject, String method, JSONObject customData) { + String replyTopic = topic + REPLY_SUFFIX; + JSONObject data = customData != null ? customData : new JSONObject(); - // 发送响应消息 - String replyTopic = topic + "_reply"; - String eventIdentifier = topicParts[6]; // 从 topic 中获取事件标识符 JSONObject response = new JSONObject() .set("id", jsonObject.getStr("id")) - .set("code", 200) - .set("data", new JSONObject()) - .set("message", "success") - .set("method", "thing.event." + eventIdentifier + ".post"); + .set("code", SUCCESS_CODE) + .set("data", data) + .set("message", SUCCESS_MESSAGE) + .set("method", method); - mqttClient.publish(replyTopic, - Buffer.buffer(response.toString()), - MqttQoS.AT_LEAST_ONCE, - false, - false); - log.info("[handleEventPost][发送响应消息成功][topic: {}][response: {}]", - replyTopic, response.toString()); + try { + mqttClient.publish(replyTopic, + Buffer.buffer(response.toString()), + MqttQoS.AT_LEAST_ONCE, + false, + false); + log.info("[sendResponse][发送响应消息成功][topic: {}]", replyTopic); + } catch (Exception e) { + log.error("[sendResponse][发送响应消息失败][topic: {}][response: {}]", + replyTopic, response.toString(), e); + } } /** @@ -163,15 +240,15 @@ public class IotDeviceMqttMessageHandler { * @param topicParts 主题部分 * @return 设备属性上报请求对象 */ - private IotDevicePropertyReportReqDTO buildPropertyReportDTO(JSONObject jsonObject, - String[] topicParts) { - return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO() - .setRequestId(jsonObject.getStr("id")) - .setProcessId(IotPluginCommonUtils.getProcessId()) - .setReportTime(LocalDateTime.now()) - .setProductKey(topicParts[2]) - .setDeviceName(topicParts[3])) - .setProperties(jsonObject.getJSONObject("params")); + private IotDevicePropertyReportReqDTO buildPropertyReportDTO(JSONObject jsonObject, String[] topicParts) { + IotDevicePropertyReportReqDTO reportReqDTO = new IotDevicePropertyReportReqDTO(); + reportReqDTO.setRequestId(jsonObject.getStr("id")); + reportReqDTO.setProcessId(IotPluginCommonUtils.getProcessId()); + reportReqDTO.setReportTime(LocalDateTime.now()); + reportReqDTO.setProductKey(topicParts[2]); + reportReqDTO.setDeviceName(topicParts[3]); + reportReqDTO.setProperties(jsonObject.getJSONObject("params")); + return reportReqDTO; } /** @@ -182,13 +259,14 @@ public class IotDeviceMqttMessageHandler { * @return 设备事件上报请求对象 */ private IotDeviceEventReportReqDTO buildEventReportDTO(JSONObject jsonObject, String[] topicParts) { - return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO() - .setRequestId(jsonObject.getStr("id")) - .setProcessId(IotPluginCommonUtils.getProcessId()) - .setReportTime(LocalDateTime.now()) - .setProductKey(topicParts[2]) - .setDeviceName(topicParts[3])) - .setIdentifier(topicParts[4]) - .setParams(jsonObject.getJSONObject("params")); + IotDeviceEventReportReqDTO reportReqDTO = new IotDeviceEventReportReqDTO(); + reportReqDTO.setRequestId(jsonObject.getStr("id")); + reportReqDTO.setProcessId(IotPluginCommonUtils.getProcessId()); + reportReqDTO.setReportTime(LocalDateTime.now()); + reportReqDTO.setProductKey(topicParts[2]); + reportReqDTO.setDeviceName(topicParts[3]); + reportReqDTO.setIdentifier(topicParts[6]); + reportReqDTO.setParams(jsonObject.getJSONObject("params")); + return reportReqDTO; } } \ No newline at end of file From 6cf7a67406929df0e4cd9c57e844c4ce8f777269 Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Thu, 27 Feb 2025 10:52:28 +0800 Subject: [PATCH 186/228] =?UTF-8?q?[fix]=EF=BC=9Aiot=20home=20count?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../statistics/IotStatisticsController.java | 12 +++++++----- .../admin/statistics/vo/IotStatisticsReqVO.java | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java index 9752a04ab..61f773f47 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsReqVO; import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; @@ -10,6 +11,7 @@ import cn.iocoder.yudao.module.iot.service.product.IotProductService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; +import jakarta.validation.Valid; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -37,9 +39,9 @@ public class IotStatisticsController { private IotDeviceLogService iotDeviceLogService; - @GetMapping("/count") + @GetMapping("/main") @Operation(summary = "获取IOT首页的数据统计", description = "用于IOT首页的数据统计") - public CommonResult getIotCount(){ + public CommonResult getIotMainStats(@Valid IotStatisticsReqVO reqVO){ IotStatisticsRespVO iotStatisticsRespVO = new IotStatisticsRespVO(); // 获取总数 iotStatisticsRespVO.setCategoryTotal(iotProductCategoryService.getProductCategoryCount(null)); @@ -64,9 +66,9 @@ public class IotStatisticsController { iotStatisticsRespVO.setOfflineTotal(iotDeviceService.getDeviceCountByState(IotDeviceStateEnum.OFFLINE.getState())); iotStatisticsRespVO.setNeverOnlineTotal(iotDeviceService.getDeviceCountByState(IotDeviceStateEnum.INACTIVE.getState())); - // 获取设备上下行消息数量统计 - iotStatisticsRespVO.setDeviceUpMessageStats(iotDeviceLogService.getDeviceLogUpCountByHour(null,null,null)); - iotStatisticsRespVO.setDeviceDownMessageStats(iotDeviceLogService.getDeviceLogDownCountByHour(null,null,null)); + // 根据传入时间范围获取设备上下行消息数量统计 + iotStatisticsRespVO.setDeviceUpMessageStats(iotDeviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); + iotStatisticsRespVO.setDeviceDownMessageStats(iotDeviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); return CommonResult.success(iotStatisticsRespVO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java new file mode 100644 index 000000000..56f013963 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - Iot统计 Request VO") +@Data +public class IotStatisticsReqVO { + @Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @NotNull(message = "查询起始时间不能为空") + Long startTime; + @Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @NotNull(message = "查询结束时间不能为空") + Long endTime; +} From 36dd18d41faa4a34a197821e73af20116ba97da1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 27 Feb 2025 12:45:42 +0800 Subject: [PATCH 187/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9AMQTT=20=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/util/MqttSignUtils.java | 2 ++ .../emqx/config/IotPluginEmqxProperties.java | 1 + .../IotDeviceDownstreamHandlerImpl.java | 1 + .../upstream/IotDeviceUpstreamServer.java | 27 +++++++++++++++---- .../router/IotDeviceAuthVertxHandler.java | 4 ++- .../router/IotDeviceMqttMessageHandler.java | 10 ++++--- 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java index 7a6b6e441..01a6dba93 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java @@ -59,9 +59,11 @@ public class MqttSignUtils { @Getter @AllArgsConstructor public static class MqttSignResult { + private final String clientId; private final String username; private final String password; + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java index fbc689b35..72a085bd9 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java @@ -36,6 +36,7 @@ public class IotPluginEmqxProperties { */ private boolean mqttSsl; + // TODO @haohao:这个是不是改成数组? /** * 订阅的主题 */ diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java index 57445e5ad..aed677c49 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java @@ -26,6 +26,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle private static final String SYS_TOPIC_PREFIX = "/sys/"; + // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。 // 设备服务调用 标准 JSON // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}_reply diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java index 738860361..5dd627671 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java @@ -26,17 +26,33 @@ import java.util.concurrent.TimeUnit; @Slf4j public class IotDeviceUpstreamServer { - private static final int RECONNECT_DELAY_MS = 5000; // 重连延迟时间(毫秒) - private static final int CONNECTION_TIMEOUT_MS = 10000; // 连接超时时间(毫秒) - private static final String TOPIC_SEPARATOR = ","; // 主题分隔符 - private static final MqttQoS DEFAULT_QOS = MqttQoS.AT_LEAST_ONCE; // 默认QoS级别 + /** + * 重连延迟时间(毫秒) + */ + private static final int RECONNECT_DELAY_MS = 5000; + /** + * 连接超时时间(毫秒) + */ + private static final int CONNECTION_TIMEOUT_MS = 10000; + /** + * 主题分隔符 + */ + private static final String TOPIC_SEPARATOR = ","; + /** + * 默认 QoS 级别 + */ + private static final MqttQoS DEFAULT_QOS = MqttQoS.AT_LEAST_ONCE; private final Vertx vertx; private final HttpServer server; private final MqttClient client; private final IotPluginEmqxProperties emqxProperties; private final IotDeviceMqttMessageHandler mqttMessageHandler; - private volatile boolean isRunning = false; // 服务运行状态标志 + + /** + * 服务运行状态标志 + */ + private volatile boolean isRunning = false; public IotDeviceUpstreamServer(IotPluginEmqxProperties emqxProperties, IotDeviceUpstreamApi deviceUpstreamApi, @@ -50,6 +66,7 @@ public class IotDeviceUpstreamServer { Router router = Router.router(vertx); router.route().handler(BodyHandler.create()); // 处理 Body router.post(IotDeviceAuthVertxHandler.PATH) + // TODO @haohao:疑问,mqtt 的认证,需要通过 http 呀? .handler(new IotDeviceAuthVertxHandler(deviceUpstreamApi)); // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java index 794949c28..8eac1ffbd 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java @@ -27,7 +27,7 @@ public class IotDeviceAuthVertxHandler implements Handler { @Override @SuppressWarnings("unchecked") public void handle(RoutingContext routingContext) { - + // TODO @haohao:try catch 兜底异常 JsonObject json = routingContext.body().asJsonObject(); String clientId = json.getString("clientid"); String username = json.getString("username"); @@ -40,9 +40,11 @@ public class IotDeviceAuthVertxHandler implements Handler { denyAccess(routingContext); return; } + // TODO @haohao:貌似可以考虑封装一个 writeJson ,里面有个参数是 data,然后里面去 JsonUtils.toJsonString(data) IotPluginCommonUtils.writeJson(routingContext, "{\"result\": \"allow\"}"); } + // TODO @haohao:下面两个简单方法,貌似可以考虑不抽小方法哈。 private void denyAccess(RoutingContext routingContext) { IotPluginCommonUtils.writeJson(routingContext, "{\"result\": \"deny\"}"); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java index 83e9d1bfd..9851d1747 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java @@ -26,12 +26,14 @@ import java.util.Arrays; @Slf4j public class IotDeviceMqttMessageHandler { + // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。 // 设备上报属性 标准 JSON - // 请求Topic:/sys/${productKey}/${deviceName}/thing/event/property/post - // 响应Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply + // 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post + // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply + // 设备上报事件 标准 JSON - // 请求Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post - // 响应Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply + // 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post + // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply private static final String SYS_TOPIC_PREFIX = "/sys/"; private static final String PROPERTY_POST_TOPIC = "/thing/event/property/post"; From 6e1ec8b3eb7ee3261a58126c86ff2c516a1b78cd Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 27 Feb 2025 13:30:39 +0800 Subject: [PATCH 188/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E9=A6=96=E9=A1=B5=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../statistics/IotStatisticsController.java | 46 +++++++++---------- .../statistics/vo/IotStatisticsReqVO.java | 6 +++ .../statistics/vo/IotStatisticsRespVO.java | 31 +++++++++++-- .../iot/dal/mysql/device/IotDeviceMapper.java | 17 ++----- .../product/IotProductCategoryMapper.java | 10 +--- .../dal/mysql/product/IotProductMapper.java | 15 +----- .../mysql/thingmodel/IotThingModelMapper.java | 1 + .../iot/dal/tdengine/IotDeviceLogMapper.java | 3 +- .../iot/service/device/IotDeviceService.java | 2 +- .../service/device/IotDeviceServiceImpl.java | 1 + .../device/data/IotDeviceLogService.java | 12 +++-- .../device/data/IotDeviceLogServiceImpl.java | 2 + .../product/IotProductCategoryService.java | 4 +- .../IotProductCategoryServiceImpl.java | 9 ++-- .../service/product/IotProductService.java | 4 +- .../thingmodel/IotThingModelService.java | 1 + .../thingmodel/IotThingModelServiceImpl.java | 1 + 17 files changed, 90 insertions(+), 75 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java index 61f773f47..bb5fa92ae 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java @@ -19,7 +19,6 @@ import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; - @Tag(name = "管理后台 - IoT 数据统计") @RestController @RequestMapping("/iot/statistics") @@ -27,48 +26,47 @@ import java.time.LocalDateTime; public class IotStatisticsController { @Resource - private IotDeviceService iotDeviceService; - + private IotDeviceService deviceService; @Resource - private IotProductCategoryService iotProductCategoryService; - + private IotProductCategoryService productCategoryService; @Resource - private IotProductService iotProductService; - + private IotProductService productService; @Resource - private IotDeviceLogService iotDeviceLogService; - + private IotDeviceLogService deviceLogService; + // TODO @super:description 非必要,可以不写哈 @GetMapping("/main") - @Operation(summary = "获取IOT首页的数据统计", description = "用于IOT首页的数据统计") + @Operation(summary = "获取首页的数据统计", description = "用于IOT首页的数据统计") public CommonResult getIotMainStats(@Valid IotStatisticsReqVO reqVO){ + // TODO @super:新增 get-summary 接口,返回:总数、今日新增、数量、状态 IotStatisticsRespVO iotStatisticsRespVO = new IotStatisticsRespVO(); // 获取总数 - iotStatisticsRespVO.setCategoryTotal(iotProductCategoryService.getProductCategoryCount(null)); - iotStatisticsRespVO.setProductTotal(iotProductService.getProductCount(null)); - iotStatisticsRespVO.setDeviceTotal(iotDeviceService.getDeviceCount(null)); - iotStatisticsRespVO.setReportTotal(iotDeviceLogService.getDeviceLogCount(null)); + iotStatisticsRespVO.setCategoryTotal(productCategoryService.getProductCategoryCount(null)); + iotStatisticsRespVO.setProductTotal(productService.getProductCount(null)); + iotStatisticsRespVO.setDeviceTotal(deviceService.getDeviceCount(null)); + iotStatisticsRespVO.setReportTotal(deviceLogService.getDeviceLogCount(null)); // 获取今日新增数量 LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0); - iotStatisticsRespVO.setCategoryTodayTotal(iotProductCategoryService.getProductCategoryCount(todayStart)); - iotStatisticsRespVO.setProductTodayTotal(iotProductService.getProductCount(todayStart)); - iotStatisticsRespVO.setDeviceTodayTotal(iotDeviceService.getDeviceCount(todayStart)); - iotStatisticsRespVO.setReportTodayTotal(iotDeviceLogService.getDeviceLogCount(todayStart)); + iotStatisticsRespVO.setCategoryTodayTotal(productCategoryService.getProductCategoryCount(todayStart)); + iotStatisticsRespVO.setProductTodayTotal(productService.getProductCount(todayStart)); + iotStatisticsRespVO.setDeviceTodayTotal(deviceService.getDeviceCount(todayStart)); + iotStatisticsRespVO.setReportTodayTotal(deviceLogService.getDeviceLogCount(todayStart)); // 获取各个品类下设备数量统计 iotStatisticsRespVO.setDeviceStatsOfCategory( - iotProductCategoryService.getDeviceCountsOfProductCategory() + productCategoryService.getDeviceCountsOfProductCategory() ); // 获取设备状态数量统计 - iotStatisticsRespVO.setOnlineTotal(iotDeviceService.getDeviceCountByState(IotDeviceStateEnum.ONLINE.getState())); - iotStatisticsRespVO.setOfflineTotal(iotDeviceService.getDeviceCountByState(IotDeviceStateEnum.OFFLINE.getState())); - iotStatisticsRespVO.setNeverOnlineTotal(iotDeviceService.getDeviceCountByState(IotDeviceStateEnum.INACTIVE.getState())); + iotStatisticsRespVO.setOnlineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.ONLINE.getState())); + iotStatisticsRespVO.setOfflineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.OFFLINE.getState())); + iotStatisticsRespVO.setNeverOnlineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.INACTIVE.getState())); + // TODO @super:新增 get-log-summary 接口,返回 // 根据传入时间范围获取设备上下行消息数量统计 - iotStatisticsRespVO.setDeviceUpMessageStats(iotDeviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); - iotStatisticsRespVO.setDeviceDownMessageStats(iotDeviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); + iotStatisticsRespVO.setDeviceUpMessageStats(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); + iotStatisticsRespVO.setDeviceDownMessageStats(deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); return CommonResult.success(iotStatisticsRespVO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java index 56f013963..4a225bc5a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java @@ -7,10 +7,16 @@ import lombok.Data; @Schema(description = "管理后台 - Iot统计 Request VO") @Data public class IotStatisticsReqVO { + + // TODO @supper:times 直接传递哈; + // TODO 2super:private 不要丢了 + @Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") @NotNull(message = "查询起始时间不能为空") Long startTime; + @Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") @NotNull(message = "查询结束时间不能为空") Long endTime; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java index a72c0536e..0e68c078d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java @@ -5,10 +5,16 @@ import lombok.Data; import java.util.List; -@Schema(description = "管理后台 - Iot统计 Response VO") +// TODO @super:Total 全部改成 Count +// TODO @super:IotStatisticsSummaryRespVO +/** + * 管理后台 - Iot 统计 Response VO + */ +@Schema(description = "管理后台 - Iot 统计 Response VO") @Data public class IotStatisticsRespVO { + // TODO @super:productCategory 哈 @Schema(description = "品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") private long categoryTotal; @@ -18,9 +24,11 @@ public class IotStatisticsRespVO { @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") private long deviceTotal; + // TODO @super:deviceMessageCount;设备消息数量 @Schema(description = "上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") private long reportTotal; + // TODO @super:productCategory 哈 @Schema(description = "今日新增品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") private long categoryTodayTotal; @@ -30,30 +38,42 @@ public class IotStatisticsRespVO { @Schema(description = "今日新增设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") private long deviceTodayTotal; + // TODO @super:deviceMessageCount;今日设备消息数量 @Schema(description = "今日新增上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") private long reportTodayTotal; + // TODO @super:deviceOnlineCount + @Schema(description = "在线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") private long onlineTotal; + // TODO @super:deviceOfflineCount + @Schema(description = "离线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15") private long offlineTotal; + // TODO @super:deviceInactivECount + @Schema(description = "待激活设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") private long neverOnlineTotal; + // TODO @super:1)类型改成 Map,key 分类名、value 设备数量;2)deviceStatsOfCategory => productCategoryDeviceCounts + @Schema(description = "按品类统计的设备数量") + private List deviceStatsOfCategory; + + // TODO @super:貌似界面里,用不到这个字段??? @Schema(description = "上报数据数量统计") private List reportDataStats; + // TODO @super:deviceUpMessageStats、deviceDownMessageStats 单独抽到 IotStatisticsDeviceMessageSummaryRespVO,然后里面属性就是 upstreamCounts、downstreamCounts + @Schema(description = "上行数据数量统计") private List deviceUpMessageStats; @Schema(description = "下行数据数量统计") private List deviceDownMessageStats; - @Schema(description = "按品类统计的设备数量") - private List deviceStatsOfCategory; - + // TODO @super:如果只有这两个字段,使用 KeyValue 这个键值对 @Schema(description = "时间数据") @Data public static class TimeData { @@ -63,6 +83,7 @@ public class IotStatisticsRespVO { @Schema(description = "数据值", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") private Object data; + } @Schema(description = "数据项") @@ -74,5 +95,7 @@ public class IotStatisticsRespVO { @Schema(description = "数据项值", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") private Object value; + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 0f642541e..cceeb5338 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; +import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; @@ -70,24 +71,12 @@ public interface IotDeviceMapper extends BaseMapperX { .apply("FIND_IN_SET(" + groupId + ",group_ids) > 0")); } - /** - * 统计设备数量 - * - * @param createTime 创建时间,如果为空,则统计所有设备数量 - * @return 设备数量 - */ - default Long selectCountByCreateTime(LocalDateTime createTime) { + default Long selectCountByCreateTime(@Nullable LocalDateTime createTime) { return selectCount(new LambdaQueryWrapperX() .geIfPresent(IotDeviceDO::getCreateTime, createTime)); } - /** - * 统计指定状态的设备数量 - * - * @param state 状态 - * @return 设备数量 - */ - default Long selectCountByState(Integer state) { + default Long selectCountByState(@Nullable Integer state) { return selectCount(new LambdaQueryWrapperX() .eqIfPresent(IotDeviceDO::getState, state)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java index 6e9deb4eb..dc9367bbd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductCategoryMapper.java @@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; +import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; @@ -30,13 +30,7 @@ public interface IotProductCategoryMapper extends BaseMapperX() .geIfPresent(IotProductCategoryDO::getCreateTime, createTime)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index 11a255161..f63a14be9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; +import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; @@ -31,23 +32,11 @@ public interface IotProductMapper extends BaseMapperX { .apply("LOWER(product_key) = {0}", productKey.toLowerCase())); } - /** - * 统计产品数量 - * - * @param createTime 创建时间,如果为空,则统计所有产品数量 - * @return 产品数量 - */ - default Long selectCountByCreateTime(LocalDateTime createTime) { + default Long selectCountByCreateTime(@Nullable LocalDateTime createTime) { return selectCount(new LambdaQueryWrapperX() .geIfPresent(IotProductDO::getCreateTime, createTime)); } - /** - * 获得产品列表,基于分类编号 - * - * @param categoryId 分类编号 - * @return 产品列表 - */ default List selectListByCategoryId(Long categoryId) { return selectList(new LambdaQueryWrapperX() .eq(IotProductDO::getCategoryId, categoryId) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java index 21972343f..082386b4e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java @@ -73,6 +73,7 @@ public interface IotThingModelMapper extends BaseMapperX { IotThingModelDO::getName, name); } + // TODO @super:用不到,删除下; /** * 统计物模型数量 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java index ab351e158..df64aefb3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java @@ -9,7 +9,6 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; -import java.time.LocalDateTime; import java.util.List; /** @@ -58,6 +57,8 @@ public interface IotDeviceLogMapper { */ Long selectCountByCreateTime(@Param("createTime") Long createTime); + // TODO @super:1)上行、下行,不写在 mapper 里,而是通过参数传递,这样,selectDeviceLogUpCountByHour、selectDeviceLogDownCountByHour 可以合并; + // TODO @super:2)不能只基于 identifier 来计算,而是要 type + identifier 成对 /** * 获得每个小时设备上行消息数量统计 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 151dc6266..6d48b38d2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -192,7 +192,7 @@ public interface IotDeviceService { * @param createTime 创建时间,如果为空,则统计所有设备数量 * @return 设备数量 */ - Long getDeviceCount(LocalDateTime createTime); + Long getDeviceCount(@Nullable LocalDateTime createTime); /** * 获得设备数量,基于状态 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 28925cd9d..4d4892733 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -429,6 +429,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectCountByCreateTime(createTime); } + // TODO @super:是不是 groupby 查询,更高效;不过 controller,还是要考虑 null 的情况;不过可以直接枚举 foreach 处理下 @Override public Long getDeviceCountByState(Integer state) { return deviceMapper.selectCountByState(state); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java index faff5a928..592217bb6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java @@ -5,8 +5,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogP import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; -import org.apache.ibatis.annotations.Param; +import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; @@ -45,7 +45,7 @@ public interface IotDeviceLogService { * @param createTime 创建时间,如果为空,则统计所有日志数量 * @return 日志数量 */ - Long getDeviceLogCount(LocalDateTime createTime); + Long getDeviceLogCount(@Nullable LocalDateTime createTime); /** * 获得每个小时设备上行消息数量统计 @@ -55,7 +55,9 @@ public interface IotDeviceLogService { * @param endTime 结束时间,如果为空,则不限制结束时间 * @return 每小时消息数量统计列表 */ - List getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime); + List getDeviceLogUpCountByHour(@Nullable String deviceKey, + @Nullable Long startTime, + @Nullable Long endTime); /** * 获得每个小时设备下行消息数量统计 @@ -65,6 +67,8 @@ public interface IotDeviceLogService { * @param endTime 结束时间,如果为空,则不限制结束时间 * @return 每小时消息数量统计列表 */ - List getDeviceLogDownCountByHour( String deviceKey, Long startTime, Long endTime); + List getDeviceLogDownCountByHour(@Nullable String deviceKey, + @Nullable Long startTime, + @Nullable Long endTime); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java index ea3a8ac5f..a5ac4a8c1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java @@ -73,11 +73,13 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { public Long getDeviceLogCount(LocalDateTime createTime) { Long time = null; if (createTime != null) { + // todo @super:1)LocalDateTimeUtil.toEpochMilli(createTime);2)直接表达式,更简洁 time != null ? createTime.toInstant(ZoneOffset.UTC).toEpochMilli() : null; time = createTime.toInstant(ZoneOffset.UTC).toEpochMilli(); } return deviceLogMapper.selectCountByCreateTime(time); } + // TODO @super:加一个参数,Boolean upstream:true 上行,false 下行,null 不过滤 @Override public List getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) { try { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java index b4e8fa3f9..8d6ccdada 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsR import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import jakarta.validation.Valid; +import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.Collection; import java.util.List; @@ -91,8 +92,9 @@ public interface IotProductCategoryService { * @param createTime 创建时间,如果为空,则统计所有分类数量 * @return 产品分类数量 */ - Long getProductCategoryCount(LocalDateTime createTime); + Long getProductCategoryCount(@Nullable LocalDateTime createTime); + // TODO @super:1)Map 虽然有点怪哈,然后 Controller 按需转换成 Map ;2)名字 getProductCategoryDeviceCountMap 方法 /** * 获得各个品类下设备数量统计 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java index c4af16c9d..d8b9af1fb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductCategoryMapper; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.product.IotProductCategoryService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -108,16 +107,18 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService // 1. 获取所有数据 List categoryList = productCategoryMapper.selectList(); List productList = productService.getProductList(); + // TODO @super:不要 list 查询,返回内存,而是查询一个 Map List deviceList = deviceService.getDeviceList(); // 2. 统计每个分类下的设备数量 Map categoryDeviceCountMap = new HashMap<>(); - + // 2.1 初始化所有分类的计数为0 for (IotProductCategoryDO category : categoryList) { categoryDeviceCountMap.put(category.getName(), 0); + // TODO @super:直接这里面计算,不用多个循环。产品本身也不多,不用构建 Map,直接 filter 就好了 } - + // 2.2 构建产品ID到分类的映射 Map productCategoryMap = new HashMap<>(); for (IotProductDO product : productList) { @@ -130,7 +131,7 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService productCategoryMap.put(product.getId(), category); } } - + // 2.3 统计每个分类下的设备数量 for (IotDeviceDO device : deviceList) { Long productId = device.getProductId(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 590db15a8..5d6f7c788 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProduc import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import jakarta.validation.Valid; +import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; @@ -99,8 +100,9 @@ public interface IotProductService { * @param createTime 创建时间,如果为空,则统计所有产品数量 * @return 产品数量 */ - Long getProductCount(LocalDateTime createTime); + Long getProductCount(@Nullable LocalDateTime createTime); + // TODO @super:用不到的,删除下哈 /** * 获得产品列表,基于分类编号 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java index 6eb8bb346..8834772d3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java @@ -81,6 +81,7 @@ public interface IotThingModelService { */ List getThingModelList(IotThingModelListReqVO reqVO); + // TODO @super:用不到,删除下哈。 /** * 获得物模型数量 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index 813b5ea58..9487ff2de 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -364,6 +364,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { return SpringUtil.getBean(getClass()); } + // TODO @super:用不到,删除下; @Override public Long getThingModelCount(LocalDateTime createTime) { return thingModelMapper.selectCountByCreateTime(createTime); From 0302ebee9915bc6abb3435c11df47dff57b9bbc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E7=8E=84=E7=A4=BC?= Date: Thu, 27 Feb 2025 23:07:09 +0800 Subject: [PATCH 189/228] =?UTF-8?q?refactor(iot):=20=E4=BC=98=E5=8C=96=20O?= =?UTF-8?q?TA=20=E5=8D=87=E7=BA=A7=E8=AE=B0=E5=BD=95=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重写 getOtaUpgradeRecordCount 和 getOtaUpgradeRecordStatistics 方法,使用 MyBatis-Plus 的 LambdaQueryWrapperX -移除 XML 中对应的 SQL 查询语句 - 提高代码可维护性和数据库兼容性 --- .../mysql/ota/IotOtaUpgradeRecordMapper.java | 20 ++++++++++++++----- .../mapper/ota/IotOtaUpgradeRecordMapper.xml | 17 ---------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java index 35a164ca2..83bdb4306 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -13,6 +13,7 @@ import org.apache.ibatis.annotations.Param; import java.util.List; // TODO @li:这里的注释,可以去掉哈,多了点点 + /** * OTA 升级记录 Mapper 接口 */ @@ -43,9 +44,14 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX() + .eqIfPresent(IotOtaUpgradeRecordDO::getTaskId, taskId) + .likeIfPresent(IotOtaUpgradeRecordDO::getDeviceId, deviceName) + .eqIfPresent(IotOtaUpgradeRecordDO::getStatus, status)); + } /** * 获取OTA升级记录的统计信息 @@ -54,8 +60,12 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX() + .eqIfPresent(IotOtaUpgradeRecordDO::getFirmwareId, firmwareId) + .eqIfPresent(IotOtaUpgradeRecordDO::getStatus, status)); + } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml index ea86ba5c4..74fa85eac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml @@ -4,21 +4,4 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - - - - - - \ No newline at end of file From 4629084c1ba1411109403dcec1f11b6096b46f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E7=8E=84=E7=A4=BC?= Date: Thu, 27 Feb 2025 23:18:25 +0800 Subject: [PATCH 190/228] =?UTF-8?q?refactor(iot):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=E8=AE=B0=E5=BD=95=E7=8A=B6=E6=80=81=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改 IotOtaUpgradeRecordMapper 中的 cancelUpgradeRecordByTaskId 方法- 新增 updateUpgradeRecordStatusByTaskIdAndStatus 方法,用于更通用的状态更新 - 在 IotOtaUpgradeRecordServiceImpl 中调用新方法来取消升级记录 --- .../mysql/ota/IotOtaUpgradeRecordMapper.java | 19 ++++++++++--------- .../ota/IotOtaUpgradeRecordServiceImpl.java | 4 +++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java index 83bdb4306..bba148a59 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -82,18 +81,20 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX + * 该函数用于将符合指定任务ID和状态的升级记录的状态更新为新的状态。 * - * @param taskId 任务ID,用于查找对应的升级记录。 + * @param setStatus 要设置的新状态值,类型为Integer + * @param taskId 要更新的升级记录对应的任务ID,类型为Long + * @param whereStatus 用于筛选升级记录的当前状态值,类型为Integer */ - default void cancelUpgradeRecordByTaskId(Long taskId) { - // 使用LambdaUpdateWrapper构建更新条件,将状态为“待处理”的记录更新为“已取消” - // TODO @li:哪些可以更新,通过 service 传递。mapper 尽量不要有逻辑 + default void updateUpgradeRecordStatusByTaskIdAndStatus(Integer setStatus, Long taskId, Integer whereStatus) { + // 使用LambdaUpdateWrapper构建更新条件,将指定状态的记录更新为指定状态 update(new LambdaUpdateWrapper() - .set(IotOtaUpgradeRecordDO::getStatus, IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()) + .set(IotOtaUpgradeRecordDO::getStatus, setStatus) .eq(IotOtaUpgradeRecordDO::getTaskId, taskId) - .eq(IotOtaUpgradeRecordDO::getStatus, IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()) + .eq(IotOtaUpgradeRecordDO::getStatus, whereStatus) ); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java index ae2b68273..5738f5763 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java @@ -134,7 +134,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Override public void cancelUpgradeRecordByTaskId(Long taskId) { // 暂定只有待推送的升级记录可以取消 - upgradeRecordMapper.cancelUpgradeRecordByTaskId(taskId); + upgradeRecordMapper.updateUpgradeRecordStatusByTaskIdAndStatus( + IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus(), taskId, + IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); } @Override From 4e33cd2bde4917307a0429f14986a89b3a57e160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E7=8E=84=E7=A4=BC?= Date: Thu, 27 Feb 2025 23:28:04 +0800 Subject: [PATCH 191/228] =?UTF-8?q?refactor(iot):=20=E4=BC=98=E5=8C=96=20O?= =?UTF-8?q?TA=20=E7=9B=B8=E5=85=B3=20Mapper=20=E6=8E=A5=E5=8F=A3=E7=9A=84?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除了多余的 TODO 注释 - 更新了 IotOtaFirmwareMapper、IotOtaUpgradeRecordMapper 和 IotOtaUpgradeTaskMapper 的类注释 - 统一了注释格式,增加了作者信息 --- .../module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java | 6 +++--- .../iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java | 6 +++--- .../module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java | 7 +++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java index 9bd461916..9652942b2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java @@ -9,10 +9,10 @@ import org.apache.ibatis.annotations.Mapper; import java.util.List; -// TODO @li:这里的注释,可以去掉哈,多了点点 /** - * IotOtaFirmwareMapper 接口用于操作 IotOtaFirmwareDO 实体类对应的数据库表。 - * 该接口继承自 BaseMapperX,提供了基本的 CRUD 操作,并扩展了特定查询方法。 + * OTA固件 Mapper + * + * @author Shelly */ @Mapper public interface IotOtaFirmwareMapper extends BaseMapperX { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java index bba148a59..b48131c61 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -11,10 +11,10 @@ import org.apache.ibatis.annotations.Param; import java.util.List; -// TODO @li:这里的注释,可以去掉哈,多了点点 - /** - * OTA 升级记录 Mapper 接口 + * OTA 升级记录 Mapper + * + * @author Shelly */ @Mapper public interface IotOtaUpgradeRecordMapper extends BaseMapperX { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java index 80c3ff565..d955b1361 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java @@ -9,10 +9,10 @@ import org.apache.ibatis.annotations.Mapper; import java.util.List; -// TODO @li:这里的注释,可以去掉哈,多了点点 /** - * IotOtaUpgradeTaskMapper 接口用于操作 IotOtaUpgradeTaskDO 数据库表。 - * 该接口继承自 BaseMapperX,提供了基本的数据库操作方法。 + * OTA 升级任务Mapper + * + * @author Shelly */ @Mapper public interface IotOtaUpgradeTaskMapper extends BaseMapperX { @@ -54,5 +54,4 @@ public interface IotOtaUpgradeTaskMapper extends BaseMapperX Date: Fri, 28 Feb 2025 14:46:02 +0800 Subject: [PATCH 192/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT:=20=E6=96=B0=E5=A2=9E=20Kafka=20=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=A1=A5=E6=A2=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 8 +- yudao-module-iot/yudao-module-iot-biz/pom.xml | 5 + .../dal/dataobject/rule/IotDataBridgeDO.java | 34 +++++ .../AbstractCacheableDataBridgeExecute.java | 2 +- .../databridge/IotDataBridgeExecute.java | 2 +- .../databridge/IotHttpDataBridgeExecute.java | 2 +- .../IotKafkaMQDataBridgeExecute.java | 124 ++++++++++++++++++ .../IotRocketMQDataBridgeExecute.java | 2 +- 8 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 23859c783..7bdba6462 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -35,6 +35,7 @@ 3.3.3 2.3.2 + 3.3.3 2.2.7 @@ -285,13 +286,16 @@ yudao-spring-boot-starter-mq ${revision} - org.apache.rocketmq rocketmq-spring-boot-starter ${rocketmq-spring.version} - + + org.springframework.kafka + spring-kafka + ${kafka-spring.version} + cn.iocoder.boot diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index ea1dde86f..1c07e4940 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -81,6 +81,11 @@ rocketmq-spring-boot-starter true + + org.springframework.kafka + spring-kafka + true + org.pf4j diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index 213b0cda1..220edef71 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -170,4 +170,38 @@ public class IotDataBridgeDO extends BaseDO { } + /** + * Kafka 配置 + */ + @Data + public static class KafkaMQConfig implements Config { + + /** + * Kafka 服务器地址 + */ + private String bootstrapServers; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + /** + * 是否启用 SSL + */ + private Boolean ssl; + + /** + * 生产者组 ID + */ + private String groupId; + /** + * 主题 + */ + private String topic; + + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java index 264bce553..e8fbb0ccb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java @@ -8,7 +8,7 @@ import lombok.extern.slf4j.Slf4j; import java.time.Duration; /** - * 带缓存功能的数据桥接执行器抽象类 + * 带缓存功能的数据桥梁执行器抽象类 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java index cd00f4f3e..1617c3b09 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; public interface IotDataBridgeExecute { /** - * 执行数据桥接操作 + * 执行数据桥梁操作 * * @param message 设备消息 * @param dataBridge 数据桥梁 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java index 76f1b793f..27b8bc6bb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java @@ -32,7 +32,7 @@ public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { @Override public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { - // 1.1 校验数据桥接的类型 == HTTP + // 1.1 校验数据桥梁的类型 == HTTP if (!IotDataBridgTypeEnum.HTTP.getType().equals(dataBridge.getType())) { return; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java new file mode 100644 index 000000000..8c0ef2b03 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -0,0 +1,124 @@ +package cn.iocoder.yudao.module.iot.service.rule.action.databridge; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * Kafka 的 {@link IotDataBridgeExecute} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { + + @Override + public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { + // 1.1 校验数据桥梁的类型 == KAFKA + if (!IotDataBridgTypeEnum.KAFKA.getType().equals(dataBridge.getType())) { + return; + } + // 1.2 执行 Kafka 发送消息 + executeKafka(message, (IotDataBridgeDO.KafkaMQConfig) dataBridge.getConfig()); + } + + private void executeKafka(IotDeviceMessage message, IotDataBridgeDO.KafkaMQConfig config) { + try { + // 1. 获取或创建 KafkaTemplate + KafkaTemplate kafkaTemplate = (KafkaTemplate) getProducer(config); + + // 2. 发送消息并等待结果 + kafkaTemplate.send(config.getTopic(), message.toString()) + .get(10, TimeUnit.SECONDS); // 添加超时等待 + log.info("[executeKafka][message({}) 发送成功]", message); + } catch (TimeoutException e) { + log.error("[executeKafka][message({}) config({}) 发送超时]", message, config, e); + } catch (Exception e) { + log.error("[executeKafka][message({}) config({}) 发送异常]", message, config, e); + } + } + + @Override + protected Object initProducer(Object config) { + IotDataBridgeDO.KafkaMQConfig kafkaConfig = (IotDataBridgeDO.KafkaMQConfig) config; + + // 1.1 构建生产者配置 + Map props = new HashMap<>(); + props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServers()); + props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + + // 1.2 如果配置了认证信息 + if (kafkaConfig.getUsername() != null && kafkaConfig.getPassword() != null) { + props.put("security.protocol", "SASL_PLAINTEXT"); + props.put("sasl.mechanism", "PLAIN"); + props.put("sasl.jaas.config", + "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"" + + kafkaConfig.getUsername() + "\" password=\"" + kafkaConfig.getPassword() + "\";"); + } + + // 1.3 如果启用 SSL + if (Boolean.TRUE.equals(kafkaConfig.getSsl())) { + props.put("security.protocol", "SSL"); + } + + // 2. 创建 KafkaTemplate + DefaultKafkaProducerFactory producerFactory = new DefaultKafkaProducerFactory<>(props); + return new KafkaTemplate<>(producerFactory); + } + + @Override + protected void closeProducer(Object producer) { + if (producer instanceof KafkaTemplate) { + ((KafkaTemplate) producer).destroy(); + } + } + + // TODO @芋艿:测试代码,后续清理 + public static void main(String[] args) { + // 1. 创建一个共享的实例 + IotKafkaMQDataBridgeExecute action = new IotKafkaMQDataBridgeExecute(); + + // 2. 创建共享的配置 + IotDataBridgeDO.KafkaMQConfig config = new IotDataBridgeDO.KafkaMQConfig(); + config.setBootstrapServers("127.0.0.1:9092"); + config.setTopic("test-topic"); + config.setSsl(false); + config.setUsername(null); + config.setPassword(null); + + // 3. 创建共享的消息 + IotDeviceMessage message = IotDeviceMessage.builder() + .requestId("TEST-001") + .productKey("testProduct") + .deviceName("testDevice") + .deviceKey("testDeviceKey") + .type("property") + .identifier("temperature") + .data("{\"value\": 60}") + .reportTime(LocalDateTime.now()) + .tenantId(1L) + .build(); + + // 4. 执行两次测试,验证缓存 + log.info("[main][第一次执行,应该会创建新的 producer]"); + action.executeKafka(message, config); + + log.info("[main][第二次执行,应该会复用缓存的 producer]"); + action.executeKafka(message, config); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index af701cd90..3b5325253 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -24,7 +24,7 @@ public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExe @Override public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { - // 1.1 校验数据桥接的类型 == ROCKETMQ + // 1.1 校验数据桥梁的类型 == ROCKETMQ if (!IotDataBridgTypeEnum.ROCKETMQ.getType().equals(dataBridge.getType())) { return; } From 0f0ebda4692da2044ca6b27c44de5de45e5e91da Mon Sep 17 00:00:00 2001 From: alwayssuper <191763414@qq.com> Date: Fri, 28 Feb 2025 15:28:38 +0800 Subject: [PATCH 193/228] =?UTF-8?q?[fix]=EF=BC=9Aiot=20home=20count?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../statistics/IotStatisticsController.java | 51 ++++++++------- ...tStatisticsDeviceMessageSummaryRespVO.java | 19 ++++++ .../statistics/vo/IotStatisticsReqVO.java | 8 +-- ...O.java => IotStatisticsSummaryRespVO.java} | 62 +++++-------------- .../iot/dal/mysql/device/IotDeviceMapper.java | 17 +++++ .../dal/mysql/product/IotProductMapper.java | 5 -- .../iot/dal/tdengine/IotDeviceLogMapper.java | 28 +++------ .../iot/service/device/IotDeviceService.java | 26 +++++--- .../service/device/IotDeviceServiceImpl.java | 25 ++++++-- .../device/data/IotDeviceLogService.java | 31 +++++----- .../device/data/IotDeviceLogServiceImpl.java | 56 +++++++++-------- .../product/IotProductCategoryService.java | 3 +- .../IotProductCategoryServiceImpl.java | 54 ++++------------ .../service/product/IotProductService.java | 8 --- .../product/IotProductServiceImpl.java | 4 -- .../mapper/device/IotDeviceLogMapper.xml | 4 +- .../mapper/device/IotDeviceMapper.xml | 25 ++++++++ 17 files changed, 217 insertions(+), 209 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/{IotStatisticsRespVO.java => IotStatisticsSummaryRespVO.java} (59%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java index bb5fa92ae..c4ef83a4a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java @@ -1,8 +1,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO; import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsSummaryRespVO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; @@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; +import java.util.Map; @Tag(name = "管理后台 - IoT 数据统计") @RestController @@ -35,38 +37,41 @@ public class IotStatisticsController { private IotDeviceLogService deviceLogService; // TODO @super:description 非必要,可以不写哈 - @GetMapping("/main") - @Operation(summary = "获取首页的数据统计", description = "用于IOT首页的数据统计") - public CommonResult getIotMainStats(@Valid IotStatisticsReqVO reqVO){ - // TODO @super:新增 get-summary 接口,返回:总数、今日新增、数量、状态 - IotStatisticsRespVO iotStatisticsRespVO = new IotStatisticsRespVO(); + @GetMapping("/get-summary") + @Operation(summary = "获取IOT数据统计") + public CommonResult getIotStatisticsSummary(){ + IotStatisticsSummaryRespVO respVO = new IotStatisticsSummaryRespVO(); // 获取总数 - iotStatisticsRespVO.setCategoryTotal(productCategoryService.getProductCategoryCount(null)); - iotStatisticsRespVO.setProductTotal(productService.getProductCount(null)); - iotStatisticsRespVO.setDeviceTotal(deviceService.getDeviceCount(null)); - iotStatisticsRespVO.setReportTotal(deviceLogService.getDeviceLogCount(null)); + respVO.setProductCategoryCount(productCategoryService.getProductCategoryCount(null)); + respVO.setProductCount(productService.getProductCount(null)); + respVO.setDeviceCount(deviceService.getDeviceCount(null)); + respVO.setDeviceMessageCount(deviceLogService.getDeviceLogCount(null)); // 获取今日新增数量 LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0); - iotStatisticsRespVO.setCategoryTodayTotal(productCategoryService.getProductCategoryCount(todayStart)); - iotStatisticsRespVO.setProductTodayTotal(productService.getProductCount(todayStart)); - iotStatisticsRespVO.setDeviceTodayTotal(deviceService.getDeviceCount(todayStart)); - iotStatisticsRespVO.setReportTodayTotal(deviceLogService.getDeviceLogCount(todayStart)); + respVO.setProductCategoryTodayCount(productCategoryService.getProductCategoryCount(todayStart)); + respVO.setProductTodayCount(productService.getProductCount(todayStart)); + respVO.setDeviceTodayCount(deviceService.getDeviceCount(todayStart)); + respVO.setDeviceMessageTodayCount(deviceLogService.getDeviceLogCount(todayStart)); // 获取各个品类下设备数量统计 - iotStatisticsRespVO.setDeviceStatsOfCategory( - productCategoryService.getDeviceCountsOfProductCategory() - ); + respVO.setProductCategoryDeviceCounts(productCategoryService.getProductCategoryDeviceCountMap()); // 获取设备状态数量统计 - iotStatisticsRespVO.setOnlineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.ONLINE.getState())); - iotStatisticsRespVO.setOfflineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.OFFLINE.getState())); - iotStatisticsRespVO.setNeverOnlineTotal(deviceService.getDeviceCountByState(IotDeviceStateEnum.INACTIVE.getState())); + Map deviceCountMap = deviceService.getDeviceCountMapByState(); + respVO.setDeviceOnlineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.ONLINE.getState(), 0L)); + respVO.setDeviceOfflineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.OFFLINE.getState(), 0L)); + respVO.setDeviceInactiveCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.INACTIVE.getState(), 0L)); - // TODO @super:新增 get-log-summary 接口,返回 + return CommonResult.success(respVO); + } + @GetMapping("/get-log-summary") + @Operation(summary = "获取IOT上下行消息数据统计") + public CommonResult getIotStatisticsDeviceMessageSummary(@Valid IotStatisticsReqVO reqVO){ // 根据传入时间范围获取设备上下行消息数量统计 - iotStatisticsRespVO.setDeviceUpMessageStats(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); - iotStatisticsRespVO.setDeviceDownMessageStats(deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); + IotStatisticsDeviceMessageSummaryRespVO iotStatisticsRespVO = new IotStatisticsDeviceMessageSummaryRespVO(); + iotStatisticsRespVO.setUpstreamCounts(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); + iotStatisticsRespVO.setDownstreamCounts(deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); return CommonResult.success(iotStatisticsRespVO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java new file mode 100644 index 000000000..250c63e2a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Schema(description = "管理后台 - Iot 上下行消息数量统计 Response VO") +@Data +public class IotStatisticsDeviceMessageSummaryRespVO { + @Schema(description = "每小时上行数据数量统计") + private List> upstreamCounts; + + @Schema(description = "每小时下行数据数量统计") + private List> downstreamCounts; + + // TODO @super:如果只有这两个字段,使用 KeyValue 这个键值对 +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java index 4a225bc5a..acffe1299 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java @@ -11,12 +11,12 @@ public class IotStatisticsReqVO { // TODO @supper:times 直接传递哈; // TODO 2super:private 不要丢了 - @Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1658486600000") @NotNull(message = "查询起始时间不能为空") - Long startTime; + private Long startTime; - @Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @Schema(description = "查询结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1758486600000") @NotNull(message = "查询结束时间不能为空") - Long endTime; + private Long endTime; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java similarity index 59% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java index 0e68c078d..0ad1f9ff4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.statistics.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import java.util.List; +import java.util.Map; // TODO @super:Total 全部改成 Count // TODO @super:IotStatisticsSummaryRespVO @@ -12,90 +12,58 @@ import java.util.List; */ @Schema(description = "管理后台 - Iot 统计 Response VO") @Data -public class IotStatisticsRespVO { +public class IotStatisticsSummaryRespVO { // TODO @super:productCategory 哈 @Schema(description = "品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private long categoryTotal; + private long productCategoryCount; @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") - private long productTotal; + private long productCount; @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - private long deviceTotal; + private long deviceCount; // TODO @super:deviceMessageCount;设备消息数量 @Schema(description = "上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") - private long reportTotal; + private long deviceMessageCount; // TODO @super:productCategory 哈 @Schema(description = "今日新增品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private long categoryTodayTotal; + private long productCategoryTodayCount; @Schema(description = "今日新增产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") - private long productTodayTotal; + private long productTodayCount; @Schema(description = "今日新增设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - private long deviceTodayTotal; + private long deviceTodayCount; // TODO @super:deviceMessageCount;今日设备消息数量 @Schema(description = "今日新增上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") - private long reportTodayTotal; + private long deviceMessageTodayCount; // TODO @super:deviceOnlineCount @Schema(description = "在线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") - private long onlineTotal; + private long deviceOnlineCount; // TODO @super:deviceOfflineCount @Schema(description = "离线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15") - private long offlineTotal; + private long deviceOfflineCount; // TODO @super:deviceInactivECount @Schema(description = "待激活设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") - private long neverOnlineTotal; + private long deviceInactiveCount; // TODO @super:1)类型改成 Map,key 分类名、value 设备数量;2)deviceStatsOfCategory => productCategoryDeviceCounts @Schema(description = "按品类统计的设备数量") - private List deviceStatsOfCategory; + private Map productCategoryDeviceCounts; // TODO @super:貌似界面里,用不到这个字段??? - @Schema(description = "上报数据数量统计") - private List reportDataStats; + // TODO @super:deviceUpMessageStats、deviceDownMessageStats 单独抽到 IotStatisticsDeviceMessageSummaryRespVO,然后里面属性就是 upstreamCounts、downstreamCounts - @Schema(description = "上行数据数量统计") - private List deviceUpMessageStats; - - @Schema(description = "下行数据数量统计") - private List deviceDownMessageStats; - - // TODO @super:如果只有这两个字段,使用 KeyValue 这个键值对 - @Schema(description = "时间数据") - @Data - public static class TimeData { - - @Schema(description = "时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1646092800000") - private long time; - - @Schema(description = "数据值", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - private Object data; - - } - - @Schema(description = "数据项") - @Data - public static class DataItem { - - @Schema(description = "数据项名", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能家居") - private String name; - - @Schema(description = "数据项值", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") - private Object value; - - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index cceeb5338..128b026f5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -8,10 +8,13 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePa import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * IoT 设备 Mapper @@ -81,4 +84,18 @@ public interface IotDeviceMapper extends BaseMapperX { .eqIfPresent(IotDeviceDO::getState, state)); } + /** + * 查询指定产品下各状态的设备数量 + * + * @return 设备数量统计列表 + */ + List> selectDeviceCountMapByProductId(); + + /** + * 查询各个状态下的设备数量 + * + * @return 设备数量统计列表 + */ + List> selectDeviceCountGroupByState(); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index f63a14be9..5ba4a8177 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -37,10 +37,5 @@ public interface IotProductMapper extends BaseMapperX { .geIfPresent(IotProductDO::getCreateTime, createTime)); } - default List selectListByCategoryId(Long categoryId) { - return selectList(new LambdaQueryWrapperX() - .eq(IotProductDO::getCategoryId, categoryId) - .orderByDesc(IotProductDO::getId)); - } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java index df64aefb3..9efe2ec80 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.tdengine; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; @@ -10,6 +9,7 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; +import java.util.Map; /** * 设备日志 {@link IotDeviceLogDO} Mapper 接口 @@ -60,27 +60,17 @@ public interface IotDeviceLogMapper { // TODO @super:1)上行、下行,不写在 mapper 里,而是通过参数传递,这样,selectDeviceLogUpCountByHour、selectDeviceLogDownCountByHour 可以合并; // TODO @super:2)不能只基于 identifier 来计算,而是要 type + identifier 成对 /** - * 获得每个小时设备上行消息数量统计 - * - * @param deviceKey 设备标识 - * @param startTime 开始时间 - * @param endTime 结束时间 - * @return 每小时消息数量统计 + * 查询每个小时设备上行消息数量 */ - List selectDeviceLogUpCountByHour(@Param("deviceKey") String deviceKey, - @Param("startTime") Long startTime, - @Param("endTime") Long endTime); + List> selectDeviceLogUpCountByHour(@Param("deviceKey") String deviceKey, + @Param("startTime") Long startTime, + @Param("endTime") Long endTime); /** - * 获得每个小时设备下行消息数量统计 - * - * @param deviceKey 设备标识 - * @param startTime 开始时间 - * @param endTime 结束时间 - * @return 每小时消息数量统计 + * 查询每个小时设备下行消息数量 */ - List selectDeviceLogDownCountByHour(@Param("deviceKey") String deviceKey, - @Param("startTime") Long startTime, - @Param("endTime") Long endTime); + List> selectDeviceLogDownCountByHour(@Param("deviceKey") String deviceKey, + @Param("startTime") Long startTime, + @Param("endTime") Long endTime); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 6d48b38d2..0e50f4a27 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; @@ -10,6 +11,7 @@ import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.Collection; import java.util.List; +import java.util.Map; /** * IoT 设备 Service 接口 @@ -111,7 +113,7 @@ public interface IotDeviceService { IotDeviceDO getDeviceByDeviceKey(String deviceKey); /** - * ��得设备分页 + * 获得设备分页 * * @param pageReqVO 分页查询 * @return IoT 设备分页 @@ -194,13 +196,6 @@ public interface IotDeviceService { */ Long getDeviceCount(@Nullable LocalDateTime createTime); - /** - * 获得设备数量,基于状态 - * - * @param state 状态 - * @return 设备数量 - */ - Long getDeviceCountByState(Integer state); /** * 获得所有设备列表 @@ -217,4 +212,19 @@ public interface IotDeviceService { */ IotDeviceMqttConnectionParamsRespVO getMqttConnectionParams(Long deviceId); + /** + * 获得各个产品下的设备数量 Map + * + * @return key: 产品编号, value: 设备数量 + */ + Map getDeviceCountMapByProductId(); + + /** + * 获得各个状态下的设备数量 Map + * + * @return key: 设备状态枚举 {@link IotDeviceStateEnum} + * value: 设备数量 + */ + Map getDeviceCountMapByState(); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 4d4892733..b6c0969d1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -35,6 +35,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.*; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -430,14 +431,30 @@ public class IotDeviceServiceImpl implements IotDeviceService { } // TODO @super:是不是 groupby 查询,更高效;不过 controller,还是要考虑 null 的情况;不过可以直接枚举 foreach 处理下 - @Override - public Long getDeviceCountByState(Integer state) { - return deviceMapper.selectCountByState(state); - } @Override public List getDeviceList() { return deviceMapper.selectList(); } + @Override + public Map getDeviceCountMapByProductId() { + // 查询结果转换成Map + List> list = deviceMapper.selectDeviceCountMapByProductId(); + return list.stream().collect(Collectors.toMap( + map -> Long.valueOf(map.get("key").toString()), + map -> Integer.valueOf(map.get("value").toString()) + )); + } + + @Override + public Map getDeviceCountMapByState() { + // 查询结果转换成Map + List> list = deviceMapper.selectDeviceCountGroupByState(); + return list.stream().collect(Collectors.toMap( + map -> Integer.valueOf(map.get("key").toString()), + map -> Long.valueOf(map.get("value").toString()) + )); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java index 592217bb6..e1a15aaa1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java @@ -2,13 +2,14 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; /** * IoT 设备日志数据 Service 接口 @@ -50,25 +51,25 @@ public interface IotDeviceLogService { /** * 获得每个小时设备上行消息数量统计 * - * @param deviceKey 设备标识,如果为空,则统计所有设备 - * @param startTime 开始时间,如果为空,则不限制开始时间 - * @param endTime 结束时间,如果为空,则不限制结束时间 - * @return 每小时消息数量统计列表 + * @param deviceKey 设备标识 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return key: 时间戳, value: 消息数量 */ - List getDeviceLogUpCountByHour(@Nullable String deviceKey, - @Nullable Long startTime, - @Nullable Long endTime); + List> getDeviceLogUpCountByHour(@Nullable String deviceKey, + @Nullable Long startTime, + @Nullable Long endTime); /** * 获得每个小时设备下行消息数量统计 * - * @param deviceKey 设备标识,如果为空,则统计所有设备 - * @param startTime 开始时间,如果为空,则不限制开始时间 - * @param endTime 结束时间,如果为空,则不限制结束时间 - * @return 每小时消息数量统计列表 + * @param deviceKey 设备标识 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return key: 时间戳, value: 消息数量 */ - List getDeviceLogDownCountByHour(@Nullable String deviceKey, - @Nullable Long startTime, - @Nullable Long endTime); + List> getDeviceLogDownCountByHour(@Nullable String deviceKey, + @Nullable Long startTime, + @Nullable Long endTime); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java index a5ac4a8c1..29b57402b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java @@ -1,12 +1,13 @@ package cn.iocoder.yudao.module.iot.service.device.data; +import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; @@ -17,10 +18,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.sql.Timestamp; import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * IoT 设备日志数据 Service 实现类 @@ -71,37 +73,39 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { @Override public Long getDeviceLogCount(LocalDateTime createTime) { - Long time = null; - if (createTime != null) { // todo @super:1)LocalDateTimeUtil.toEpochMilli(createTime);2)直接表达式,更简洁 time != null ? createTime.toInstant(ZoneOffset.UTC).toEpochMilli() : null; - time = createTime.toInstant(ZoneOffset.UTC).toEpochMilli(); - } - return deviceLogMapper.selectCountByCreateTime(time); + return deviceLogMapper.selectCountByCreateTime(createTime != null ? LocalDateTimeUtil.toEpochMilli(createTime) : null); } // TODO @super:加一个参数,Boolean upstream:true 上行,false 下行,null 不过滤 @Override - public List getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) { - try { - return deviceLogMapper.selectDeviceLogUpCountByHour(deviceKey, startTime, endTime); - } catch (Exception exception) { - if (exception.getMessage().contains("Table does not exist")) { - return new ArrayList<>(); - } - throw exception; - } + public List> getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) { + List> list = deviceLogMapper.selectDeviceLogUpCountByHour(deviceKey, startTime, endTime); + return list.stream() + .map(map -> { + // 从Timestamp获取时间戳 + Timestamp timestamp = (Timestamp) map.get("time"); + Long timeMillis = timestamp.getTime(); + // 消息数量转换 + Integer count = ((Number) map.get("data")).intValue(); + return Map.of(timeMillis, count); + }) + .collect(Collectors.toList()); } @Override - public List getDeviceLogDownCountByHour(String deviceKey, Long startTime, Long endTime) { - try { - return deviceLogMapper.selectDeviceLogDownCountByHour(deviceKey, startTime, endTime); - } catch (Exception exception) { - if (exception.getMessage().contains("Table does not exist")) { - return new ArrayList<>(); - } - throw exception; - } + public List> getDeviceLogDownCountByHour(String deviceKey, Long startTime, Long endTime) { + List> list = deviceLogMapper.selectDeviceLogDownCountByHour(deviceKey, startTime, endTime); + return list.stream() + .map(map -> { + // 从Timestamp获取时间戳 + Timestamp timestamp = (Timestamp) map.get("time"); + Long timeMillis = timestamp.getTime(); + // 消息数量转换 + Integer count = ((Number) map.get("data")).intValue(); + return Map.of(timeMillis, count); + }) + .collect(Collectors.toList()); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java index 8d6ccdada..662d161c1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.service.product; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import jakarta.validation.Valid; @@ -100,6 +99,6 @@ public interface IotProductCategoryService { * * @return 品类设备统计列表 */ - List getDeviceCountsOfProductCategory(); + Map getProductCategoryDeviceCountMap(); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java index d8b9af1fb..5499937fd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java @@ -5,8 +5,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategoryPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.category.IotProductCategorySaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsRespVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductCategoryDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductCategoryMapper; @@ -16,11 +14,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS; @@ -103,54 +97,30 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService } @Override - public List getDeviceCountsOfProductCategory() { + public Map getProductCategoryDeviceCountMap() { // 1. 获取所有数据 List categoryList = productCategoryMapper.selectList(); List productList = productService.getProductList(); // TODO @super:不要 list 查询,返回内存,而是查询一个 Map - List deviceList = deviceService.getDeviceList(); + Map deviceCountMapByProductId = deviceService.getDeviceCountMapByProductId(); // 2. 统计每个分类下的设备数量 Map categoryDeviceCountMap = new HashMap<>(); - + // 2.1 初始化所有分类的计数为0 for (IotProductCategoryDO category : categoryList) { categoryDeviceCountMap.put(category.getName(), 0); - // TODO @super:直接这里面计算,不用多个循环。产品本身也不多,不用构建 Map,直接 filter 就好了 - } - - // 2.2 构建产品ID到分类的映射 - Map productCategoryMap = new HashMap<>(); - for (IotProductDO product : productList) { - Long categoryId = product.getCategoryId(); - IotProductCategoryDO category = categoryList.stream() - .filter(c -> c.getId().equals(categoryId)) - .findFirst() - .orElse(null); - if (category != null) { - productCategoryMap.put(product.getId(), category); + + // 2.2 找到该分类下的所有产品,累加设备数量 + for (IotProductDO product : productList) { + if (Objects.equals(product.getCategoryId(), category.getId())) { + Integer deviceCount = deviceCountMapByProductId.getOrDefault(product.getId(), 0); + categoryDeviceCountMap.merge(category.getName(), deviceCount, Integer::sum); + } } } - // 2.3 统计每个分类下的设备数量 - for (IotDeviceDO device : deviceList) { - Long productId = device.getProductId(); - IotProductCategoryDO category = productCategoryMap.get(productId); - if (category != null) { - String categoryName = category.getName(); - categoryDeviceCountMap.merge(categoryName, 1, Integer::sum); - } - } - - // 3. 转换为 DataItem 列表 - return categoryDeviceCountMap.entrySet().stream() - .map(entry -> { - IotStatisticsRespVO.DataItem dataItem = new IotStatisticsRespVO.DataItem(); - dataItem.setName(entry.getKey()); - dataItem.setValue(entry.getValue()); - return dataItem; - }) - .collect(Collectors.toList()); + return categoryDeviceCountMap; } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 5d6f7c788..8497d73aa 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -102,13 +102,5 @@ public interface IotProductService { */ Long getProductCount(@Nullable LocalDateTime createTime); - // TODO @super:用不到的,删除下哈 - /** - * 获得产品列表,基于分类编号 - * - * @param categoryId 分类编号 - * @return 产品列表 - */ - List getProductListByCategoryId(Long categoryId); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 848da74d6..4a7263c27 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -143,9 +143,5 @@ public class IotProductServiceImpl implements IotProductService { return productMapper.selectCountByCreateTime(createTime); } - @Override - public List getProductListByCategoryId(Long categoryId) { - return productMapper.selectListByCategoryId(categoryId); - } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml index 4a4c3d6bd..932a9a862 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml @@ -65,7 +65,7 @@ - SELECT TIMETRUNCATE(ts, 1h) as time, COUNT(*) as data @@ -93,7 +93,7 @@ ORDER BY time ASC - SELECT TIMETRUNCATE(ts, 1h) as time, COUNT(*) as data diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml new file mode 100644 index 000000000..8404729cc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file From 7b449b81e7be2671446a94a74c9c539f6c9be2a8 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 28 Feb 2025 18:03:34 +0800 Subject: [PATCH 194/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT:=20=E6=96=B0=E5=A2=9E=20RabbitMQ=20?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 7 + yudao-module-iot/yudao-module-iot-biz/pom.xml | 5 + .../dal/dataobject/rule/IotDataBridgeDO.java | 41 ++++++ .../IotRabbitMQDataBridgeExecute.java | 126 ++++++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 7bdba6462..fa54eef60 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -36,6 +36,7 @@ 2.3.2 3.3.3 + 3.4.3 2.2.7 @@ -296,6 +297,12 @@ spring-kafka ${kafka-spring.version} + + org.springframework.boot + spring-boot-starter-amqp + ${rabbitmq-spring.version} + + cn.iocoder.boot diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 1c07e4940..1b897c5d7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -86,6 +86,11 @@ spring-kafka true + + org.springframework.boot + spring-boot-starter-amqp + true + org.pf4j diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index 220edef71..e95cb695e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -204,4 +204,45 @@ public class IotDataBridgeDO extends BaseDO { } + /** + * RabbitMQ 配置 + */ + @Data + public static class RabbitMQConfig implements Config { + + /** + * RabbitMQ 服务器地址 + */ + private String host; + /** + * 端口 + */ + private Integer port; + /** + * 虚拟主机 + */ + private String virtualHost; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + + /** + * 交换机名称 + */ + private String exchange; + /** + * 路由键 + */ + private String routingKey; + /** + * 队列名称 + */ + private String queue; + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java new file mode 100644 index 000000000..2c257051f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.iot.service.rule.action.databridge; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; + +/** + * RabbitMQ 的 {@link IotDataBridgeExecute} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { + + @Override + public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { + // 1.1 校验数据桥梁的类型 == RABBITMQ + if (!IotDataBridgTypeEnum.RABBITMQ.getType().equals(dataBridge.getType())) { + return; + } + // 1.2 执行 RabbitMQ 发送消息 + executeRabbitMQ(message, (IotDataBridgeDO.RabbitMQConfig) dataBridge.getConfig()); + } + + private void executeRabbitMQ(IotDeviceMessage message, IotDataBridgeDO.RabbitMQConfig config) { + try { + // 1. 获取或创建 Channel + Channel channel = (Channel) getProducer(config); + + // 2.1 声明交换机、队列和绑定关系 + channel.exchangeDeclare(config.getExchange(), "direct", true); + channel.queueDeclare(config.getQueue(), true, false, false, null); + channel.queueBind(config.getQueue(), config.getExchange(), config.getRoutingKey()); + + // 2.2 发送消息 + channel.basicPublish(config.getExchange(), config.getRoutingKey(), null, + message.toString().getBytes(StandardCharsets.UTF_8)); + log.info("[executeRabbitMQ][message({}) config({}) 发送成功]", message, config); + } catch (Exception e) { + log.error("[executeRabbitMQ][message({}) config({}) 发送异常]", message, config, e); + } + } + + @Override + protected Object initProducer(Object config) throws Exception { + IotDataBridgeDO.RabbitMQConfig rabbitConfig = (IotDataBridgeDO.RabbitMQConfig) config; + + // 1. 创建连接工厂 + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost(rabbitConfig.getHost()); + factory.setPort(rabbitConfig.getPort()); + factory.setVirtualHost(rabbitConfig.getVirtualHost()); + factory.setUsername(rabbitConfig.getUsername()); + factory.setPassword(rabbitConfig.getPassword()); + + // 2. 创建连接 + Connection connection = factory.newConnection(); + + // 3. 创建信道 + return connection.createChannel(); + } + + @Override + protected void closeProducer(Object producer) { + if (producer instanceof Channel) { + try { + Channel channel = (Channel) producer; + if (channel.isOpen()) { + channel.close(); + } + Connection connection = channel.getConnection(); + if (connection.isOpen()) { + connection.close(); + } + } catch (Exception e) { + log.error("[closeProducer][关闭 RabbitMQ 连接异常]", e); + } + } + } + + // TODO @芋道源码:测试代码,后续清理 + public static void main(String[] args) { + // 1. 创建一个共享的实例 + IotRabbitMQDataBridgeExecute action = new IotRabbitMQDataBridgeExecute(); + + // 2. 创建共享的配置 + IotDataBridgeDO.RabbitMQConfig config = new IotDataBridgeDO.RabbitMQConfig(); + config.setHost("localhost"); + config.setPort(5672); + config.setVirtualHost("/"); + config.setUsername("admin"); + config.setPassword("123456"); + config.setExchange("test-exchange"); + config.setRoutingKey("test-key"); + config.setQueue("test-queue"); + + // 3. 创建共享的消息 + IotDeviceMessage message = IotDeviceMessage.builder() + .requestId("TEST-001") + .productKey("testProduct") + .deviceName("testDevice") + .deviceKey("testDeviceKey") + .type("property") + .identifier("temperature") + .data("{\"value\": 60}") + .reportTime(LocalDateTime.now()) + .tenantId(1L) + .build(); + + // 4. 执行两次测试,验证缓存 + log.info("[main][第一次执行,应该会创建新的 channel]"); + action.executeRabbitMQ(message, config); + + log.info("[main][第二次执行,应该会复用缓存的 channel]"); + action.executeRabbitMQ(message, config); + } +} From cb16539b663b2e510f8e67aa9f37b78378c68599 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sat, 1 Mar 2025 17:43:46 +0800 Subject: [PATCH 195/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT:=20=E6=96=B0=E5=A2=9E=20Redis=20Stream=20?= =?UTF-8?q?MQ=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/enums/rule/IotDataBridgTypeEnum.java | 2 +- .../dal/dataobject/rule/IotDataBridgeDO.java | 33 +++- .../AbstractCacheableDataBridgeExecute.java | 10 ++ .../databridge/IotDataBridgeExecute.java | 10 -- .../IotKafkaMQDataBridgeExecute.java | 1 + .../IotRabbitMQDataBridgeExecute.java | 2 +- .../IotRedisStreamMQDataBridgeExecute.java | 147 ++++++++++++++++++ 7 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java index cdec8d797..295f35cff 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java @@ -22,7 +22,7 @@ public enum IotDataBridgTypeEnum implements ArrayValuable { MQTT(10), DATABASE(20), - REDIS(21), + REDIS_STREAM(21), ROCKETMQ(30), RABBITMQ(31), diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index e95cb695e..bb0623a1f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -193,10 +193,6 @@ public class IotDataBridgeDO extends BaseDO { */ private Boolean ssl; - /** - * 生产者组 ID - */ - private String groupId; /** * 主题 */ @@ -245,4 +241,33 @@ public class IotDataBridgeDO extends BaseDO { private String queue; } + /** + * Redis Stream MQ 配置 + */ + @Data + public static class RedisStreamMQConfig implements Config { + + /** + * Redis 服务器地址 + */ + private String host; + /** + * 端口 + */ + private Integer port; + /** + * 密码 + */ + private String password; + /** + * 数据库索引 + */ + private Integer database; + + /** + * 主题 + */ + private String topic; + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java index e8fbb0ccb..96b1edd33 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java @@ -7,6 +7,16 @@ import lombok.extern.slf4j.Slf4j; import java.time.Duration; +// TODO @芋艿:因为下面的,都是有状态的,所以通过 guava 缓存连接,然后通过 RemovalNotification 实现关闭。例如说,一次新建有效期是 10 分钟; +// TODO @芋艿:mq-redis +// TODO @芋艿:mq-数据库 +// TODO @芋艿:kafka +// TODO @芋艿:rocketmq +// TODO @芋艿:rabbitmq +// TODO @芋艿:mqtt +// TODO @芋艿:tcp +// TODO @芋艿:websocket + /** * 带缓存功能的数据桥梁执行器抽象类 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java index 1617c3b09..a2593f3d9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java @@ -19,14 +19,4 @@ public interface IotDataBridgeExecute { */ void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge); - // TODO @芋艿:因为下面的,都是有状态的,所以通过 guava 缓存连接,然后通过 RemovalNotification 实现关闭。例如说,一次新建有效期是 10 分钟; - // TODO @芋艿:mq-redis - // TODO @芋艿:mq-数据库 - // TODO @芋艿:kafka - // TODO @芋艿:rocketmq - // TODO @芋艿:rabbitmq - // TODO @芋艿:mqtt - // TODO @芋艿:tcp - // TODO @芋艿:websocket - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index 8c0ef2b03..ec560122a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -35,6 +35,7 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec executeKafka(message, (IotDataBridgeDO.KafkaMQConfig) dataBridge.getConfig()); } + @SuppressWarnings("unchecked") private void executeKafka(IotDeviceMessage message, IotDataBridgeDO.KafkaMQConfig config) { try { // 1. 获取或创建 KafkaTemplate diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java index 2c257051f..78c1343c2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -87,7 +87,7 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe } } - // TODO @芋道源码:测试代码,后续清理 + // TODO @芋艿:测试代码,后续清理 public static void main(String[] args) { // 1. 创建一个共享的实例 IotRabbitMQDataBridgeExecute action = new IotRabbitMQDataBridgeExecute(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java new file mode 100644 index 000000000..4eed88aec --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.iot.service.rule.action.databridge; + +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import lombok.extern.slf4j.Slf4j; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.redisson.config.SingleServerConfig; +import org.redisson.spring.data.connection.RedissonConnectionFactory; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.stream.ObjectRecord; +import org.springframework.data.redis.connection.stream.StreamRecords; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * Redis Stream MQ 的 {@link IotDataBridgeExecute} 实现类 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { + + @Override + public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { + // 1.1 校验数据桥梁类型 + if (!IotDataBridgTypeEnum.REDIS_STREAM.getType().equals(dataBridge.getType())) { + return; + } + // 1.2 执行消息发送 + executeRedisStream(message, (IotDataBridgeDO.RedisStreamMQConfig) dataBridge.getConfig()); + } + + @SuppressWarnings("unchecked") + private void executeRedisStream(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) { + try { + // 1. 获取 RedisTemplate + RedisTemplate redisTemplate = (RedisTemplate) getProducer(config); + + // 2. 创建并发送 Stream 记录 + ObjectRecord record = StreamRecords.newRecord() + .ofObject(message).withStreamKey(config.getTopic()); + String recordId = String.valueOf(redisTemplate.opsForStream().add(record)); + log.info("[executeRedisStream][消息发送成功] messageId: {}, config: {}", recordId, config); + } catch (Exception e) { + log.error("[executeRedisStream][消息发送失败] message: {}, config: {}", message, config, e); + } + } + + @Override + protected Object initProducer(Object config) { + IotDataBridgeDO.RedisStreamMQConfig redisConfig = (IotDataBridgeDO.RedisStreamMQConfig) config; + + // 1.1 创建 Redisson 配置 + Config redissonConfig = new Config(); + SingleServerConfig serverConfig = redissonConfig.useSingleServer() + .setAddress("redis://" + redisConfig.getHost() + ":" + redisConfig.getPort()) + .setDatabase(redisConfig.getDatabase()); + // 1.2 设置密码(如果有) + if (StrUtil.isNotBlank(redisConfig.getPassword())) { + serverConfig.setPassword(redisConfig.getPassword()); + } + + // 2.1 创建 RedissonClient + RedissonClient redisson = Redisson.create(redissonConfig); + // 2.2 创建并配置 RedisTemplate + RedisTemplate template = new RedisTemplate<>(); + // 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。 + template.setConnectionFactory(new RedissonConnectionFactory(redisson)); + // 使用 String 序列化方式,序列化 KEY 。 + template.setKeySerializer(RedisSerializer.string()); + template.setHashKeySerializer(RedisSerializer.string()); + // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。 + template.setValueSerializer(buildRedisSerializer()); + template.setHashValueSerializer(buildRedisSerializer()); + template.afterPropertiesSet();// 初始化 + return template; + } + + @Override + protected void closeProducer(Object producer) { + if (producer instanceof RedisTemplate) { + RedisConnectionFactory factory = ((RedisTemplate) producer).getConnectionFactory(); + try { + if (factory != null) { + ((RedissonConnectionFactory) factory).destroy(); + } + } catch (Exception e) { + log.error("[closeProducer][关闭 redisson 连接异常]", e); + } + } + } + + + public static RedisSerializer buildRedisSerializer() { + RedisSerializer json = RedisSerializer.json(); + // 解决 LocalDateTime 的序列化 + ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(json, "mapper"); + objectMapper.registerModules(new JavaTimeModule()); + return json; + } + + // TODO @芋艿:测试代码,后续清理 + public static void main(String[] args) { + // 1. 创建一个共享的实例 + IotRedisStreamMQDataBridgeExecute action = new IotRedisStreamMQDataBridgeExecute(); + + // 2. 创建共享的配置 + IotDataBridgeDO.RedisStreamMQConfig config = new IotDataBridgeDO.RedisStreamMQConfig(); + config.setHost("127.0.0.1"); + config.setPort(6379); + config.setDatabase(0); + config.setPassword("123456"); + config.setTopic("test-stream"); + + // 3. 创建共享的消息 + IotDeviceMessage message = IotDeviceMessage.builder() + .requestId("TEST-001") + .productKey("testProduct") + .deviceName("testDevice") + .deviceKey("testDeviceKey") + .type("property") + .identifier("temperature") + .data("{\"value\": 60}") + .reportTime(LocalDateTime.now()) + .tenantId(1L) + .build(); + + // 4. 执行两次测试,验证缓存 + log.info("[main][第一次执行,应该会创建新的 RedisTemplate]"); + action.executeRedisStream(message, config); + + log.info("[main][第二次执行,应该会复用缓存的 RedisTemplate]"); + action.executeRedisStream(message, config); + } + +} \ No newline at end of file From 53693529e1d06a417f7e1d8f9f68e0478cdb4fca Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Mar 2025 23:30:47 +0800 Subject: [PATCH 196/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E9=A6=96=E9=A1=B5=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../statistics/IotStatisticsController.java | 31 +++++++------- ...tStatisticsDeviceMessageSummaryRespVO.java | 4 +- .../statistics/vo/IotStatisticsReqVO.java | 5 +-- .../vo/IotStatisticsSummaryRespVO.java | 40 +++++-------------- .../iot/dal/mysql/device/IotDeviceMapper.java | 9 +---- .../iot/dal/tdengine/IotDeviceLogMapper.java | 8 ++-- .../iot/service/device/IotDeviceService.java | 8 ---- .../service/device/IotDeviceServiceImpl.java | 8 +--- .../device/data/IotDeviceLogService.java | 9 ++--- .../device/data/IotDeviceLogServiceImpl.java | 4 +- .../product/IotProductCategoryService.java | 3 +- .../IotProductCategoryServiceImpl.java | 5 +-- 13 files changed, 46 insertions(+), 90 deletions(-) diff --git a/pom.xml b/pom.xml index a34330972..0b8e28284 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ yudao-module-system yudao-module-infra - + yudao-module-bpm diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java index c4ef83a4a..31cc5121a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java @@ -36,43 +36,42 @@ public class IotStatisticsController { @Resource private IotDeviceLogService deviceLogService; - // TODO @super:description 非必要,可以不写哈 @GetMapping("/get-summary") - @Operation(summary = "获取IOT数据统计") + @Operation(summary = "获取 IoT 数据统计") public CommonResult getIotStatisticsSummary(){ IotStatisticsSummaryRespVO respVO = new IotStatisticsSummaryRespVO(); - // 获取总数 + // 1.1 获取总数 respVO.setProductCategoryCount(productCategoryService.getProductCategoryCount(null)); respVO.setProductCount(productService.getProductCount(null)); respVO.setDeviceCount(deviceService.getDeviceCount(null)); respVO.setDeviceMessageCount(deviceLogService.getDeviceLogCount(null)); - - // 获取今日新增数量 + // 1.2 获取今日新增数量 + // TODO @super:使用 LocalDateTimeUtils.getToday() LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0); respVO.setProductCategoryTodayCount(productCategoryService.getProductCategoryCount(todayStart)); respVO.setProductTodayCount(productService.getProductCount(todayStart)); respVO.setDeviceTodayCount(deviceService.getDeviceCount(todayStart)); respVO.setDeviceMessageTodayCount(deviceLogService.getDeviceLogCount(todayStart)); - // 获取各个品类下设备数量统计 + // 2. 获取各个品类下设备数量统计 respVO.setProductCategoryDeviceCounts(productCategoryService.getProductCategoryDeviceCountMap()); - // 获取设备状态数量统计 + // 3. 获取设备状态数量统计 Map deviceCountMap = deviceService.getDeviceCountMapByState(); respVO.setDeviceOnlineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.ONLINE.getState(), 0L)); respVO.setDeviceOfflineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.OFFLINE.getState(), 0L)); respVO.setDeviceInactiveCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.INACTIVE.getState(), 0L)); - return CommonResult.success(respVO); } - @GetMapping("/get-log-summary") - @Operation(summary = "获取IOT上下行消息数据统计") - public CommonResult getIotStatisticsDeviceMessageSummary(@Valid IotStatisticsReqVO reqVO){ - // 根据传入时间范围获取设备上下行消息数量统计 - IotStatisticsDeviceMessageSummaryRespVO iotStatisticsRespVO = new IotStatisticsDeviceMessageSummaryRespVO(); - iotStatisticsRespVO.setUpstreamCounts(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); - iotStatisticsRespVO.setDownstreamCounts(deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())); - return CommonResult.success(iotStatisticsRespVO); + // TODO @super:要不干掉 IotStatisticsReqVO 参数,直接使用 @RequestParam 接收,简单一些。 + @GetMapping("/get-log-summary") + @Operation(summary = "获取 IoT 设备上下行消息数据统计") + public CommonResult getIotStatisticsDeviceMessageSummary( + @Valid IotStatisticsReqVO reqVO) { + return CommonResult.success(new IotStatisticsDeviceMessageSummaryRespVO() + .setDownstreamCounts(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())) + .setDownstreamCounts((deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())))); } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java index 250c63e2a..15d2abccc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsDeviceMessageSummaryRespVO.java @@ -6,14 +6,14 @@ import lombok.Data; import java.util.List; import java.util.Map; -@Schema(description = "管理后台 - Iot 上下行消息数量统计 Response VO") +@Schema(description = "管理后台 - IoT 设备上下行消息数量统计 Response VO") @Data public class IotStatisticsDeviceMessageSummaryRespVO { + @Schema(description = "每小时上行数据数量统计") private List> upstreamCounts; @Schema(description = "每小时下行数据数量统计") private List> downstreamCounts; - // TODO @super:如果只有这两个字段,使用 KeyValue 这个键值对 } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java index acffe1299..741f77f3a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsReqVO.java @@ -4,12 +4,11 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; -@Schema(description = "管理后台 - Iot统计 Request VO") +@Schema(description = "管理后台 - IoT 统计 Request VO") @Data public class IotStatisticsReqVO { - // TODO @supper:times 直接传递哈; - // TODO 2super:private 不要丢了 + // TODO @super:前端传递的时候,还是通过 startTime 和 endTime 传递。后端转成 Long @Schema(description = "查询起始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1658486600000") @NotNull(message = "查询起始时间不能为空") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java index 0ad1f9ff4..1b750f380 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java @@ -5,8 +5,6 @@ import lombok.Data; import java.util.Map; -// TODO @super:Total 全部改成 Count -// TODO @super:IotStatisticsSummaryRespVO /** * 管理后台 - Iot 统计 Response VO */ @@ -14,56 +12,40 @@ import java.util.Map; @Data public class IotStatisticsSummaryRespVO { - // TODO @super:productCategory 哈 @Schema(description = "品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private long productCategoryCount; + private Long productCategoryCount; @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") - private long productCount; + private Long productCount; @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - private long deviceCount; + private Long deviceCount; - // TODO @super:deviceMessageCount;设备消息数量 @Schema(description = "上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") - private long deviceMessageCount; + private Long deviceMessageCount; - // TODO @super:productCategory 哈 @Schema(description = "今日新增品类数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private long productCategoryTodayCount; + private Long productCategoryTodayCount; @Schema(description = "今日新增产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") - private long productTodayCount; + private Long productTodayCount; @Schema(description = "今日新增设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - private long deviceTodayCount; + private Long deviceTodayCount; - // TODO @super:deviceMessageCount;今日设备消息数量 @Schema(description = "今日新增上报数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") - private long deviceMessageTodayCount; - - // TODO @super:deviceOnlineCount + private Long deviceMessageTodayCount; @Schema(description = "在线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "80") - private long deviceOnlineCount; - - // TODO @super:deviceOfflineCount + private Long deviceOnlineCount; @Schema(description = "离线数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15") - private long deviceOfflineCount; - - // TODO @super:deviceInactivECount + private Long deviceOfflineCount; @Schema(description = "待激活设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") - private long deviceInactiveCount; + private Long deviceInactiveCount; - // TODO @super:1)类型改成 Map,key 分类名、value 设备数量;2)deviceStatsOfCategory => productCategoryDeviceCounts @Schema(description = "按品类统计的设备数量") private Map productCategoryDeviceCounts; - // TODO @super:貌似界面里,用不到这个字段??? - - - // TODO @super:deviceUpMessageStats、deviceDownMessageStats 单独抽到 IotStatisticsDeviceMessageSummaryRespVO,然后里面属性就是 upstreamCounts、downstreamCounts - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 128b026f5..babbf29e7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -8,13 +8,11 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePa import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; /** * IoT 设备 Mapper @@ -79,18 +77,15 @@ public interface IotDeviceMapper extends BaseMapperX { .geIfPresent(IotDeviceDO::getCreateTime, createTime)); } - default Long selectCountByState(@Nullable Integer state) { - return selectCount(new LambdaQueryWrapperX() - .eqIfPresent(IotDeviceDO::getState, state)); - } - /** * 查询指定产品下各状态的设备数量 * * @return 设备数量统计列表 */ + // TODO @super:通过 mybatis-plus 来写哈,然后返回 Map 貌似就行了?! List> selectDeviceCountMapByProductId(); + // TODO @super:通过 mybatis-plus 来写哈,然后返回 Map 貌似就行了?! /** * 查询各个状态下的设备数量 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java index 9efe2ec80..96741e609 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDeviceLogMapper.java @@ -63,14 +63,14 @@ public interface IotDeviceLogMapper { * 查询每个小时设备上行消息数量 */ List> selectDeviceLogUpCountByHour(@Param("deviceKey") String deviceKey, - @Param("startTime") Long startTime, - @Param("endTime") Long endTime); + @Param("startTime") Long startTime, + @Param("endTime") Long endTime); /** * 查询每个小时设备下行消息数量 */ List> selectDeviceLogDownCountByHour(@Param("deviceKey") String deviceKey, - @Param("startTime") Long startTime, - @Param("endTime") Long endTime); + @Param("startTime") Long startTime, + @Param("endTime") Long endTime); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 0e50f4a27..1dda3f333 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -196,14 +196,6 @@ public interface IotDeviceService { */ Long getDeviceCount(@Nullable LocalDateTime createTime); - - /** - * 获得所有设备列表 - * - * @return 设备列表 - */ - List getDeviceList(); - /** * 获取 MQTT 连接参数 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index b6c0969d1..989f10a09 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -430,13 +430,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectCountByCreateTime(createTime); } - // TODO @super:是不是 groupby 查询,更高效;不过 controller,还是要考虑 null 的情况;不过可以直接枚举 foreach 处理下 - - @Override - public List getDeviceList() { - return deviceMapper.selectList(); - } - + // TODO @super:简化 @Override public Map getDeviceCountMapByProductId() { // 查询结果转换成Map diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java index e1a15aaa1..468599e1c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.service.device.data; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; @@ -57,8 +56,8 @@ public interface IotDeviceLogService { * @return key: 时间戳, value: 消息数量 */ List> getDeviceLogUpCountByHour(@Nullable String deviceKey, - @Nullable Long startTime, - @Nullable Long endTime); + @Nullable Long startTime, + @Nullable Long endTime); /** * 获得每个小时设备下行消息数量统计 @@ -69,7 +68,7 @@ public interface IotDeviceLogService { * @return key: 时间戳, value: 消息数量 */ List> getDeviceLogDownCountByHour(@Nullable String deviceKey, - @Nullable Long startTime, - @Nullable Long endTime); + @Nullable Long startTime, + @Nullable Long endTime); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java index 29b57402b..1df4d4cd4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogServiceImpl.java @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.statistics.vo.IotStatisticsDeviceMessageSummaryRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogMapper; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; @@ -73,13 +72,13 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { @Override public Long getDeviceLogCount(LocalDateTime createTime) { - // todo @super:1)LocalDateTimeUtil.toEpochMilli(createTime);2)直接表达式,更简洁 time != null ? createTime.toInstant(ZoneOffset.UTC).toEpochMilli() : null; return deviceLogMapper.selectCountByCreateTime(createTime != null ? LocalDateTimeUtil.toEpochMilli(createTime) : null); } // TODO @super:加一个参数,Boolean upstream:true 上行,false 下行,null 不过滤 @Override public List> getDeviceLogUpCountByHour(String deviceKey, Long startTime, Long endTime) { + // TODO @super:不能只基于数据库统计。因为有一些小时,可能出现没数据的情况,导致前端展示的图是不全的。可以参考 CrmStatisticsCustomerService 来实现 List> list = deviceLogMapper.selectDeviceLogUpCountByHour(deviceKey, startTime, endTime); return list.stream() .map(map -> { @@ -93,6 +92,7 @@ public class IotDeviceLogServiceImpl implements IotDeviceLogService { .collect(Collectors.toList()); } + // TODO @super:getDeviceLogDownCountByHour 融合到 getDeviceLogUpCountByHour @Override public List> getDeviceLogDownCountByHour(String deviceKey, Long startTime, Long endTime) { List> list = deviceLogMapper.selectDeviceLogDownCountByHour(deviceKey, startTime, endTime); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java index 662d161c1..8cc640556 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryService.java @@ -93,9 +93,8 @@ public interface IotProductCategoryService { */ Long getProductCategoryCount(@Nullable LocalDateTime createTime); - // TODO @super:1)Map 虽然有点怪哈,然后 Controller 按需转换成 Map ;2)名字 getProductCategoryDeviceCountMap 方法 /** - * 获得各个品类下设备数量统计 + * 获得各个品类下设备数量统计,其中 key 是产品分类名 * * @return 品类设备统计列表 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java index 5499937fd..f03186866 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java @@ -106,11 +106,9 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService // 2. 统计每个分类下的设备数量 Map categoryDeviceCountMap = new HashMap<>(); - - // 2.1 初始化所有分类的计数为0 for (IotProductCategoryDO category : categoryList) { categoryDeviceCountMap.put(category.getName(), 0); - + // TODO @super:CollectionUtils.getSumValue(),看看能不能简化下 // 2.2 找到该分类下的所有产品,累加设备数量 for (IotProductDO product : productList) { if (Objects.equals(product.getCategoryId(), category.getId())) { @@ -119,7 +117,6 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService } } } - return categoryDeviceCountMap; } From c6b58b0ebfbfdac305f8ae9d32de6156faba8131 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Mar 2025 23:58:16 +0800 Subject: [PATCH 197/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=95=B0=E6=8D=AE=E6=A1=A5?= =?UTF-8?q?=E6=A2=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AbstractCacheableDataBridgeExecute.java | 12 +++++------- .../action/databridge/IotDataBridgeExecute.java | 2 ++ .../databridge/IotKafkaMQDataBridgeExecute.java | 13 +++++++------ .../databridge/IotRabbitMQDataBridgeExecute.java | 1 + .../IotRedisStreamMQDataBridgeExecute.java | 5 ++++- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java index 96b1edd33..ebd0f8776 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java @@ -7,12 +7,7 @@ import lombok.extern.slf4j.Slf4j; import java.time.Duration; -// TODO @芋艿:因为下面的,都是有状态的,所以通过 guava 缓存连接,然后通过 RemovalNotification 实现关闭。例如说,一次新建有效期是 10 分钟; -// TODO @芋艿:mq-redis -// TODO @芋艿:mq-数据库 -// TODO @芋艿:kafka -// TODO @芋艿:rocketmq -// TODO @芋艿:rabbitmq +// TODO @芋艿:数据库 // TODO @芋艿:mqtt // TODO @芋艿:tcp // TODO @芋艿:websocket @@ -25,6 +20,7 @@ import java.time.Duration; @Slf4j public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute { + // TODO @huihui:AbstractCacheableDataBridgeExecute 这样,下面的 Object, Object 就有了类型;另外 IotDataBridgeDO.Config 可以替代一个 Object 哇, /** * Producer 缓存 */ @@ -43,12 +39,14 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg } }) .build(new CacheLoader() { + @Override public Object load(Object config) throws Exception { Object producer = initProducer(config); log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config); return producer; } + }); /** @@ -77,4 +75,4 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg */ protected abstract void closeProducer(Object producer); -} \ No newline at end of file +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java index a2593f3d9..a10f75103 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java @@ -11,6 +11,8 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; */ public interface IotDataBridgeExecute { + // TODO @huihui:要不搞个 getType?然后 execute0 由子类实现。这样,子类的 executeRedisStream ,其实就是 execute0 了。 + /** * 执行数据桥梁操作 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index ec560122a..e95d4ced9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -10,6 +10,7 @@ import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; +import java.time.Duration; import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; @@ -25,13 +26,15 @@ import java.util.concurrent.TimeoutException; @Slf4j public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { + private static final Duration SEND_TIMEOUT = Duration.ofMillis(10); + @Override public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { - // 1.1 校验数据桥梁的类型 == KAFKA + // 1. 校验数据桥梁的类型 == KAFKA if (!IotDataBridgTypeEnum.KAFKA.getType().equals(dataBridge.getType())) { return; } - // 1.2 执行 Kafka 发送消息 + // 2. 执行 Kafka 发送消息 executeKafka(message, (IotDataBridgeDO.KafkaMQConfig) dataBridge.getConfig()); } @@ -43,7 +46,7 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec // 2. 发送消息并等待结果 kafkaTemplate.send(config.getTopic(), message.toString()) - .get(10, TimeUnit.SECONDS); // 添加超时等待 + .get(SEND_TIMEOUT.getSeconds(), TimeUnit.SECONDS); // 添加超时等待 log.info("[executeKafka][message({}) 发送成功]", message); } catch (TimeoutException e) { log.error("[executeKafka][message({}) config({}) 发送超时]", message, config, e); @@ -55,13 +58,12 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec @Override protected Object initProducer(Object config) { IotDataBridgeDO.KafkaMQConfig kafkaConfig = (IotDataBridgeDO.KafkaMQConfig) config; - + // 1.1 构建生产者配置 Map props = new HashMap<>(); props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServers()); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); - // 1.2 如果配置了认证信息 if (kafkaConfig.getUsername() != null && kafkaConfig.getPassword() != null) { props.put("security.protocol", "SASL_PLAINTEXT"); @@ -70,7 +72,6 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"" + kafkaConfig.getUsername() + "\" password=\"" + kafkaConfig.getPassword() + "\";"); } - // 1.3 如果启用 SSL if (Boolean.TRUE.equals(kafkaConfig.getSsl())) { props.put("security.protocol", "SSL"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java index 78c1343c2..561187315 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -51,6 +51,7 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe } @Override + @SuppressWarnings("resource") protected Object initProducer(Object config) throws Exception { IotDataBridgeDO.RabbitMQConfig rabbitConfig = (IotDataBridgeDO.RabbitMQConfig) config; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java index 4eed88aec..552fc3425 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java @@ -42,6 +42,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid } @SuppressWarnings("unchecked") + // TODO @huihui:try catch 交给父类来做,子类不处理异常 private void executeRedisStream(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) { try { // 1. 获取 RedisTemplate @@ -71,6 +72,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid serverConfig.setPassword(redisConfig.getPassword()); } + // TODO @huihui:看看能不能简化一些。按道理说,不用这么多的哈。 // 2.1 创建 RedissonClient RedissonClient redisson = Redisson.create(redissonConfig); // 2.2 创建并配置 RedisTemplate @@ -89,6 +91,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid @Override protected void closeProducer(Object producer) { + // TODO @huihui:try catch 交给父类来做。子类不处理异常 if (producer instanceof RedisTemplate) { RedisConnectionFactory factory = ((RedisTemplate) producer).getConnectionFactory(); try { @@ -101,7 +104,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid } } - + // TODO @huihui:看看能不能简化一些。按道理说,不用这么多的哈。 public static RedisSerializer buildRedisSerializer() { RedisSerializer json = RedisSerializer.json(); // 解决 LocalDateTime 的序列化 From 3c9985978b081cbdff7541b13f98d347b26d1fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 2 Mar 2025 20:47:50 +0800 Subject: [PATCH 198/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=9B=B4=E6=96=B0=20MQTT=20=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E9=85=8D=E7=BD=AE=E4=B8=BA=E6=95=B0=E7=BB=84=EF=BC=8C?= =?UTF-8?q?=E9=87=8D=E6=9E=84=20EMQX=20=E8=AE=A4=E8=AF=81=E9=80=BB?= =?UTF-8?q?=E8=BE=91=EF=BC=8C=E4=BC=98=E5=8C=96=E5=BC=82=E5=B8=B8=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=92=8C=E5=93=8D=E5=BA=94=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/tdengine/core/TaosAspect.java | 39 --------------- .../common/util/IotPluginCommonUtils.java | 14 ++++++ .../emqx/config/IotPluginEmqxProperties.java | 5 +- .../upstream/IotDeviceUpstreamServer.java | 6 +-- .../router/IotDeviceAuthVertxHandler.java | 48 ++++++++++--------- .../src/main/resources/application.yml | 3 +- .../plugin/http/IotHttpPluginApplication.java | 10 +--- .../http/config/IotHttpVertxPlugin.java | 14 ------ 8 files changed, 47 insertions(+), 92 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TaosAspect.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TaosAspect.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TaosAspect.java deleted file mode 100644 index d83f34d04..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TaosAspect.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.iot.framework.tdengine.core; - -import lombok.extern.slf4j.Slf4j; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.springframework.stereotype.Component; - -import java.sql.Timestamp; -import java.util.Map; - -// TODO @haohao:这个还需要的么? -/** - * TaosAspect 是一个处理 Taos 数据库返回值的切面。 - */ -@Aspect -@Component -@Slf4j -public class TaosAspect { - - @Around("execution(java.util.Map cn.iocoder.yudao.module.iot.dal.tdengine.*.*(..))") - public Object handleType(ProceedingJoinPoint joinPoint) { - Map result = null; - try { - result = (Map) joinPoint.proceed(); - result.replaceAll((key, value) -> { - if (value instanceof byte[]) { - return new String((byte[]) value); - } else if (value instanceof Timestamp) { - return ((Timestamp) value).getTime(); - } - return value; - }); - } catch (Throwable e) { - log.error("TaosAspect handleType error", e); - } - return result; - } -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java index a632c73c7..753e62c94 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java @@ -49,4 +49,18 @@ public class IotPluginCommonUtils { .end(result); } + /** + * 将对象转换为JSON字符串后写入响应 + * + * @param routingContext 路由上下文 + * @param data 要转换为JSON的数据对象 + */ + @SuppressWarnings("deprecation") + public static void writeJson(RoutingContext routingContext, Object data) { + routingContext.response() + .setStatusCode(200) + .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .end(JsonUtils.toJsonString(data)); + } + } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java index 72a085bd9..4117e7182 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java @@ -36,11 +36,10 @@ public class IotPluginEmqxProperties { */ private boolean mqttSsl; - // TODO @haohao:这个是不是改成数组? /** - * 订阅的主题 + * 订阅的主题列表 */ - private String mqttTopics; + private String[] mqttTopics; /** * 认证端口 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java index 5dd627671..54479df15 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java @@ -67,6 +67,7 @@ public class IotDeviceUpstreamServer { router.route().handler(BodyHandler.create()); // 处理 Body router.post(IotDeviceAuthVertxHandler.PATH) // TODO @haohao:疑问,mqtt 的认证,需要通过 http 呀? + // 回复:MQTT 认证不必须通过 HTTP 进行,但 HTTP 认证是 EMQX 等 MQTT 服务器支持的一种灵活的认证方式 .handler(new IotDeviceAuthVertxHandler(deviceUpstreamApi)); // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); @@ -165,15 +166,14 @@ public class IotDeviceUpstreamServer { * @return 订阅结果的Future */ private Future subscribeToTopics() { - String topicsStr = emqxProperties.getMqttTopics(); - if (topicsStr == null || topicsStr.trim().isEmpty()) { + String[] topics = emqxProperties.getMqttTopics(); + if (topics == null || topics.length == 0) { log.warn("[subscribeToTopics] 未配置MQTT主题,跳过订阅"); return Future.succeededFuture(); } log.info("[subscribeToTopics] 开始订阅设备上行消息主题"); - String[] topics = topicsStr.split(TOPIC_SEPARATOR); Future compositeFuture = Future.succeededFuture(); for (String topic : topics) { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java index 8eac1ffbd..350de674c 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java @@ -10,9 +10,12 @@ import io.vertx.ext.web.RoutingContext; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import java.util.Collections; + /** * IoT Emqx 连接认证的 Vert.x Handler - * ... + * ... * * @author haohao */ @@ -27,30 +30,29 @@ public class IotDeviceAuthVertxHandler implements Handler { @Override @SuppressWarnings("unchecked") public void handle(RoutingContext routingContext) { - // TODO @haohao:try catch 兜底异常 - JsonObject json = routingContext.body().asJsonObject(); - String clientId = json.getString("clientid"); - String username = json.getString("username"); - String password = json.getString("password"); + try { + JsonObject json = routingContext.body().asJsonObject(); + String clientId = json.getString("clientid"); + String username = json.getString("username"); + String password = json.getString("password"); - IotDeviceEmqxAuthReqDTO authReqDTO = buildDeviceEmqxAuthReqDTO(clientId, username, password); + // 构建认证请求DTO + IotDeviceEmqxAuthReqDTO authReqDTO = new IotDeviceEmqxAuthReqDTO() + .setClientId(clientId) + .setUsername(username) + .setPassword(password); - CommonResult authResult = deviceUpstreamApi.authenticateEmqxConnection(authReqDTO); - if (authResult.getCode() != 0 || !authResult.getData()) { - denyAccess(routingContext); - return; + // 调用认证API + CommonResult authResult = deviceUpstreamApi.authenticateEmqxConnection(authReqDTO); + if (authResult.getCode() != 0 || !authResult.getData()) { + IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "deny")); + return; + } + + IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "allow")); + } catch (Exception e) { + log.error("[handle][EMQX认证异常]", e); + IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "deny")); } - // TODO @haohao:貌似可以考虑封装一个 writeJson ,里面有个参数是 data,然后里面去 JsonUtils.toJsonString(data) - IotPluginCommonUtils.writeJson(routingContext, "{\"result\": \"allow\"}"); } - - // TODO @haohao:下面两个简单方法,貌似可以考虑不抽小方法哈。 - private void denyAccess(RoutingContext routingContext) { - IotPluginCommonUtils.writeJson(routingContext, "{\"result\": \"deny\"}"); - } - - private IotDeviceEmqxAuthReqDTO buildDeviceEmqxAuthReqDTO(String clientId, String username, String password) { - return new IotDeviceEmqxAuthReqDTO().setClientId(clientId).setUsername(username).setPassword(password); - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/resources/application.yml index 9343d3614..c00621c82 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/resources/application.yml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/resources/application.yml @@ -15,5 +15,6 @@ yudao: mqtt-ssl: false mqtt-username: yudao mqtt-password: 123456 - mqtt-topics: "/sys/#" + mqtt-topics: + - "/sys/#" auth-port: 8101 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/IotHttpPluginApplication.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/IotHttpPluginApplication.java index 0aa08505a..a88b34eb3 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/IotHttpPluginApplication.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/IotHttpPluginApplication.java @@ -4,7 +4,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ConfigurableApplicationContext; /** * 独立运行入口 @@ -16,14 +15,7 @@ public class IotHttpPluginApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(IotHttpPluginApplication.class); application.setWebApplicationType(WebApplicationType.NONE); - ConfigurableApplicationContext context = application.run(args); - - // 手动获取 VertxService 并启动 - // TODO @haohao:可以放在 bean 的 init 里么?回复:会和插件模式冲突 @芋艿,测试下 - // TODO @haohao:貌似去掉,没有问题额。。。 -// IotDeviceUpstreamServer vertxService = context.getBean(IotDeviceUpstreamServer.class); -// vertxService.start(); - + application.run(args); log.info("[main][独立模式启动完成]"); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java index ac9a93340..674980d00 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java @@ -2,11 +2,9 @@ package cn.iocoder.yudao.module.iot.plugin.http.config; import cn.hutool.core.lang.Assert; import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import lombok.extern.slf4j.Slf4j; import org.pf4j.PluginWrapper; import org.pf4j.spring.SpringPlugin; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -29,11 +27,6 @@ public class IotHttpVertxPlugin extends SpringPlugin { ApplicationContext pluginContext = getApplicationContext(); Assert.notNull(pluginContext, "pluginContext 不能为空"); - // 2. 启动 Vert.x - // TODO @haohao:貌似去掉,没有问题额。。。 -// IotDeviceUpstreamServer vertxService = pluginContext.getBean(IotDeviceUpstreamServer.class); -// vertxService.start(); - log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动成功...]"); } catch (Exception e) { log.error("[HttpVertxPlugin][HttpVertxPlugin 插件开启动异常...]", e); @@ -44,13 +37,6 @@ public class IotHttpVertxPlugin extends SpringPlugin { public void stop() { log.info("[HttpVertxPlugin][HttpVertxPlugin 插件停止开始...]"); try { - // 停止服务器 -// ApplicationContext pluginContext = getApplicationContext(); -// if (pluginContext != null) { -// IotDeviceUpstreamServer vertxService = pluginContext.getBean(IotDeviceUpstreamServer.class); -// vertxService.stop(); -// } - log.info("[HttpVertxPlugin][HttpVertxPlugin 插件停止成功...]"); } catch (Exception e) { log.error("[HttpVertxPlugin][HttpVertxPlugin 插件停止异常...]", e); From 61ea09488ed624d1f15fc01b8ffa98aa717484b7 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 3 Mar 2025 12:22:19 +0800 Subject: [PATCH 199/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E4=BC=98=E5=8C=96=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=A1=A5=E6=A2=81=E6=89=A7=E8=A1=8C=E5=99=A8=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E7=B1=BB=E5=A2=9E=E5=8A=A0=E6=B3=9B=E5=9E=8B=EF=BC=8C=E5=87=8F?= =?UTF-8?q?=E5=B0=91=E5=AD=90=E7=B1=BB=E7=B1=BB=E5=9E=8B=E5=BC=BA=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AbstractCacheableDataBridgeExecute.java | 50 +++++++++++++------ .../IotKafkaMQDataBridgeExecute.java | 24 ++++----- .../IotRabbitMQDataBridgeExecute.java | 41 +++++++-------- .../IotRedisStreamMQDataBridgeExecute.java | 32 +++++------- .../IotRocketMQDataBridgeExecute.java | 18 +++---- 5 files changed, 81 insertions(+), 84 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java index ebd0f8776..ec0c8bea9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.cache.RemovalListener; import lombok.extern.slf4j.Slf4j; import java.time.Duration; @@ -15,22 +16,36 @@ import java.time.Duration; /** * 带缓存功能的数据桥梁执行器抽象类 * + * 该类提供了一个通用的缓存机制,用于管理各类数据桥接的生产者(Producer)实例。 + * + * 主要特点: + * - 基于Guava Cache实现高效的生产者实例缓存管理 + * - 自动处理生产者的生命周期(创建、获取、关闭) + * - 支持30分钟未访问自动过期清理机制 + * - 异常处理与日志记录,便于问题排查 + * + * 子类需要实现: + * - initProducer(Config) - 初始化特定类型的生产者实例 + * - closeProducer(Producer) - 关闭生产者实例并释放资源 + * + * @param 配置信息类型,用于初始化生产者 + * @param 生产者类型,负责将数据发送到目标系统 * @author HUIHUI */ @Slf4j -public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute { +public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute { - // TODO @huihui:AbstractCacheableDataBridgeExecute 这样,下面的 Object, Object 就有了类型;另外 IotDataBridgeDO.Config 可以替代一个 Object 哇, /** * Producer 缓存 */ - private final LoadingCache PRODUCER_CACHE = CacheBuilder.newBuilder() - .expireAfterAccess(Duration.ofMinutes(30)) - .removalListener(notification -> { - Object producer = notification.getValue(); + private final LoadingCache PRODUCER_CACHE = CacheBuilder.newBuilder() + .expireAfterAccess(Duration.ofMinutes(30)) // 30 分钟未访问就提前过期 + .removalListener((RemovalListener) notification -> { + Producer producer = notification.getValue(); if (producer == null) { return; } + try { closeProducer(producer); log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已关闭]", notification.getKey()); @@ -38,15 +53,18 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg log.error("[PRODUCER_CACHE][配置({}) 对应的 producer 关闭失败]", notification.getKey(), e); } }) - .build(new CacheLoader() { - + .build(new CacheLoader() { @Override - public Object load(Object config) throws Exception { - Object producer = initProducer(config); - log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config); - return producer; + public Producer load(Config config) throws Exception { + try { + Producer producer = initProducer(config); + log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config); + return producer; + } catch (Exception e) { + log.error("[PRODUCER_CACHE][配置({}) 对应的 producer 创建启动失败]", config, e); + throw e; // 抛出异常,触发缓存加载失败机制 + } } - }); /** @@ -55,7 +73,7 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg * @param config 配置信息 * @return 生产者对象 */ - protected Object getProducer(Object config) throws Exception { + protected Producer getProducer(Config config) throws Exception { return PRODUCER_CACHE.get(config); } @@ -66,13 +84,13 @@ public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridg * @return 生产者对象 * @throws Exception 如果初始化失败 */ - protected abstract Object initProducer(Object config) throws Exception; + protected abstract Producer initProducer(Config config) throws Exception; /** * 关闭生产者 * * @param producer 生产者对象 */ - protected abstract void closeProducer(Object producer); + protected abstract void closeProducer(Producer producer) throws Exception; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index e95d4ced9..33aa744a8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -24,7 +24,8 @@ import java.util.concurrent.TimeoutException; */ @Component @Slf4j -public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { +public class IotKafkaMQDataBridgeExecute extends + AbstractCacheableDataBridgeExecute> { private static final Duration SEND_TIMEOUT = Duration.ofMillis(10); @@ -38,11 +39,10 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec executeKafka(message, (IotDataBridgeDO.KafkaMQConfig) dataBridge.getConfig()); } - @SuppressWarnings("unchecked") private void executeKafka(IotDeviceMessage message, IotDataBridgeDO.KafkaMQConfig config) { try { // 1. 获取或创建 KafkaTemplate - KafkaTemplate kafkaTemplate = (KafkaTemplate) getProducer(config); + KafkaTemplate kafkaTemplate = getProducer(config); // 2. 发送消息并等待结果 kafkaTemplate.send(config.getTopic(), message.toString()) @@ -56,24 +56,22 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec } @Override - protected Object initProducer(Object config) { - IotDataBridgeDO.KafkaMQConfig kafkaConfig = (IotDataBridgeDO.KafkaMQConfig) config; - + protected KafkaTemplate initProducer(IotDataBridgeDO.KafkaMQConfig config) { // 1.1 构建生产者配置 Map props = new HashMap<>(); - props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConfig.getBootstrapServers()); + props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, config.getBootstrapServers()); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); // 1.2 如果配置了认证信息 - if (kafkaConfig.getUsername() != null && kafkaConfig.getPassword() != null) { + if (config.getUsername() != null && config.getPassword() != null) { props.put("security.protocol", "SASL_PLAINTEXT"); props.put("sasl.mechanism", "PLAIN"); props.put("sasl.jaas.config", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"" - + kafkaConfig.getUsername() + "\" password=\"" + kafkaConfig.getPassword() + "\";"); + + config.getUsername() + "\" password=\"" + config.getPassword() + "\";"); } // 1.3 如果启用 SSL - if (Boolean.TRUE.equals(kafkaConfig.getSsl())) { + if (Boolean.TRUE.equals(config.getSsl())) { props.put("security.protocol", "SSL"); } @@ -83,10 +81,8 @@ public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExec } @Override - protected void closeProducer(Object producer) { - if (producer instanceof KafkaTemplate) { - ((KafkaTemplate) producer).destroy(); - } + protected void closeProducer(KafkaTemplate producer) { + producer.destroy(); } // TODO @芋艿:测试代码,后续清理 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java index 561187315..0918a5546 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -19,7 +19,8 @@ import java.time.LocalDateTime; */ @Component @Slf4j -public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { +public class IotRabbitMQDataBridgeExecute extends + AbstractCacheableDataBridgeExecute { @Override public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { @@ -34,7 +35,7 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe private void executeRabbitMQ(IotDeviceMessage message, IotDataBridgeDO.RabbitMQConfig config) { try { // 1. 获取或创建 Channel - Channel channel = (Channel) getProducer(config); + Channel channel = getProducer(config); // 2.1 声明交换机、队列和绑定关系 channel.exchangeDeclare(config.getExchange(), "direct", true); @@ -52,16 +53,14 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe @Override @SuppressWarnings("resource") - protected Object initProducer(Object config) throws Exception { - IotDataBridgeDO.RabbitMQConfig rabbitConfig = (IotDataBridgeDO.RabbitMQConfig) config; - + protected Channel initProducer(IotDataBridgeDO.RabbitMQConfig config) throws Exception { // 1. 创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); - factory.setHost(rabbitConfig.getHost()); - factory.setPort(rabbitConfig.getPort()); - factory.setVirtualHost(rabbitConfig.getVirtualHost()); - factory.setUsername(rabbitConfig.getUsername()); - factory.setPassword(rabbitConfig.getPassword()); + factory.setHost(config.getHost()); + factory.setPort(config.getPort()); + factory.setVirtualHost(config.getVirtualHost()); + factory.setUsername(config.getUsername()); + factory.setPassword(config.getPassword()); // 2. 创建连接 Connection connection = factory.newConnection(); @@ -71,20 +70,13 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe } @Override - protected void closeProducer(Object producer) { - if (producer instanceof Channel) { - try { - Channel channel = (Channel) producer; - if (channel.isOpen()) { - channel.close(); - } - Connection connection = channel.getConnection(); - if (connection.isOpen()) { - connection.close(); - } - } catch (Exception e) { - log.error("[closeProducer][关闭 RabbitMQ 连接异常]", e); - } + protected void closeProducer(Channel channel) throws Exception { + if (channel.isOpen()) { + channel.close(); + } + Connection connection = channel.getConnection(); + if (connection.isOpen()) { + connection.close(); } } @@ -124,4 +116,5 @@ public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExe log.info("[main][第二次执行,应该会复用缓存的 channel]"); action.executeRabbitMQ(message, config); } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java index 552fc3425..77b688606 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java @@ -29,7 +29,8 @@ import java.time.LocalDateTime; */ @Component @Slf4j -public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { +public class IotRedisStreamMQDataBridgeExecute extends + AbstractCacheableDataBridgeExecute> { @Override public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { @@ -46,7 +47,7 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid private void executeRedisStream(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) { try { // 1. 获取 RedisTemplate - RedisTemplate redisTemplate = (RedisTemplate) getProducer(config); + RedisTemplate redisTemplate = getProducer(config); // 2. 创建并发送 Stream 记录 ObjectRecord record = StreamRecords.newRecord() @@ -59,17 +60,15 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid } @Override - protected Object initProducer(Object config) { - IotDataBridgeDO.RedisStreamMQConfig redisConfig = (IotDataBridgeDO.RedisStreamMQConfig) config; - + protected RedisTemplate initProducer(IotDataBridgeDO.RedisStreamMQConfig config) { // 1.1 创建 Redisson 配置 Config redissonConfig = new Config(); SingleServerConfig serverConfig = redissonConfig.useSingleServer() - .setAddress("redis://" + redisConfig.getHost() + ":" + redisConfig.getPort()) - .setDatabase(redisConfig.getDatabase()); + .setAddress("redis://" + config.getHost() + ":" + config.getPort()) + .setDatabase(config.getDatabase()); // 1.2 设置密码(如果有) - if (StrUtil.isNotBlank(redisConfig.getPassword())) { - serverConfig.setPassword(redisConfig.getPassword()); + if (StrUtil.isNotBlank(config.getPassword())) { + serverConfig.setPassword(config.getPassword()); } // TODO @huihui:看看能不能简化一些。按道理说,不用这么多的哈。 @@ -90,17 +89,10 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBrid } @Override - protected void closeProducer(Object producer) { - // TODO @huihui:try catch 交给父类来做。子类不处理异常 - if (producer instanceof RedisTemplate) { - RedisConnectionFactory factory = ((RedisTemplate) producer).getConnectionFactory(); - try { - if (factory != null) { - ((RedissonConnectionFactory) factory).destroy(); - } - } catch (Exception e) { - log.error("[closeProducer][关闭 redisson 连接异常]", e); - } + protected void closeProducer(RedisTemplate producer) throws Exception { + RedisConnectionFactory factory = producer.getConnectionFactory(); + if (factory != null) { + ((RedissonConnectionFactory) factory).destroy(); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index 3b5325253..061bbfc69 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -20,7 +20,8 @@ import java.time.LocalDateTime; */ @Component @Slf4j -public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { +public class IotRocketMQDataBridgeExecute extends + AbstractCacheableDataBridgeExecute { @Override public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { @@ -35,7 +36,7 @@ public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExe private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { try { // 1. 获取或创建 Producer - DefaultMQProducer producer = (DefaultMQProducer) getProducer(config); + DefaultMQProducer producer = getProducer(config); // 2.1 创建消息对象,指定Topic、Tag和消息体 Message msg = new Message( @@ -57,19 +58,16 @@ public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExe } @Override - protected Object initProducer(Object config) throws Exception { - IotDataBridgeDO.RocketMQConfig rocketMQConfig = (IotDataBridgeDO.RocketMQConfig) config; - DefaultMQProducer producer = new DefaultMQProducer(rocketMQConfig.getGroup()); - producer.setNamesrvAddr(rocketMQConfig.getNameServer()); + protected DefaultMQProducer initProducer(IotDataBridgeDO.RocketMQConfig config) throws Exception { + DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); + producer.setNamesrvAddr(config.getNameServer()); producer.start(); return producer; } @Override - protected void closeProducer(Object producer) { - if (producer instanceof DefaultMQProducer) { - ((DefaultMQProducer) producer).shutdown(); - } + protected void closeProducer(DefaultMQProducer producer) { + producer.shutdown(); } // TODO @芋艿:测试代码,后续清理 From 3b54deb989630f21b7313ac398b4e1f417172fe4 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 3 Mar 2025 12:48:07 +0800 Subject: [PATCH 200/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E4=BC=98=E5=8C=96=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=A1=A5=E6=A2=81=E7=9A=84=E6=89=A7=E8=A1=8C=E5=99=A8=E5=87=8F?= =?UTF-8?q?=E5=B0=91=E5=AD=90=E7=B1=BB=E4=BB=A3=E7=A0=81=E5=86=97=E4=BD=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AbstractCacheableDataBridgeExecute.java | 2 +- .../databridge/IotDataBridgeExecute.java | 28 +++++++++++++++++-- .../databridge/IotHttpDataBridgeExecute.java | 14 ++++------ .../IotKafkaMQDataBridgeExecute.java | 16 ++++------- .../IotRabbitMQDataBridgeExecute.java | 17 +++++------ .../IotRedisStreamMQDataBridgeExecute.java | 18 ++++-------- .../IotRocketMQDataBridgeExecute.java | 16 ++++------- 7 files changed, 56 insertions(+), 55 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java index ec0c8bea9..52c4483ec 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java @@ -33,7 +33,7 @@ import java.time.Duration; * @author HUIHUI */ @Slf4j -public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute { +public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute { /** * Producer 缓存 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java index a10f75103..3f842f1f5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java @@ -9,9 +9,14 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; * * @author HUIHUI */ -public interface IotDataBridgeExecute { +public interface IotDataBridgeExecute { - // TODO @huihui:要不搞个 getType?然后 execute0 由子类实现。这样,子类的 executeRedisStream ,其实就是 execute0 了。 + /** + * 获取数据桥梁类型 + * + * @return 数据桥梁类型 + */ + Integer getType(); /** * 执行数据桥梁操作 @@ -19,6 +24,23 @@ public interface IotDataBridgeExecute { * @param message 设备消息 * @param dataBridge 数据桥梁 */ - void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge); + @SuppressWarnings({"unchecked"}) + default void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { + // 1.1 校验数据桥梁类型 + if (!getType().equals(dataBridge.getType())) { + return; + } + + // 1.2 执行对应的数据桥梁发送消息 + execute0(message, (Config) dataBridge.getConfig()); + } + + /** + * 【真正】执行数据桥梁操作 + * + * @param message 设备消息 + * @param config 桥梁配置 + */ + void execute0(IotDeviceMessage message, Config config); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java index 27b8bc6bb..ffe2c5b80 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java @@ -25,23 +25,19 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ */ @Component @Slf4j -public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { +public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { @Resource private RestTemplate restTemplate; @Override - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { - // 1.1 校验数据桥梁的类型 == HTTP - if (!IotDataBridgTypeEnum.HTTP.getType().equals(dataBridge.getType())) { - return; - } - // 1.2 执行 HTTP 请求 - executeHttp(message, (IotDataBridgeDO.HttpConfig) dataBridge.getConfig()); + public Integer getType() { + return IotDataBridgTypeEnum.HTTP.getType(); } + @Override @SuppressWarnings({"unchecked", "deprecation"}) - private void executeHttp(IotDeviceMessage message, IotDataBridgeDO.HttpConfig config) { + public void execute0(IotDeviceMessage message, IotDataBridgeDO.HttpConfig config) { String url = null; HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase()); HttpEntity requestEntity = null; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index 33aa744a8..1efcfe9ca 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -30,16 +30,12 @@ public class IotKafkaMQDataBridgeExecute extends private static final Duration SEND_TIMEOUT = Duration.ofMillis(10); @Override - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { - // 1. 校验数据桥梁的类型 == KAFKA - if (!IotDataBridgTypeEnum.KAFKA.getType().equals(dataBridge.getType())) { - return; - } - // 2. 执行 Kafka 发送消息 - executeKafka(message, (IotDataBridgeDO.KafkaMQConfig) dataBridge.getConfig()); + public Integer getType() { + return IotDataBridgTypeEnum.KAFKA.getType(); } - private void executeKafka(IotDeviceMessage message, IotDataBridgeDO.KafkaMQConfig config) { + @Override + public void execute0(IotDeviceMessage message, IotDataBridgeDO.KafkaMQConfig config) { try { // 1. 获取或创建 KafkaTemplate KafkaTemplate kafkaTemplate = getProducer(config); @@ -113,10 +109,10 @@ public class IotKafkaMQDataBridgeExecute extends // 4. 执行两次测试,验证缓存 log.info("[main][第一次执行,应该会创建新的 producer]"); - action.executeKafka(message, config); + action.execute0(message, config); log.info("[main][第二次执行,应该会复用缓存的 producer]"); - action.executeKafka(message, config); + action.execute0(message, config); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java index 0918a5546..27ebccc39 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -22,17 +22,14 @@ import java.time.LocalDateTime; public class IotRabbitMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { + @Override - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { - // 1.1 校验数据桥梁的类型 == RABBITMQ - if (!IotDataBridgTypeEnum.RABBITMQ.getType().equals(dataBridge.getType())) { - return; - } - // 1.2 执行 RabbitMQ 发送消息 - executeRabbitMQ(message, (IotDataBridgeDO.RabbitMQConfig) dataBridge.getConfig()); + public Integer getType() { + return IotDataBridgTypeEnum.RABBITMQ.getType(); } - private void executeRabbitMQ(IotDeviceMessage message, IotDataBridgeDO.RabbitMQConfig config) { + @Override + public void execute0(IotDeviceMessage message, IotDataBridgeDO.RabbitMQConfig config) { try { // 1. 获取或创建 Channel Channel channel = getProducer(config); @@ -111,10 +108,10 @@ public class IotRabbitMQDataBridgeExecute extends // 4. 执行两次测试,验证缓存 log.info("[main][第一次执行,应该会创建新的 channel]"); - action.executeRabbitMQ(message, config); + action.execute0(message, config); log.info("[main][第二次执行,应该会复用缓存的 channel]"); - action.executeRabbitMQ(message, config); + action.execute0(message, config); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java index 77b688606..f60528ef9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java @@ -33,18 +33,12 @@ public class IotRedisStreamMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute> { @Override - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { - // 1.1 校验数据桥梁类型 - if (!IotDataBridgTypeEnum.REDIS_STREAM.getType().equals(dataBridge.getType())) { - return; - } - // 1.2 执行消息发送 - executeRedisStream(message, (IotDataBridgeDO.RedisStreamMQConfig) dataBridge.getConfig()); + public Integer getType() { + return IotDataBridgTypeEnum.REDIS_STREAM.getType(); } - @SuppressWarnings("unchecked") - // TODO @huihui:try catch 交给父类来做,子类不处理异常 - private void executeRedisStream(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) { + @Override + public void execute0(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) { try { // 1. 获取 RedisTemplate RedisTemplate redisTemplate = getProducer(config); @@ -133,10 +127,10 @@ public class IotRedisStreamMQDataBridgeExecute extends // 4. 执行两次测试,验证缓存 log.info("[main][第一次执行,应该会创建新的 RedisTemplate]"); - action.executeRedisStream(message, config); + action.execute0(message, config); log.info("[main][第二次执行,应该会复用缓存的 RedisTemplate]"); - action.executeRedisStream(message, config); + action.execute0(message, config); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index 061bbfc69..a68a6525e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -24,16 +24,12 @@ public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute { @Override - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { - // 1.1 校验数据桥梁的类型 == ROCKETMQ - if (!IotDataBridgTypeEnum.ROCKETMQ.getType().equals(dataBridge.getType())) { - return; - } - // 1.2 执行 RocketMQ 发送消息 - executeRocketMQ(message, (IotDataBridgeDO.RocketMQConfig) dataBridge.getConfig()); + public Integer getType() { + return IotDataBridgTypeEnum.ROCKETMQ.getType(); } - private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { + @Override + public void execute0(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { try { // 1. 获取或创建 Producer DefaultMQProducer producer = getProducer(config); @@ -97,10 +93,10 @@ public class IotRocketMQDataBridgeExecute extends // 4. 执行两次测试,验证缓存 log.info("[main][第一次执行,应该会创建新的 producer]"); - action.executeRocketMQ(message, config); + action.execute0(message, config); log.info("[main][第二次执行,应该会复用缓存的 producer]"); - action.executeRocketMQ(message, config); + action.execute0(message, config); } } From ce5e64e0aa635be458334af1d27236b102c6db4b Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 3 Mar 2025 13:03:41 +0800 Subject: [PATCH 201/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E4=BC=98=E5=8C=96=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=A1=A5=E6=A2=81=E7=9A=84=E6=89=A7=E8=A1=8C=E5=99=A8=E5=87=8F?= =?UTF-8?q?=E5=B0=91=E5=AD=90=E7=B1=BB=E4=BB=A3=E7=A0=81=E5=86=97=E4=BD=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rule/action/IotRuleSceneAction.java | 2 +- .../action/IotRuleSceneDataBridgeAction.java | 8 ++-- .../AbstractCacheableDataBridgeExecute.java | 18 +++++++++ .../databridge/IotDataBridgeExecute.java | 4 +- .../IotKafkaMQDataBridgeExecute.java | 25 +++++------- .../IotRabbitMQDataBridgeExecute.java | 35 ++++++++-------- .../IotRedisStreamMQDataBridgeExecute.java | 28 ++++++------- .../IotRocketMQDataBridgeExecute.java | 40 +++++++++---------- 8 files changed, 81 insertions(+), 79 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java index 4cf1f8f28..a673b538e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java @@ -22,7 +22,7 @@ public interface IotRuleSceneAction { * 2. 非空的情况:设备触发 * @param config 配置 */ - void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config); + void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) throws Exception; /** * 获得类型 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index 6733331cb..d94922f5d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -26,10 +26,10 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { @Resource private IotDataBridgeService dataBridgeService; @Resource - private List dataBridgeExecutes; + private List> dataBridgeExecutes; @Override - public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { + public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) throws Exception { // 1.1 如果消息为空,直接返回 if (message == null) { return; @@ -47,7 +47,9 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { } // 2. 执行数据桥接操作 - dataBridgeExecutes.forEach(execute -> execute.execute(message, dataBridge)); + for (IotDataBridgeExecute execute : dataBridgeExecutes) { + execute.execute(message, dataBridge); + } } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java index 52c4483ec..d26c2dd43 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -93,4 +95,20 @@ public abstract class AbstractCacheableDataBridgeExecute imple */ protected abstract void closeProducer(Producer producer) throws Exception; + @Override + @SuppressWarnings({"unchecked"}) + public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { + // 1.1 校验数据桥梁类型 + if (!getType().equals(dataBridge.getType())) { + return; + } + + // 1.2 执行对应的数据桥梁发送消息 + try { + execute0(message, (Config) dataBridge.getConfig()); + } catch (Exception e) { + log.error("[execute][桥梁配置 config({}) 对应的 message({}) 发送异常]", dataBridge.getConfig(), message, e); + } + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java index 3f842f1f5..ce3d0f193 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java @@ -25,7 +25,7 @@ public interface IotDataBridgeExecute { * @param dataBridge 数据桥梁 */ @SuppressWarnings({"unchecked"}) - default void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { + default void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) throws Exception { // 1.1 校验数据桥梁类型 if (!getType().equals(dataBridge.getType())) { return; @@ -41,6 +41,6 @@ public interface IotDataBridgeExecute { * @param message 设备消息 * @param config 桥梁配置 */ - void execute0(IotDeviceMessage message, Config config); + void execute0(IotDeviceMessage message, Config config) throws Exception; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index 1efcfe9ca..b943eb31a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -15,7 +15,6 @@ import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; /** * Kafka 的 {@link IotDataBridgeExecute} 实现类 @@ -35,20 +34,14 @@ public class IotKafkaMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeDO.KafkaMQConfig config) { - try { - // 1. 获取或创建 KafkaTemplate - KafkaTemplate kafkaTemplate = getProducer(config); + public void execute0(IotDeviceMessage message, IotDataBridgeDO.KafkaMQConfig config) throws Exception { + // 1. 获取或创建 KafkaTemplate + KafkaTemplate kafkaTemplate = getProducer(config); - // 2. 发送消息并等待结果 - kafkaTemplate.send(config.getTopic(), message.toString()) - .get(SEND_TIMEOUT.getSeconds(), TimeUnit.SECONDS); // 添加超时等待 - log.info("[executeKafka][message({}) 发送成功]", message); - } catch (TimeoutException e) { - log.error("[executeKafka][message({}) config({}) 发送超时]", message, config, e); - } catch (Exception e) { - log.error("[executeKafka][message({}) config({}) 发送异常]", message, config, e); - } + // 2. 发送消息并等待结果 + kafkaTemplate.send(config.getTopic(), message.toString()) + .get(SEND_TIMEOUT.getSeconds(), TimeUnit.SECONDS); // 添加超时等待 + log.info("[execute0][message({}) 发送成功]", message); } @Override @@ -109,10 +102,10 @@ public class IotKafkaMQDataBridgeExecute extends // 4. 执行两次测试,验证缓存 log.info("[main][第一次执行,应该会创建新的 producer]"); - action.execute0(message, config); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); log.info("[main][第二次执行,应该会复用缓存的 producer]"); - action.execute0(message, config); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java index 27ebccc39..f99e65179 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -29,23 +29,19 @@ public class IotRabbitMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeDO.RabbitMQConfig config) { - try { - // 1. 获取或创建 Channel - Channel channel = getProducer(config); + public void execute0(IotDeviceMessage message, IotDataBridgeDO.RabbitMQConfig config) throws Exception { + // 1. 获取或创建 Channel + Channel channel = getProducer(config); - // 2.1 声明交换机、队列和绑定关系 - channel.exchangeDeclare(config.getExchange(), "direct", true); - channel.queueDeclare(config.getQueue(), true, false, false, null); - channel.queueBind(config.getQueue(), config.getExchange(), config.getRoutingKey()); + // 2.1 声明交换机、队列和绑定关系 + channel.exchangeDeclare(config.getExchange(), "direct", true); + channel.queueDeclare(config.getQueue(), true, false, false, null); + channel.queueBind(config.getQueue(), config.getExchange(), config.getRoutingKey()); - // 2.2 发送消息 - channel.basicPublish(config.getExchange(), config.getRoutingKey(), null, - message.toString().getBytes(StandardCharsets.UTF_8)); - log.info("[executeRabbitMQ][message({}) config({}) 发送成功]", message, config); - } catch (Exception e) { - log.error("[executeRabbitMQ][message({}) config({}) 发送异常]", message, config, e); - } + // 2.2 发送消息 + channel.basicPublish(config.getExchange(), config.getRoutingKey(), null, + message.toString().getBytes(StandardCharsets.UTF_8)); + log.info("[executeRabbitMQ][message({}) config({}) 发送成功]", message, config); } @Override @@ -107,11 +103,12 @@ public class IotRabbitMQDataBridgeExecute extends .build(); // 4. 执行两次测试,验证缓存 - log.info("[main][第一次执行,应该会创建新的 channel]"); - action.execute0(message, config); + // 4. 执行两次测试,验证缓存 + log.info("[main][第一次执行,应该会创建新的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - log.info("[main][第二次执行,应该会复用缓存的 channel]"); - action.execute0(message, config); + log.info("[main][第二次执行,应该会复用缓存的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java index f60528ef9..a20334f4f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java @@ -38,19 +38,15 @@ public class IotRedisStreamMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) { - try { - // 1. 获取 RedisTemplate - RedisTemplate redisTemplate = getProducer(config); + public void execute0(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) throws Exception { + // 1. 获取 RedisTemplate + RedisTemplate redisTemplate = getProducer(config); - // 2. 创建并发送 Stream 记录 - ObjectRecord record = StreamRecords.newRecord() - .ofObject(message).withStreamKey(config.getTopic()); - String recordId = String.valueOf(redisTemplate.opsForStream().add(record)); - log.info("[executeRedisStream][消息发送成功] messageId: {}, config: {}", recordId, config); - } catch (Exception e) { - log.error("[executeRedisStream][消息发送失败] message: {}, config: {}", message, config, e); - } + // 2. 创建并发送 Stream 记录 + ObjectRecord record = StreamRecords.newRecord() + .ofObject(message).withStreamKey(config.getTopic()); + String recordId = String.valueOf(redisTemplate.opsForStream().add(record)); + log.info("[executeRedisStream][消息发送成功] messageId: {}, config: {}", recordId, config); } @Override @@ -126,11 +122,11 @@ public class IotRedisStreamMQDataBridgeExecute extends .build(); // 4. 执行两次测试,验证缓存 - log.info("[main][第一次执行,应该会创建新的 RedisTemplate]"); - action.execute0(message, config); + log.info("[main][第一次执行,应该会创建新的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - log.info("[main][第二次执行,应该会复用缓存的 RedisTemplate]"); - action.execute0(message, config); + log.info("[main][第二次执行,应该会复用缓存的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index a68a6525e..df413c750 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -29,27 +29,23 @@ public class IotRocketMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { - try { - // 1. 获取或创建 Producer - DefaultMQProducer producer = getProducer(config); + public void execute0(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) throws Exception { + // 1. 获取或创建 Producer + DefaultMQProducer producer = getProducer(config); - // 2.1 创建消息对象,指定Topic、Tag和消息体 - Message msg = new Message( - config.getTopic(), - config.getTags(), - message.toString().getBytes(RemotingHelper.DEFAULT_CHARSET) - ); - // 2.2 发送同步消息并处理结果 - SendResult sendResult = producer.send(msg); - // 2.3 处理发送结果 - if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { - log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", message, config, sendResult); - } else { - log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", message, config, sendResult); - } - } catch (Exception e) { - log.error("[executeRocketMQ][message({}) config({}) 发送异常]", message, config, e); + // 2.1 创建消息对象,指定Topic、Tag和消息体 + Message msg = new Message( + config.getTopic(), + config.getTags(), + message.toString().getBytes(RemotingHelper.DEFAULT_CHARSET) + ); + // 2.2 发送同步消息并处理结果 + SendResult sendResult = producer.send(msg); + // 2.3 处理发送结果 + if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { + log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", message, config, sendResult); + } else { + log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", message, config, sendResult); } } @@ -93,10 +89,10 @@ public class IotRocketMQDataBridgeExecute extends // 4. 执行两次测试,验证缓存 log.info("[main][第一次执行,应该会创建新的 producer]"); - action.execute0(message, config); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); log.info("[main][第二次执行,应该会复用缓存的 producer]"); - action.execute0(message, config); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); } } From 7ab61b6d061801c5a24cd1d974ad382f174da1fe Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 3 Mar 2025 21:50:52 +0800 Subject: [PATCH 202/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20kafka=20=E6=95=B0=E6=8D=AE=E6=A1=A5?= =?UTF-8?q?=E6=A2=81=E6=B6=88=E6=81=AF=E7=AD=89=E5=BE=85=E7=9A=84=E6=9C=80?= =?UTF-8?q?=E5=A4=A7=E6=97=B6=E9=97=B4=E8=B0=83=E6=95=B4=E4=B8=BA=2010=20?= =?UTF-8?q?=E7=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rule/action/databridge/IotKafkaMQDataBridgeExecute.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index b943eb31a..9c125960b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -26,7 +26,7 @@ import java.util.concurrent.TimeUnit; public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute> { - private static final Duration SEND_TIMEOUT = Duration.ofMillis(10); + private static final Duration SEND_TIMEOUT = Duration.ofMillis(10000); // 10 秒超时时间 @Override public Integer getType() { From 71b45a29a304e033ea29dafc546873caa50c6678 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 4 Mar 2025 20:13:19 +0800 Subject: [PATCH 203/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9AMQTT=20=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/common/util/IotPluginCommonUtils.java | 4 ++-- .../emqx/upstream/IotDeviceUpstreamServer.java | 13 +++---------- .../upstream/router/IotDeviceAuthVertxHandler.java | 12 ++++++------ 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java index 753e62c94..d60df9cc0 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java @@ -50,10 +50,10 @@ public class IotPluginCommonUtils { } /** - * 将对象转换为JSON字符串后写入响应 + * 将对象转换为 JSON 字符串后写入响应 * * @param routingContext 路由上下文 - * @param data 要转换为JSON的数据对象 + * @param data 数据对象 */ @SuppressWarnings("deprecation") public static void writeJson(RoutingContext routingContext, Object data) { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java index 54479df15..c9db423e9 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin.emqx.upstream; +import cn.hutool.core.util.ArrayUtil; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.plugin.emqx.config.IotPluginEmqxProperties; import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router.IotDeviceAuthVertxHandler; @@ -167,33 +168,28 @@ public class IotDeviceUpstreamServer { */ private Future subscribeToTopics() { String[] topics = emqxProperties.getMqttTopics(); - if (topics == null || topics.length == 0) { + if (ArrayUtil.isEmpty(topics)) { log.warn("[subscribeToTopics] 未配置MQTT主题,跳过订阅"); return Future.succeededFuture(); } - log.info("[subscribeToTopics] 开始订阅设备上行消息主题"); Future compositeFuture = Future.succeededFuture(); - for (String topic : topics) { String trimmedTopic = topic.trim(); if (trimmedTopic.isEmpty()) { continue; } - compositeFuture = compositeFuture.compose(v -> client.subscribe(trimmedTopic, DEFAULT_QOS.value()) .map(ack -> { log.info("[subscribeToTopics] 成功订阅主题: {}", trimmedTopic); return null; }) .recover(err -> { - log.error("[subscribeToTopics] 订阅主题失败: {}, 原因: {}", - trimmedTopic, err.getMessage()); + log.error("[subscribeToTopics] 订阅主题失败: {}, 原因: {}", trimmedTopic, err.getMessage()); return Future.succeededFuture(); // 继续订阅其他主题 })); } - return compositeFuture; } @@ -205,7 +201,6 @@ public class IotDeviceUpstreamServer { log.warn("[stop] 服务未运行,无需停止"); return; } - log.info("[stop] 开始关闭服务"); isRunning = false; @@ -213,11 +208,9 @@ public class IotDeviceUpstreamServer { CompletableFuture serverFuture = server != null ? server.close().toCompletionStage().toCompletableFuture() : CompletableFuture.completedFuture(null); - CompletableFuture clientFuture = client != null ? client.disconnect().toCompletionStage().toCompletableFuture() : CompletableFuture.completedFuture(null); - CompletableFuture vertxFuture = vertx != null ? vertx.close().toCompletionStage().toCompletableFuture() : CompletableFuture.completedFuture(null); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java index 350de674c..3f3cf94e9 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java @@ -14,8 +14,7 @@ import java.util.Collections; /** * IoT Emqx 连接认证的 Vert.x Handler - * ... + * MQTT HTTP * * @author haohao */ @@ -31,28 +30,29 @@ public class IotDeviceAuthVertxHandler implements Handler { @SuppressWarnings("unchecked") public void handle(RoutingContext routingContext) { try { + // 构建认证请求 DTO JsonObject json = routingContext.body().asJsonObject(); String clientId = json.getString("clientid"); String username = json.getString("username"); String password = json.getString("password"); - - // 构建认证请求DTO IotDeviceEmqxAuthReqDTO authReqDTO = new IotDeviceEmqxAuthReqDTO() .setClientId(clientId) .setUsername(username) .setPassword(password); - // 调用认证API + // 调用认证 API CommonResult authResult = deviceUpstreamApi.authenticateEmqxConnection(authReqDTO); if (authResult.getCode() != 0 || !authResult.getData()) { IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "deny")); return; } + // 响应结果 IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "allow")); } catch (Exception e) { - log.error("[handle][EMQX认证异常]", e); + log.error("[handle][EMQX 认证异常]", e); IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "deny")); } } + } \ No newline at end of file From 824a801b39225d356bf5a7d6745e62d084b93a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 7 Mar 2025 22:36:38 +0800 Subject: [PATCH 204/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=B7=BB=E5=8A=A0=20Webhook=20?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=99=A8=E4=BB=A5=E5=A4=84=E7=90=86=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E8=BF=9E=E6=8E=A5=E5=92=8C=E6=96=AD=E5=BC=80=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E6=9B=B4=E6=96=B0=E8=AE=BE=E5=A4=87=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E7=AE=A1=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../upstream/IotDeviceUpstreamServer.java | 4 + .../router/IotDeviceWebhookVertxHandler.java | 154 ++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java index c9db423e9..040985ba9 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.plugin.emqx.config.IotPluginEmqxProperties; import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router.IotDeviceAuthVertxHandler; import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router.IotDeviceMqttMessageHandler; +import cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router.IotDeviceWebhookVertxHandler; import io.netty.handler.codec.mqtt.MqttQoS; import io.vertx.core.Future; import io.vertx.core.Vertx; @@ -70,6 +71,9 @@ public class IotDeviceUpstreamServer { // TODO @haohao:疑问,mqtt 的认证,需要通过 http 呀? // 回复:MQTT 认证不必须通过 HTTP 进行,但 HTTP 认证是 EMQX 等 MQTT 服务器支持的一种灵活的认证方式 .handler(new IotDeviceAuthVertxHandler(deviceUpstreamApi)); + // 添加 Webhook 处理器,用于处理设备连接和断开连接事件 + router.post(IotDeviceWebhookVertxHandler.PATH) + .handler(new IotDeviceWebhookVertxHandler(deviceUpstreamApi)); // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); this.mqttMessageHandler = new IotDeviceMqttMessageHandler(deviceUpstreamApi, client); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java new file mode 100644 index 000000000..a2499826f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java @@ -0,0 +1,154 @@ +package cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.Collections; + +/** + * IoT Emqx Webhook 事件处理的 Vert.x Handler + * EMQX + * Webhook + * + * @author haohao + */ +@RequiredArgsConstructor +@Slf4j +public class IotDeviceWebhookVertxHandler implements Handler { + + public static final String PATH = "/mqtt/webhook"; + + private final IotDeviceUpstreamApi deviceUpstreamApi; + + @Override + public void handle(RoutingContext routingContext) { + try { + // 解析请求体 + JsonObject json = routingContext.body().asJsonObject(); + String event = json.getString("event"); + String clientId = json.getString("clientid"); + String username = json.getString("username"); + + // 处理不同的事件类型 + switch (event) { + case "client.connected": + handleClientConnected(clientId, username); + break; + case "client.disconnected": + handleClientDisconnected(clientId, username); + break; + default: + log.info("[handle][未处理的 Webhook 事件] event={}, clientId={}, username={}", event, clientId, + username); + break; + } + + // 返回成功响应 + IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "success")); + } catch (Exception e) { + log.error("[handle][处理 Webhook 事件异常]", e); + IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "error")); + } + } + + /** + * 处理客户端连接事件 + * + * @param clientId 客户端ID + * @param username 用户名 + */ + private void handleClientConnected(String clientId, String username) { + if (StrUtil.isEmpty(username) || "undefined".equals(username)) { + log.warn("[handleClientConnected][客户端连接事件,但用户名为空] clientId={}", clientId); + return; + } + + // 解析产品标识和设备名称 + String[] parts = parseUsername(username); + if (parts == null) { + return; + } + + // 更新设备状态为在线 + IotDeviceStateUpdateReqDTO updateReqDTO = new IotDeviceStateUpdateReqDTO(); + updateReqDTO.setProductKey(parts[1]); + updateReqDTO.setDeviceName(parts[0]); + updateReqDTO.setState(IotDeviceStateEnum.ONLINE.getState()); + updateReqDTO.setProcessId(IotPluginCommonUtils.getProcessId()); + updateReqDTO.setReportTime(LocalDateTime.now()); + + CommonResult result = deviceUpstreamApi.updateDeviceState(updateReqDTO); + if (result.getCode() != 0 || !result.getData()) { + log.error("[handleClientConnected][更新设备状态为在线失败] clientId={}, username={}, code={}, msg={}", + clientId, username, result.getCode(), result.getMsg()); + } else { + log.info("[handleClientConnected][更新设备状态为在线成功] clientId={}, username={}", clientId, username); + } + } + + /** + * 处理客户端断开连接事件 + * + * @param clientId 客户端ID + * @param username 用户名 + */ + private void handleClientDisconnected(String clientId, String username) { + if (StrUtil.isEmpty(username) || "undefined".equals(username)) { + log.warn("[handleClientDisconnected][客户端断开连接事件,但用户名为空] clientId={}", clientId); + return; + } + + // 解析产品标识和设备名称 + String[] parts = parseUsername(username); + if (parts == null) { + return; + } + + // 更新设备状态为离线 + IotDeviceStateUpdateReqDTO offlineReqDTO = new IotDeviceStateUpdateReqDTO(); + offlineReqDTO.setProductKey(parts[1]); + offlineReqDTO.setDeviceName(parts[0]); + offlineReqDTO.setState(IotDeviceStateEnum.OFFLINE.getState()); + offlineReqDTO.setProcessId(IotPluginCommonUtils.getProcessId()); + offlineReqDTO.setReportTime(LocalDateTime.now()); + + CommonResult offlineResult = deviceUpstreamApi.updateDeviceState(offlineReqDTO); + if (offlineResult.getCode() != 0 || !offlineResult.getData()) { + log.error("[handleClientDisconnected][更新设备状态为离线失败] clientId={}, username={}, code={}, msg={}", + clientId, username, offlineResult.getCode(), offlineResult.getMsg()); + } else { + log.info("[handleClientDisconnected][更新设备状态为离线成功] clientId={}, username={}", clientId, username); + } + } + + /** + * 解析用户名,格式为 deviceName&productKey + * + * @param username 用户名 + * @return 解析结果,[0]为deviceName,[1]为productKey,解析失败返回null + */ + private String[] parseUsername(String username) { + if (StrUtil.isEmpty(username)) { + return null; + } + + String[] parts = username.split("&"); + if (parts.length != 2) { + log.warn("[parseUsername][用户名格式不正确,无法解析产品标识和设备名称] username={}", username); + return null; + } + + return parts; + } +} \ No newline at end of file From 831970233c63cd50f056b330f0e675102d2dd9c3 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sat, 8 Mar 2025 10:50:22 +0800 Subject: [PATCH 205/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=E7=9A=84=E6=89=A7=E8=A1=8C=E5=99=A8=E6=A0=B9=E6=8D=AE=E5=BC=95?= =?UTF-8?q?=E5=85=A5=E7=9A=84=E6=B6=88=E6=81=AF=E9=98=9F=E5=88=97=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databridge/IotKafkaMQDataBridgeExecute.java | 2 ++ .../databridge/IotRabbitMQDataBridgeExecute.java | 2 ++ .../databridge/IotRocketMQDataBridgeExecute.java | 2 ++ yudao-server/pom.xml | 13 +++++++++++++ 4 files changed, 19 insertions(+) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index 9c125960b..6bcf41ab6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; @@ -21,6 +22,7 @@ import java.util.concurrent.TimeUnit; * * @author HUIHUI */ +@ConditionalOnClass(KafkaTemplate.class) @Component @Slf4j public class IotKafkaMQDataBridgeExecute extends diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java index f99e65179..ebe9d8ddd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -7,6 +7,7 @@ import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets; @@ -17,6 +18,7 @@ import java.time.LocalDateTime; * * @author HUIHUI */ +@ConditionalOnClass(Channel.class) @Component @Slf4j public class IotRabbitMQDataBridgeExecute extends diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index df413c750..655ad55eb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -9,6 +9,7 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.remoting.common.RemotingHelper; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @@ -18,6 +19,7 @@ import java.time.LocalDateTime; * * @author HUIHUI */ +@ConditionalOnClass(DefaultMQProducer.class) @Component @Slf4j public class IotRocketMQDataBridgeExecute extends diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 492e31db5..2cf04e8eb 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -114,6 +114,19 @@ yudao-module-iot-biz ${revision} + + + org.apache.rocketmq + rocketmq-spring-boot-starter + + + org.springframework.kafka + spring-kafka + + + org.springframework.boot + spring-boot-starter-amqp + From 415dd435f36d995309f2360289602b2d062311b5 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sat, 8 Mar 2025 11:25:03 +0800 Subject: [PATCH 206/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=E7=9A=84=E6=89=A7=E8=A1=8C=E5=99=A8=E6=A0=B9=E6=8D=AE=E5=BC=95?= =?UTF-8?q?=E5=85=A5=E7=9A=84=E6=B6=88=E6=81=AF=E9=98=9F=E5=88=97=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rule/action/databridge/IotKafkaMQDataBridgeExecute.java | 2 +- .../rule/action/databridge/IotRabbitMQDataBridgeExecute.java | 2 +- .../rule/action/databridge/IotRocketMQDataBridgeExecute.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index 6bcf41ab6..6e3ef67a2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit; * * @author HUIHUI */ -@ConditionalOnClass(KafkaTemplate.class) +@ConditionalOnClass(name = "org.springframework.kafka.core.KafkaTemplate") @Component @Slf4j public class IotKafkaMQDataBridgeExecute extends diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java index ebe9d8ddd..5599144da 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -18,7 +18,7 @@ import java.time.LocalDateTime; * * @author HUIHUI */ -@ConditionalOnClass(Channel.class) +@ConditionalOnClass(name = "com.rabbitmq.client.Channel") @Component @Slf4j public class IotRabbitMQDataBridgeExecute extends diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index 655ad55eb..542d190ed 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -19,7 +19,7 @@ import java.time.LocalDateTime; * * @author HUIHUI */ -@ConditionalOnClass(DefaultMQProducer.class) +@ConditionalOnClass(name = "org.apache.rocketmq.client.producer.DefaultMQProducer") @Component @Slf4j public class IotRocketMQDataBridgeExecute extends From e66c69932f873709fd85df62ccbbcf5662cf2cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 8 Mar 2025 21:59:54 +0800 Subject: [PATCH 207/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=9B=B4=E6=96=B0=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E6=98=A0=E5=B0=84=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=B9=20device=5Fkey=20=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java index e506b49d4..955b38478 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java @@ -34,7 +34,7 @@ public interface IotDevicePropertyMapper { List newFields) { // TODO @芋艿:需要处理 device_key,重新发布的时候 oldFields.removeIf(field -> StrUtil.equalsAny(field.getField(), - TDengineTableField.FIELD_TS, "report_time")); + TDengineTableField.FIELD_TS, "report_time", "device_key")); List addFields = newFields.stream().filter( // 新增的字段 newField -> oldFields.stream().noneMatch(oldField -> oldField.getField().equals(newField.getField()))) .collect(Collectors.toList()); From ff9267ad759a819ba97cdd19c5264cb47ad23043 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 9 Mar 2025 12:53:54 +0800 Subject: [PATCH 208/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=20CRUD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 3 + .../admin/rule/IotDataBridgeController.java | 93 +++++++++++++++++++ .../vo/databridge/IotDataBridgePageReqVO.java | 39 ++++++++ .../vo/databridge/IotDataBridgeRespVO.java | 52 +++++++++++ .../vo/databridge/IotDataBridgeSaveReqVO.java | 37 ++++++++ .../admin/rule/vo/package-info.java | 1 + .../dal/mysql/rule/IotDataBridgeMapper.java | 22 ++++- .../service/rule/IotDataBridgeService.java | 48 ++++++++-- .../rule/IotDataBridgeServiceImpl.java | 67 ++++++++----- .../action/IotRuleSceneDataBridgeAction.java | 2 +- 10 files changed, 334 insertions(+), 30 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/package-info.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 3d12c4b59..7b84c66fc 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -70,4 +70,7 @@ public interface ErrorCodeConstants { // ========== MQTT 通信相关 1-050-009-000 ========== ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal"); + // ========== IoT 数据桥梁 1-050-010-000 ========== + ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在"); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java new file mode 100644 index 000000000..2d2f8fb75 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 数据桥梁") +@RestController +@RequestMapping("/iot/data-bridge") +@Validated +public class IotDataBridgeController { + + @Resource + private IotDataBridgeService dataBridgeService; + + @PostMapping("/create") + @Operation(summary = "创建IoT 数据桥梁") + @PreAuthorize("@ss.hasPermission('iot:data-bridge:create')") + public CommonResult createDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO createReqVO) { + return success(dataBridgeService.createDataBridge(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新IoT 数据桥梁") + @PreAuthorize("@ss.hasPermission('iot:data-bridge:update')") + public CommonResult updateDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO updateReqVO) { + dataBridgeService.updateDataBridge(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除IoT 数据桥梁") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:data-bridge:delete')") + public CommonResult deleteDataBridge(@RequestParam("id") Long id) { + dataBridgeService.deleteDataBridge(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得IoT 数据桥梁") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") + public CommonResult getDataBridge(@RequestParam("id") Long id) { + IotDataBridgeDO dataBridge = dataBridgeService.getDataBridge(id); + return success(BeanUtils.toBean(dataBridge, IotDataBridgeRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得IoT 数据桥梁分页") + @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") + public CommonResult> getDataBridgePage(@Valid IotDataBridgePageReqVO pageReqVO) { + PageResult pageResult = dataBridgeService.getDataBridgePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotDataBridgeRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出IoT 数据桥梁 Excel") + @PreAuthorize("@ss.hasPermission('iot:data-bridge:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDataBridgeExcel(@Valid IotDataBridgePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = dataBridgeService.getDataBridgePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "IoT 数据桥梁.xls", "数据", IotDataBridgeRespVO.class, + BeanUtils.toBean(list, IotDataBridgeRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java new file mode 100644 index 000000000..7da87be07 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 数据桥梁分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class IotDataBridgePageReqVO extends PageParam { + + @Schema(description = "桥梁名称", example = "赵六") + private String name; + + @Schema(description = "桥梁描述", example = "随便") + private String description; + + @Schema(description = "桥梁状态", example = "2") + private Integer status; + + @Schema(description = "桥梁方向") + private Integer direction; + + @Schema(description = "桥梁类型", example = "1") + private Integer type; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java new file mode 100644 index 000000000..85247358c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 数据桥梁 Response VO") +@Data +@ExcelIgnoreUnannotated +public class IotDataBridgeRespVO { + + @Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564") + @ExcelProperty("桥梁编号") + private Long id; + + @Schema(description = "桥梁名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @ExcelProperty("桥梁名称") + private String name; + + @Schema(description = "桥梁描述", example = "随便") + @ExcelProperty("桥梁描述") + private String description; + + @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty(value = "桥梁状态", converter = DictConvert.class) + @DictFormat("common_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer status; + + @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "桥梁方向", converter = DictConvert.class) + @DictFormat("iot_data_bridg_direction_enum") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer direction; + + @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "桥梁类型", converter = DictConvert.class) + @DictFormat("iot_data_bridg_type_enum") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer type; + + @Schema(description = "桥梁配置") + @ExcelProperty("桥梁配置") + private String config; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java new file mode 100644 index 000000000..2fd8b3609 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 数据桥梁新增/修改 Request VO") +@Data +public class IotDataBridgeSaveReqVO { + + @Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564") + private Long id; + + @Schema(description = "桥梁名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "桥梁名称不能为空") + private String name; + + @Schema(description = "桥梁描述", example = "随便") + private String description; + + @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "桥梁状态不能为空") + private Integer status; + + @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "桥梁方向不能为空") + private Integer direction; + + @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "桥梁类型不能为空") + private Integer type; + + @Schema(description = "桥梁配置") + private String config; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/package-info.java new file mode 100644 index 000000000..a977d86e9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java index 076b341f0..1609aec34 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java @@ -1,9 +1,29 @@ package cn.iocoder.yudao.module.iot.dal.mysql.rule; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import org.apache.ibatis.annotations.Mapper; +/** + * IoT 数据桥梁 Mapper + * + * @author HUIHUI + */ @Mapper public interface IotDataBridgeMapper extends BaseMapperX { -} + + default PageResult selectPage(IotDataBridgePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotDataBridgeDO::getName, reqVO.getName()) + .likeIfPresent(IotDataBridgeDO::getDescription, reqVO.getDescription()) + .eqIfPresent(IotDataBridgeDO::getStatus, reqVO.getStatus()) + .eqIfPresent(IotDataBridgeDO::getDirection, reqVO.getDirection()) + .eqIfPresent(IotDataBridgeDO::getType, reqVO.getType()) + .betweenIfPresent(IotDataBridgeDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotDataBridgeDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java index cbf0b36c2..f720a1d15 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java @@ -1,20 +1,54 @@ package cn.iocoder.yudao.module.iot.service.rule; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import jakarta.validation.Valid; /** - * IoT 数据桥梁的 Service 接口 + * IoT 数据桥梁 Service 接口 * - * @author 芋道源码 + * @author HUIHUI */ public interface IotDataBridgeService { /** - * 获得指定数据桥梁 + * 创建IoT 数据桥梁 * - * @param id 数据桥梁编号 - * @return 数据桥梁 + * @param createReqVO 创建信息 + * @return 编号 */ - IotDataBridgeDO getIotDataBridge(Long id); + Long createDataBridge(@Valid IotDataBridgeSaveReqVO createReqVO); -} + /** + * 更新IoT 数据桥梁 + * + * @param updateReqVO 更新信息 + */ + void updateDataBridge(@Valid IotDataBridgeSaveReqVO updateReqVO); + + /** + * 删除IoT 数据桥梁 + * + * @param id 编号 + */ + void deleteDataBridge(Long id); + + /** + * 获得IoT 数据桥梁 + * + * @param id 编号 + * @return IoT 数据桥梁 + */ + IotDataBridgeDO getDataBridge(Long id); + + /** + * 获得IoT 数据桥梁分页 + * + * @param pageReqVO 分页查询 + * @return IoT 数据桥梁分页 + */ + PageResult getDataBridgePage(IotDataBridgePageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java index 7814fd9bb..9e439fc99 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java @@ -1,45 +1,70 @@ package cn.iocoder.yudao.module.iot.service.rule; -import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataBridgeMapper; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.util.Objects; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_BRIDGE_NOT_EXISTS; /** - * IoT 数据桥梁的 Service 实现类 + * IoT 数据桥梁 Service 实现类 * - * @author 芋道源码 + * @author HUIHUI */ @Service @Validated -@Slf4j public class IotDataBridgeServiceImpl implements IotDataBridgeService { @Resource private IotDataBridgeMapper dataBridgeMapper; - // TODO @芋艿:临时测试 @Override - public IotDataBridgeDO getIotDataBridge(Long id) { - if (Objects.equals(id, 1L)) { - IotDataBridgeDO.HttpConfig config = new IotDataBridgeDO.HttpConfig() - .setUrl("http://127.0.0.1:48080/test") -// .setMethod("POST") - .setMethod("GET") - .setQuery(MapUtil.of("aaa", "bbb")) - .setHeaders(MapUtil.of("ccc", "ddd")) - .setBody(JsonUtils.toJsonString(MapUtil.of("eee", "fff"))); - return IotDataBridgeDO.builder().id(1L).name("芋道").description("芋道源码").status(0).direction(1) - .type(IotDataBridgTypeEnum.HTTP.getType()).config(config).build(); + public Long createDataBridge(IotDataBridgeSaveReqVO createReqVO) { + // 插入 + IotDataBridgeDO dataBridge = BeanUtils.toBean(createReqVO, IotDataBridgeDO.class); + dataBridgeMapper.insert(dataBridge); + // 返回 + return dataBridge.getId(); + } + + @Override + public void updateDataBridge(IotDataBridgeSaveReqVO updateReqVO) { + // 校验存在 + validateDataBridgeExists(updateReqVO.getId()); + // 更新 + IotDataBridgeDO updateObj = BeanUtils.toBean(updateReqVO, IotDataBridgeDO.class); + dataBridgeMapper.updateById(updateObj); + } + + @Override + public void deleteDataBridge(Long id) { + // 校验存在 + validateDataBridgeExists(id); + // 删除 + dataBridgeMapper.deleteById(id); + } + + private void validateDataBridgeExists(Long id) { + if (dataBridgeMapper.selectById(id) == null) { + throw exception(DATA_BRIDGE_NOT_EXISTS); } + } + + @Override + public IotDataBridgeDO getDataBridge(Long id) { return dataBridgeMapper.selectById(id); } -} + @Override + public PageResult getDataBridgePage(IotDataBridgePageReqVO pageReqVO) { + return dataBridgeMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index d94922f5d..b38e181f9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -36,7 +36,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { } // 1.2 获得数据桥梁 Assert.notNull(config.getDataBridgeId(), "数据桥梁编号不能为空"); - IotDataBridgeDO dataBridge = dataBridgeService.getIotDataBridge(config.getDataBridgeId()); + IotDataBridgeDO dataBridge = dataBridgeService.getDataBridge(config.getDataBridgeId()); if (dataBridge == null || dataBridge.getConfig() == null) { log.error("[execute][message({}) config({}) 对应的数据桥梁不存在]", message, config); return; From b1d3b73b6d73d99808a24797831a5cab58213844 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 9 Mar 2025 13:29:12 +0800 Subject: [PATCH 209/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=20config=20=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/DictTypeConstants.java | 3 + ...m.java => IotDataBridgeDirectionEnum.java} | 4 +- ...peEnum.java => IotDataBridgeTypeEnum.java} | 25 +- .../vo/databridge/IotDataBridgeRespVO.java | 13 +- .../vo/databridge/IotDataBridgeSaveReqVO.java | 4 +- .../config/IotDataBridgeConfig.java | 32 +++ .../config/IotDataBridgeHttpConfig.java | 36 +++ .../config/IotDataBridgeKafkaMQConfig.java | 35 +++ .../config/IotDataBridgeMqttConfig.java | 34 +++ .../config/IotDataBridgeRabbitMQConfig.java | 46 ++++ .../IotDataBridgeRedisStreamMQConfig.java | 34 +++ .../config/IotDataBridgeRocketMQConfig.java | 39 ++++ .../dal/dataobject/rule/IotDataBridgeDO.java | 217 +----------------- .../databridge/IotHttpDataBridgeExecute.java | 10 +- .../IotKafkaMQDataBridgeExecute.java | 13 +- .../IotRabbitMQDataBridgeExecute.java | 13 +- .../IotRedisStreamMQDataBridgeExecute.java | 13 +- .../IotRocketMQDataBridgeExecute.java | 13 +- 18 files changed, 325 insertions(+), 259 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/{IotDataBridgDirectionEnum.java => IotDataBridgeDirectionEnum.java} (78%) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/{IotDataBridgTypeEnum.java => IotDataBridgeTypeEnum.java} (53%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java index 04df143be..fc442d2b3 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java @@ -15,5 +15,8 @@ public class DictTypeConstants { public static final String VALIDATE_TYPE = "iot_validate_type"; public static final String DEVICE_STATE = "iot_device_state"; + public static final String IOT_DATA_BRIDGE_DIRECTION_ENUM = "iot_data_bridge_direction_enum"; + public static final String IOT_DATA_BRIDGE_TYPE_ENUM = "iot_data_bridge_type_enum"; + } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java similarity index 78% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgDirectionEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java index ff4993d0e..eb4b99916 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgDirectionEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java @@ -13,14 +13,14 @@ import java.util.Arrays; */ @RequiredArgsConstructor @Getter -public enum IotDataBridgDirectionEnum implements ArrayValuable { +public enum IotDataBridgeDirectionEnum implements ArrayValuable { INPUT(1), // 输入 OUTPUT(2); // 输出 private final Integer type; - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgDirectionEnum::getType).toArray(Integer[]::new); + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeDirectionEnum::getType).toArray(Integer[]::new); @Override public Integer[] array() { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java similarity index 53% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java index 295f35cff..25c7e8c1f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java @@ -13,25 +13,26 @@ import java.util.Arrays; */ @RequiredArgsConstructor @Getter -public enum IotDataBridgTypeEnum implements ArrayValuable { +public enum IotDataBridgeTypeEnum implements ArrayValuable { - HTTP(1), - TCP(2), - WEBSOCKET(3), + HTTP(1, "HTTP"), + TCP(2, "TCP"), + WEBSOCKET(3, "WEBSOCKET"), - MQTT(10), + MQTT(10, "MQTT"), - DATABASE(20), - REDIS_STREAM(21), + DATABASE(20, "DATABASE"), + REDIS_STREAM(21, "REDIS_STREAM"), - ROCKETMQ(30), - RABBITMQ(31), - KAFKA(32) - ; + ROCKETMQ(30, "ROCKETMQ"), + RABBITMQ(31, "RABBITMQ"), + KAFKA(32, "KAFKA"); private final Integer type; - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgTypeEnum::getType).toArray(Integer[]::new); + private final String name; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeTypeEnum::getType).toArray(Integer[]::new); @Override public Integer[] array() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java index 85247358c..3e50dc4d5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeConfig; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -9,6 +10,10 @@ import lombok.Data; import java.time.LocalDateTime; +import static cn.iocoder.yudao.module.iot.enums.DictTypeConstants.IOT_DATA_BRIDGE_DIRECTION_ENUM; +import static cn.iocoder.yudao.module.iot.enums.DictTypeConstants.IOT_DATA_BRIDGE_TYPE_ENUM; +import static cn.iocoder.yudao.module.system.enums.DictTypeConstants.COMMON_STATUS; + @Schema(description = "管理后台 - IoT 数据桥梁 Response VO") @Data @ExcelIgnoreUnannotated @@ -28,22 +33,22 @@ public class IotDataBridgeRespVO { @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @ExcelProperty(value = "桥梁状态", converter = DictConvert.class) - @DictFormat("common_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + @DictFormat(COMMON_STATUS) private Integer status; @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty(value = "桥梁方向", converter = DictConvert.class) - @DictFormat("iot_data_bridg_direction_enum") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + @DictFormat(IOT_DATA_BRIDGE_DIRECTION_ENUM) private Integer direction; @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelProperty(value = "桥梁类型", converter = DictConvert.class) - @DictFormat("iot_data_bridg_type_enum") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + @DictFormat(IOT_DATA_BRIDGE_TYPE_ENUM) private Integer type; @Schema(description = "桥梁配置") @ExcelProperty("桥梁配置") - private String config; + private IotDataBridgeConfig config; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java index 2fd8b3609..96620a1ca 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeConfig; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -32,6 +33,7 @@ public class IotDataBridgeSaveReqVO { private Integer type; @Schema(description = "桥梁配置") - private String config; + @NotNull(message = "桥梁配置不能为空") + private IotDataBridgeConfig config; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeConfig.java new file mode 100644 index 000000000..f37a51edb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeConfig.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import lombok.Data; + +/** + * 抽象类 IotDataBridgeConfig + * + * 用于表示数据桥梁配置数据的通用类型,根据具体的 "type" 字段动态映射到对应的子类。 + * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 + * + * @author HUIHUI + */ +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = IotDataBridgeHttpConfig.class, name = "HTTP"), + @JsonSubTypes.Type(value = IotDataBridgeKafkaMQConfig.class, name = "KAFKA"), + @JsonSubTypes.Type(value = IotDataBridgeMqttConfig.class, name = "MQTT"), + @JsonSubTypes.Type(value = IotDataBridgeRabbitMQConfig.class, name = "RABBITMQ"), + @JsonSubTypes.Type(value = IotDataBridgeRedisStreamMQConfig.class, name = "REDIS_STREAM"), + @JsonSubTypes.Type(value = IotDataBridgeRocketMQConfig.class, name = "ROCKETMQ"), +}) +public abstract class IotDataBridgeConfig { + + /** + * 配置类型 + */ + private String type; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java new file mode 100644 index 000000000..69cdc71f7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; + +import lombok.Data; + +import java.util.Map; + +/** + * HTTP 配置 + * + * @author HUIHUI + */ +@Data +public class IotDataBridgeHttpConfig extends IotDataBridgeConfig { + + /** + * 请求 URL + */ + private String url; + /** + * 请求方法 + */ + private String method; + /** + * 请求头 + */ + private Map headers; + /** + * 请求参数 + */ + private Map query; + /** + * 请求体 + */ + private String body; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java new file mode 100644 index 000000000..3acd646f3 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; + +import lombok.Data; + +/** + * Kafka 配置 + * + * @author HUIHUI + */ +@Data +public class IotDataBridgeKafkaMQConfig extends IotDataBridgeConfig { + + /** + * Kafka 服务器地址 + */ + private String bootstrapServers; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + /** + * 是否启用 SSL + */ + private Boolean ssl; + + /** + * 主题 + */ + private String topic; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java new file mode 100644 index 000000000..0bf7067bc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; + +import lombok.Data; + +/** + * MQTT 配置 + * + * @author HUIHUI + */ +@Data +public class IotDataBridgeMqttConfig extends IotDataBridgeConfig { + + /** + * MQTT 服务器地址 + */ + private String url; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + /** + * 客户端编号 + */ + private String clientId; + /** + * 主题 + */ + private String topic; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java new file mode 100644 index 000000000..29bf32897 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; + +import lombok.Data; + +/** + * RabbitMQ 配置 + * + * @author HUIHUI + */ +@Data +public class IotDataBridgeRabbitMQConfig extends IotDataBridgeConfig { + + /** + * RabbitMQ 服务器地址 + */ + private String host; + /** + * 端口 + */ + private Integer port; + /** + * 虚拟主机 + */ + private String virtualHost; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + + /** + * 交换机名称 + */ + private String exchange; + /** + * 路由键 + */ + private String routingKey; + /** + * 队列名称 + */ + private String queue; +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java new file mode 100644 index 000000000..db7b2b2bc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; + +import lombok.Data; + +/** + * Redis Stream MQ 配置 + * + * @author HUIHUI + */ +@Data +public class IotDataBridgeRedisStreamMQConfig extends IotDataBridgeConfig { + + /** + * Redis 服务器地址 + */ + private String host; + /** + * 端口 + */ + private Integer port; + /** + * 密码 + */ + private String password; + /** + * 数据库索引 + */ + private Integer database; + + /** + * 主题 + */ + private String topic; +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java new file mode 100644 index 000000000..e911461e4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; + +import lombok.Data; + +/** + * RocketMQ 配置 + * + * @author HUIHUI + */ +@Data +public class IotDataBridgeRocketMQConfig extends IotDataBridgeConfig { + + /** + * RocketMQ 名称服务器地址 + */ + private String nameServer; + /** + * 访问密钥 + */ + private String accessKey; + /** + * 秘密钥匙 + */ + private String secretKey; + + /** + * 生产者组 + */ + private String group; + /** + * 主题 + */ + private String topic; + /** + * 标签 + */ + private String tags; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index bb0623a1f..ef0a60eca 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -1,16 +1,16 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeConfig; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; -import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.*; -import java.util.Map; - /** * IoT 数据桥梁 DO * @@ -48,14 +48,14 @@ public class IotDataBridgeDO extends BaseDO { /** * 桥梁方向 * - * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgDirectionEnum} + * 枚举 {@link IotDataBridgeDirectionEnum} */ private Integer direction; /** * 桥梁类型 * - * 枚举 {@link cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum} + * 枚举 {@link IotDataBridgeTypeEnum} */ private Integer type; @@ -63,211 +63,6 @@ public class IotDataBridgeDO extends BaseDO { * 桥梁配置 */ @TableField(typeHandler = JacksonTypeHandler.class) - private Config config; - - /** - * 文件客户端的配置 - * 不同实现的客户端,需要不同的配置,通过子类来定义 - * - * @author 芋道源码 - */ - @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) - // @JsonTypeInfo 注解的作用,Jackson 多态 - // 1. 序列化到时数据库时,增加 @class 属性。 - // 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型 - public interface Config { - } - - /** - * HTTP 配置 - */ - @Data - public static class HttpConfig implements Config { - - /** - * 请求 URL - */ - private String url; - /** - * 请求方法 - */ - private String method; - /** - * 请求头 - */ - private Map headers; - /** - * 请求参数 - */ - private Map query; - /** - * 请求体 - */ - private String body; - - } - - /** - * MQTT 配置 - */ - @Data - public static class MqttConfig implements Config { - - /** - * MQTT 服务器地址 - */ - private String url; - /** - * 用户名 - */ - private String username; - /** - * 密码 - */ - private String password; - /** - * 客户端编号 - */ - private String clientId; - /** - * 主题 - */ - private String topic; - - } - - /** - * RocketMQ 配置 - */ - @Data - public static class RocketMQConfig implements Config { - - /** - * RocketMQ 名称服务器地址 - */ - private String nameServer; - /** - * 访问密钥 - */ - private String accessKey; - /** - * 秘密钥匙 - */ - private String secretKey; - - /** - * 生产者组 - */ - private String group; - /** - * 主题 - */ - private String topic; - /** - * 标签 - */ - private String tags; - - } - - /** - * Kafka 配置 - */ - @Data - public static class KafkaMQConfig implements Config { - - /** - * Kafka 服务器地址 - */ - private String bootstrapServers; - /** - * 用户名 - */ - private String username; - /** - * 密码 - */ - private String password; - /** - * 是否启用 SSL - */ - private Boolean ssl; - - /** - * 主题 - */ - private String topic; - - } - - /** - * RabbitMQ 配置 - */ - @Data - public static class RabbitMQConfig implements Config { - - /** - * RabbitMQ 服务器地址 - */ - private String host; - /** - * 端口 - */ - private Integer port; - /** - * 虚拟主机 - */ - private String virtualHost; - /** - * 用户名 - */ - private String username; - /** - * 密码 - */ - private String password; - - /** - * 交换机名称 - */ - private String exchange; - /** - * 路由键 - */ - private String routingKey; - /** - * 队列名称 - */ - private String queue; - } - - /** - * Redis Stream MQ 配置 - */ - @Data - public static class RedisStreamMQConfig implements Config { - - /** - * Redis 服务器地址 - */ - private String host; - /** - * 端口 - */ - private Integer port; - /** - * 密码 - */ - private String password; - /** - * 数据库索引 - */ - private Integer database; - - /** - * 主题 - */ - private String topic; - } + private IotDataBridgeConfig config; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java index ffe2c5b80..22b72e055 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeHttpConfig; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -25,19 +25,19 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ */ @Component @Slf4j -public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { +public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { @Resource private RestTemplate restTemplate; @Override public Integer getType() { - return IotDataBridgTypeEnum.HTTP.getType(); + return IotDataBridgeTypeEnum.HTTP.getType(); } @Override @SuppressWarnings({"unchecked", "deprecation"}) - public void execute0(IotDeviceMessage message, IotDataBridgeDO.HttpConfig config) { + public void execute0(IotDeviceMessage message, IotDataBridgeHttpConfig config) { String url = null; HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase()); HttpEntity requestEntity = null; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index 6e3ef67a2..3b7f99bf4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -1,7 +1,8 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeKafkaMQConfig; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.producer.ProducerConfig; @@ -26,17 +27,17 @@ import java.util.concurrent.TimeUnit; @Component @Slf4j public class IotKafkaMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute> { + AbstractCacheableDataBridgeExecute> { private static final Duration SEND_TIMEOUT = Duration.ofMillis(10000); // 10 秒超时时间 @Override public Integer getType() { - return IotDataBridgTypeEnum.KAFKA.getType(); + return IotDataBridgeTypeEnum.KAFKA.getType(); } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeDO.KafkaMQConfig config) throws Exception { + public void execute0(IotDeviceMessage message, IotDataBridgeKafkaMQConfig config) throws Exception { // 1. 获取或创建 KafkaTemplate KafkaTemplate kafkaTemplate = getProducer(config); @@ -47,7 +48,7 @@ public class IotKafkaMQDataBridgeExecute extends } @Override - protected KafkaTemplate initProducer(IotDataBridgeDO.KafkaMQConfig config) { + protected KafkaTemplate initProducer(IotDataBridgeKafkaMQConfig config) { // 1.1 构建生产者配置 Map props = new HashMap<>(); props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, config.getBootstrapServers()); @@ -82,7 +83,7 @@ public class IotKafkaMQDataBridgeExecute extends IotKafkaMQDataBridgeExecute action = new IotKafkaMQDataBridgeExecute(); // 2. 创建共享的配置 - IotDataBridgeDO.KafkaMQConfig config = new IotDataBridgeDO.KafkaMQConfig(); + IotDataBridgeKafkaMQConfig config = new IotDataBridgeKafkaMQConfig(); config.setBootstrapServers("127.0.0.1:9092"); config.setTopic("test-topic"); config.setSsl(false); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java index 5599144da..54485c091 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -1,7 +1,8 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeRabbitMQConfig; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -22,16 +23,16 @@ import java.time.LocalDateTime; @Component @Slf4j public class IotRabbitMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute { + AbstractCacheableDataBridgeExecute { @Override public Integer getType() { - return IotDataBridgTypeEnum.RABBITMQ.getType(); + return IotDataBridgeTypeEnum.RABBITMQ.getType(); } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeDO.RabbitMQConfig config) throws Exception { + public void execute0(IotDeviceMessage message, IotDataBridgeRabbitMQConfig config) throws Exception { // 1. 获取或创建 Channel Channel channel = getProducer(config); @@ -48,7 +49,7 @@ public class IotRabbitMQDataBridgeExecute extends @Override @SuppressWarnings("resource") - protected Channel initProducer(IotDataBridgeDO.RabbitMQConfig config) throws Exception { + protected Channel initProducer(IotDataBridgeRabbitMQConfig config) throws Exception { // 1. 创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); factory.setHost(config.getHost()); @@ -81,7 +82,7 @@ public class IotRabbitMQDataBridgeExecute extends IotRabbitMQDataBridgeExecute action = new IotRabbitMQDataBridgeExecute(); // 2. 创建共享的配置 - IotDataBridgeDO.RabbitMQConfig config = new IotDataBridgeDO.RabbitMQConfig(); + IotDataBridgeRabbitMQConfig config = new IotDataBridgeRabbitMQConfig(); config.setHost("localhost"); config.setPort(5672); config.setVirtualHost("/"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java index a20334f4f..5616c7e64 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java @@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeRedisStreamMQConfig; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -30,15 +31,15 @@ import java.time.LocalDateTime; @Component @Slf4j public class IotRedisStreamMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute> { + AbstractCacheableDataBridgeExecute> { @Override public Integer getType() { - return IotDataBridgTypeEnum.REDIS_STREAM.getType(); + return IotDataBridgeTypeEnum.REDIS_STREAM.getType(); } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeDO.RedisStreamMQConfig config) throws Exception { + public void execute0(IotDeviceMessage message, IotDataBridgeRedisStreamMQConfig config) throws Exception { // 1. 获取 RedisTemplate RedisTemplate redisTemplate = getProducer(config); @@ -50,7 +51,7 @@ public class IotRedisStreamMQDataBridgeExecute extends } @Override - protected RedisTemplate initProducer(IotDataBridgeDO.RedisStreamMQConfig config) { + protected RedisTemplate initProducer(IotDataBridgeRedisStreamMQConfig config) { // 1.1 创建 Redisson 配置 Config redissonConfig = new Config(); SingleServerConfig serverConfig = redissonConfig.useSingleServer() @@ -101,7 +102,7 @@ public class IotRedisStreamMQDataBridgeExecute extends IotRedisStreamMQDataBridgeExecute action = new IotRedisStreamMQDataBridgeExecute(); // 2. 创建共享的配置 - IotDataBridgeDO.RedisStreamMQConfig config = new IotDataBridgeDO.RedisStreamMQConfig(); + IotDataBridgeRedisStreamMQConfig config = new IotDataBridgeRedisStreamMQConfig(); config.setHost("127.0.0.1"); config.setPort(6379); config.setDatabase(0); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index 542d190ed..541bd181e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -1,7 +1,8 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeRocketMQConfig; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.producer.DefaultMQProducer; @@ -23,15 +24,15 @@ import java.time.LocalDateTime; @Component @Slf4j public class IotRocketMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute { + AbstractCacheableDataBridgeExecute { @Override public Integer getType() { - return IotDataBridgTypeEnum.ROCKETMQ.getType(); + return IotDataBridgeTypeEnum.ROCKETMQ.getType(); } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) throws Exception { + public void execute0(IotDeviceMessage message, IotDataBridgeRocketMQConfig config) throws Exception { // 1. 获取或创建 Producer DefaultMQProducer producer = getProducer(config); @@ -52,7 +53,7 @@ public class IotRocketMQDataBridgeExecute extends } @Override - protected DefaultMQProducer initProducer(IotDataBridgeDO.RocketMQConfig config) throws Exception { + protected DefaultMQProducer initProducer(IotDataBridgeRocketMQConfig config) throws Exception { DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); producer.setNamesrvAddr(config.getNameServer()); producer.start(); @@ -70,7 +71,7 @@ public class IotRocketMQDataBridgeExecute extends IotRocketMQDataBridgeExecute action = new IotRocketMQDataBridgeExecute(); // 2. 创建共享的配置 - IotDataBridgeDO.RocketMQConfig config = new IotDataBridgeDO.RocketMQConfig(); + IotDataBridgeRocketMQConfig config = new IotDataBridgeRocketMQConfig(); config.setNameServer("127.0.0.1:9876"); config.setGroup("test-group"); config.setTopic("test-topic"); From cdf316e7788a232d6d37db2b43aa7d87d360b5bf Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 9 Mar 2025 18:04:46 +0800 Subject: [PATCH 210/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=20config=20=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java | 1 - .../yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java index fc442d2b3..1fc47c0c0 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java @@ -18,5 +18,4 @@ public class DictTypeConstants { public static final String IOT_DATA_BRIDGE_DIRECTION_ENUM = "iot_data_bridge_direction_enum"; public static final String IOT_DATA_BRIDGE_TYPE_ENUM = "iot_data_bridge_type_enum"; - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index ef0a60eca..05493b916 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -16,7 +16,7 @@ import lombok.*; * * @author 芋道源码 */ -@TableName("iot_data_bridge") +@TableName(value = "iot_data_bridge", autoResultMap = true) @KeySequence("iot_data_bridge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) From 569d6514816e373c9fa2ec66295707a2b7a7c89e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 13 Mar 2025 08:17:31 +0800 Subject: [PATCH 211/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20device=20con?= =?UTF-8?q?fig=20=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../device/vo/device/IotDeviceRespVO.java | 3 +++ .../device/vo/device/IotDeviceSaveReqVO.java | 3 +++ .../dal/tdengine/IotDevicePropertyMapper.java | 1 - .../router/IotDeviceWebhookVertxHandler.java | 20 +++++++------------ yudao-server/pom.xml | 10 +++++----- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java index cc45c0280..8404ca922 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java @@ -83,6 +83,9 @@ public class IotDeviceRespVO { @ExcelProperty("认证类型(如一机一密、动态注册)") private String authType; + @Schema(description = "设备配置", example = "{\"abc\": \"efg\"}") + private String config; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") private LocalDateTime createTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java index 7bf0f33ee..b9ea9b99f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java @@ -38,4 +38,7 @@ public class IotDeviceSaveReqVO { @Schema(description = "网关设备 ID", example = "16380") private Long gatewayId; + @Schema(description = "设备配置", example = "{\"abc\": \"efg\"}") + private String config; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java index 955b38478..37a72e4b0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java @@ -32,7 +32,6 @@ public interface IotDevicePropertyMapper { default void alterProductPropertySTable(String productKey, List oldFields, List newFields) { - // TODO @芋艿:需要处理 device_key,重新发布的时候 oldFields.removeIf(field -> StrUtil.equalsAny(field.getField(), TDengineTableField.FIELD_TS, "report_time", "device_key")); List addFields = newFields.stream().filter( // 新增的字段 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java index a2499826f..31679fe05 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java @@ -17,9 +17,8 @@ import java.util.Collections; /** * IoT Emqx Webhook 事件处理的 Vert.x Handler - * EMQX - * Webhook + * + * EMQXWebhook * * @author haohao */ @@ -69,12 +68,11 @@ public class IotDeviceWebhookVertxHandler implements Handler { * @param username 用户名 */ private void handleClientConnected(String clientId, String username) { + // 解析产品标识和设备名称 if (StrUtil.isEmpty(username) || "undefined".equals(username)) { log.warn("[handleClientConnected][客户端连接事件,但用户名为空] clientId={}", clientId); return; } - - // 解析产品标识和设备名称 String[] parts = parseUsername(username); if (parts == null) { return; @@ -87,7 +85,6 @@ public class IotDeviceWebhookVertxHandler implements Handler { updateReqDTO.setState(IotDeviceStateEnum.ONLINE.getState()); updateReqDTO.setProcessId(IotPluginCommonUtils.getProcessId()); updateReqDTO.setReportTime(LocalDateTime.now()); - CommonResult result = deviceUpstreamApi.updateDeviceState(updateReqDTO); if (result.getCode() != 0 || !result.getData()) { log.error("[handleClientConnected][更新设备状态为在线失败] clientId={}, username={}, code={}, msg={}", @@ -104,12 +101,11 @@ public class IotDeviceWebhookVertxHandler implements Handler { * @param username 用户名 */ private void handleClientDisconnected(String clientId, String username) { + // 解析产品标识和设备名称 if (StrUtil.isEmpty(username) || "undefined".equals(username)) { log.warn("[handleClientDisconnected][客户端断开连接事件,但用户名为空] clientId={}", clientId); return; } - - // 解析产品标识和设备名称 String[] parts = parseUsername(username); if (parts == null) { return; @@ -122,7 +118,6 @@ public class IotDeviceWebhookVertxHandler implements Handler { offlineReqDTO.setState(IotDeviceStateEnum.OFFLINE.getState()); offlineReqDTO.setProcessId(IotPluginCommonUtils.getProcessId()); offlineReqDTO.setReportTime(LocalDateTime.now()); - CommonResult offlineResult = deviceUpstreamApi.updateDeviceState(offlineReqDTO); if (offlineResult.getCode() != 0 || !offlineResult.getData()) { log.error("[handleClientDisconnected][更新设备状态为离线失败] clientId={}, username={}, code={}, msg={}", @@ -136,19 +131,18 @@ public class IotDeviceWebhookVertxHandler implements Handler { * 解析用户名,格式为 deviceName&productKey * * @param username 用户名 - * @return 解析结果,[0]为deviceName,[1]为productKey,解析失败返回null + * @return 解析结果,[0] 为 deviceName,[1] 为productKey,解析失败返回 null */ private String[] parseUsername(String username) { if (StrUtil.isEmpty(username)) { return null; } - String[] parts = username.split("&"); if (parts.length != 2) { - log.warn("[parseUsername][用户名格式不正确,无法解析产品标识和设备名称] username={}", username); + log.warn("[parseUsername][用户名格式({})不正确,无法解析产品标识和设备名称]", username); return null; } - return parts; } + } \ No newline at end of file diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 492e31db5..17403fef8 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -46,11 +46,11 @@ - - - - - + + cn.iocoder.boot + yudao-module-bpm-biz + ${revision} + From 34453a3f70492f9dfbc8b8d70a458632321e6017 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 13 Mar 2025 08:30:27 +0800 Subject: [PATCH 212/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=95=B0=E6=8D=AE=E6=A1=A5?= =?UTF-8?q?=E6=A2=81=E7=9A=84=E7=BB=B4=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/enums/DictTypeConstants.java | 1 + .../admin/rule/IotDataBridgeController.java | 13 +++++++------ .../rule/vo/databridge/IotDataBridgePageReqVO.java | 2 ++ .../rule/vo/databridge/IotDataBridgeRespVO.java | 4 ++-- .../rule/vo/databridge/IotDataBridgeSaveReqVO.java | 5 +++-- ...onfig.java => IotDataBridgeAbstractConfig.java} | 2 +- .../databridge/config/IotDataBridgeHttpConfig.java | 2 +- .../config/IotDataBridgeKafkaMQConfig.java | 2 +- .../databridge/config/IotDataBridgeMqttConfig.java | 2 +- .../config/IotDataBridgeRabbitMQConfig.java | 2 +- .../config/IotDataBridgeRedisStreamMQConfig.java | 2 +- .../config/IotDataBridgeRocketMQConfig.java | 2 +- .../iot/dal/dataobject/rule/IotDataBridgeDO.java | 4 ++-- .../iot/service/rule/IotDataBridgeService.java | 14 +++++++------- .../AbstractCacheableDataBridgeExecute.java | 8 ++++---- .../action/databridge/IotDataBridgeExecute.java | 1 + .../databridge/IotRocketMQDataBridgeExecute.java | 1 + yudao-server/pom.xml | 1 + 18 files changed, 38 insertions(+), 30 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/{IotDataBridgeConfig.java => IotDataBridgeAbstractConfig.java} (95%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java index 1fc47c0c0..d8f0cc60d 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java @@ -15,6 +15,7 @@ public class DictTypeConstants { public static final String VALIDATE_TYPE = "iot_validate_type"; public static final String DEVICE_STATE = "iot_device_state"; + public static final String IOT_DATA_BRIDGE_DIRECTION_ENUM = "iot_data_bridge_direction_enum"; public static final String IOT_DATA_BRIDGE_TYPE_ENUM = "iot_data_bridge_type_enum"; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java index 2d2f8fb75..f6ba16123 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java @@ -37,14 +37,14 @@ public class IotDataBridgeController { private IotDataBridgeService dataBridgeService; @PostMapping("/create") - @Operation(summary = "创建IoT 数据桥梁") + @Operation(summary = "创建数据桥梁") @PreAuthorize("@ss.hasPermission('iot:data-bridge:create')") public CommonResult createDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO createReqVO) { return success(dataBridgeService.createDataBridge(createReqVO)); } @PutMapping("/update") - @Operation(summary = "更新IoT 数据桥梁") + @Operation(summary = "更新数据桥梁") @PreAuthorize("@ss.hasPermission('iot:data-bridge:update')") public CommonResult updateDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO updateReqVO) { dataBridgeService.updateDataBridge(updateReqVO); @@ -52,7 +52,7 @@ public class IotDataBridgeController { } @DeleteMapping("/delete") - @Operation(summary = "删除IoT 数据桥梁") + @Operation(summary = "删除数据桥梁") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('iot:data-bridge:delete')") public CommonResult deleteDataBridge(@RequestParam("id") Long id) { @@ -61,7 +61,7 @@ public class IotDataBridgeController { } @GetMapping("/get") - @Operation(summary = "获得IoT 数据桥梁") + @Operation(summary = "获得数据桥梁") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") public CommonResult getDataBridge(@RequestParam("id") Long id) { @@ -70,15 +70,16 @@ public class IotDataBridgeController { } @GetMapping("/page") - @Operation(summary = "获得IoT 数据桥梁分页") + @Operation(summary = "获得数据桥梁分页") @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") public CommonResult> getDataBridgePage(@Valid IotDataBridgePageReqVO pageReqVO) { PageResult pageResult = dataBridgeService.getDataBridgePage(pageReqVO); return success(BeanUtils.toBean(pageResult, IotDataBridgeRespVO.class)); } + // TODO @puhui999:不用导出哈。相关的 IotDataBridgeRespVO 里的导出也注释掉哈 @GetMapping("/export-excel") - @Operation(summary = "导出IoT 数据桥梁 Excel") + @Operation(summary = "导出数据桥梁 Excel") @PreAuthorize("@ss.hasPermission('iot:data-bridge:export')") @ApiAccessLog(operateType = EXPORT) public void exportDataBridgeExcel(@Valid IotDataBridgePageReqVO pageReqVO, diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java index 7da87be07..a3f8007c3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java @@ -20,6 +20,7 @@ public class IotDataBridgePageReqVO extends PageParam { @Schema(description = "桥梁名称", example = "赵六") private String name; + // TODO @puhui999:description、direction、type 不过滤哈 @Schema(description = "桥梁描述", example = "随便") private String description; @@ -36,4 +37,5 @@ public class IotDataBridgePageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java index 3e50dc4d5..a8faf40d6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeConfig; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -48,7 +48,7 @@ public class IotDataBridgeRespVO { @Schema(description = "桥梁配置") @ExcelProperty("桥梁配置") - private IotDataBridgeConfig config; + private IotDataBridgeAbstractConfig config; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java index 96620a1ca..37dc9b218 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeConfig; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -24,6 +24,7 @@ public class IotDataBridgeSaveReqVO { @NotNull(message = "桥梁状态不能为空") private Integer status; + // TODO @puhui999:枚举的校验 @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "桥梁方向不能为空") private Integer direction; @@ -34,6 +35,6 @@ public class IotDataBridgeSaveReqVO { @Schema(description = "桥梁配置") @NotNull(message = "桥梁配置不能为空") - private IotDataBridgeConfig config; + private IotDataBridgeAbstractConfig config; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java similarity index 95% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java index f37a51edb..06219f723 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java @@ -22,7 +22,7 @@ import lombok.Data; @JsonSubTypes.Type(value = IotDataBridgeRedisStreamMQConfig.class, name = "REDIS_STREAM"), @JsonSubTypes.Type(value = IotDataBridgeRocketMQConfig.class, name = "ROCKETMQ"), }) -public abstract class IotDataBridgeConfig { +public abstract class IotDataBridgeAbstractConfig { /** * 配置类型 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java index 69cdc71f7..9711cb6ec 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java @@ -10,7 +10,7 @@ import java.util.Map; * @author HUIHUI */ @Data -public class IotDataBridgeHttpConfig extends IotDataBridgeConfig { +public class IotDataBridgeHttpConfig extends IotDataBridgeAbstractConfig { /** * 请求 URL diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java index 3acd646f3..cbc37cd69 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java @@ -8,7 +8,7 @@ import lombok.Data; * @author HUIHUI */ @Data -public class IotDataBridgeKafkaMQConfig extends IotDataBridgeConfig { +public class IotDataBridgeKafkaMQConfig extends IotDataBridgeAbstractConfig { /** * Kafka 服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java index 0bf7067bc..c437898c2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java @@ -8,7 +8,7 @@ import lombok.Data; * @author HUIHUI */ @Data -public class IotDataBridgeMqttConfig extends IotDataBridgeConfig { +public class IotDataBridgeMqttConfig extends IotDataBridgeAbstractConfig { /** * MQTT 服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java index 29bf32897..40e72f14c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java @@ -8,7 +8,7 @@ import lombok.Data; * @author HUIHUI */ @Data -public class IotDataBridgeRabbitMQConfig extends IotDataBridgeConfig { +public class IotDataBridgeRabbitMQConfig extends IotDataBridgeAbstractConfig { /** * RabbitMQ 服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java index db7b2b2bc..288b772a0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java @@ -8,7 +8,7 @@ import lombok.Data; * @author HUIHUI */ @Data -public class IotDataBridgeRedisStreamMQConfig extends IotDataBridgeConfig { +public class IotDataBridgeRedisStreamMQConfig extends IotDataBridgeAbstractConfig { /** * Redis 服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java index e911461e4..791d36250 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java @@ -8,7 +8,7 @@ import lombok.Data; * @author HUIHUI */ @Data -public class IotDataBridgeRocketMQConfig extends IotDataBridgeConfig { +public class IotDataBridgeRocketMQConfig extends IotDataBridgeAbstractConfig { /** * RocketMQ 名称服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index 05493b916..488c451aa 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeConfig; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; @@ -63,6 +63,6 @@ public class IotDataBridgeDO extends BaseDO { * 桥梁配置 */ @TableField(typeHandler = JacksonTypeHandler.class) - private IotDataBridgeConfig config; + private IotDataBridgeAbstractConfig config; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java index f720a1d15..18069376b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java @@ -14,7 +14,7 @@ import jakarta.validation.Valid; public interface IotDataBridgeService { /** - * 创建IoT 数据桥梁 + * 创建数据桥梁 * * @param createReqVO 创建信息 * @return 编号 @@ -22,32 +22,32 @@ public interface IotDataBridgeService { Long createDataBridge(@Valid IotDataBridgeSaveReqVO createReqVO); /** - * 更新IoT 数据桥梁 + * 更新数据桥梁 * * @param updateReqVO 更新信息 */ void updateDataBridge(@Valid IotDataBridgeSaveReqVO updateReqVO); /** - * 删除IoT 数据桥梁 + * 删除数据桥梁 * * @param id 编号 */ void deleteDataBridge(Long id); /** - * 获得IoT 数据桥梁 + * 获得数据桥梁 * * @param id 编号 - * @return IoT 数据桥梁 + * @return 数据桥梁 */ IotDataBridgeDO getDataBridge(Long id); /** - * 获得IoT 数据桥梁分页 + * 获得数据桥梁分页 * * @param pageReqVO 分页查询 - * @return IoT 数据桥梁分页 + * @return 数据桥梁分页 */ PageResult getDataBridgePage(IotDataBridgePageReqVO pageReqVO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java index d26c2dd43..e7f84dd6c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import com.google.common.cache.CacheBuilder; @@ -56,6 +57,7 @@ public abstract class AbstractCacheableDataBridgeExecute imple } }) .build(new CacheLoader() { + @Override public Producer load(Config config) throws Exception { try { @@ -67,6 +69,7 @@ public abstract class AbstractCacheableDataBridgeExecute imple throw e; // 抛出异常,触发缓存加载失败机制 } } + }); /** @@ -98,12 +101,9 @@ public abstract class AbstractCacheableDataBridgeExecute imple @Override @SuppressWarnings({"unchecked"}) public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { - // 1.1 校验数据桥梁类型 - if (!getType().equals(dataBridge.getType())) { + if (ObjUtil.notEqual(message.getType(), getType())) { return; } - - // 1.2 执行对应的数据桥梁发送消息 try { execute0(message, (Config) dataBridge.getConfig()); } catch (Exception e) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java index ce3d0f193..1e8d939ec 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index 541bd181e..c3e729dda 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -66,6 +66,7 @@ public class IotRocketMQDataBridgeExecute extends } // TODO @芋艿:测试代码,后续清理 + // TODO @puhui999:搞到测试类里。 public static void main(String[] args) { // 1. 创建一个共享的实例 IotRocketMQDataBridgeExecute action = new IotRocketMQDataBridgeExecute(); diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 2c7708a51..f408ca3e5 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -115,6 +115,7 @@ ${revision} + org.apache.rocketmq rocketmq-spring-boot-starter From b87a5838424e4e091e2df22c74b69722d3adfd3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E7=8E=84=E7=A4=BC?= Date: Thu, 13 Mar 2025 22:16:45 +0800 Subject: [PATCH 213/228] =?UTF-8?q?refactor(iot):=20=E9=87=8D=E6=9E=84=20O?= =?UTF-8?q?TA=20=E5=8D=87=E7=BA=A7=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新错误码定义,调整 OTA 相关错误码的编号和描述 - 移除未使用的 IotOtaFirmwareCommonReqVO 类- 优化 IotOtaFirmwareCreateReqVO 和 IotOtaFirmwareUpdateReqVO 的结构 - 删除冗余的 IotOtaUpgradeRecordCreateReqBO 类 - 重构 IotOtaUpgradeRecordMapper 的查询方法 - 更新 IotOtaUpgradeRecordService 接口,简化升级记录创建方法 - 删除未使用的 IotOtaUpgradeRecordJob 类 - 优化 IotOtaUpgradeRecordController 的重试接口,使用 PUT 方法 --- .../module/iot/enums/ErrorCodeConstants.java | 17 ++- .../ota/IotOtaUpgradeRecordController.java | 3 +- .../ota/IotOtaUpgradeTaskController.java | 3 +- .../firmware/IotOtaFirmwareCommonReqVO.java | 27 ---- .../firmware/IotOtaFirmwareCreateReqVO.java | 64 ++------- .../firmware/IotOtaFirmwareUpdateReqVO.java | 17 ++- .../record/IotOtaUpgradeRecordPageReqVO.java | 26 ---- .../task/IotOtaUpgradeTaskSaveReqVO.java | 9 -- .../ota/IotOtaUpgradeRecordConvert.java | 24 ---- .../dataobject/ota/IotOtaUpgradeTaskDO.java | 9 -- .../mysql/ota/IotOtaUpgradeRecordMapper.java | 56 ++++---- .../iot/job/ota/IotOtaUpgradeRecordJob.java | 35 ----- .../iot/job/ota/IotOtaUpgradeTaskJob.java | 72 ---------- .../service/ota/IotOtaFirmwareService.java | 6 +- .../ota/IotOtaFirmwareServiceImpl.java | 23 ++- .../ota/IotOtaUpgradeRecordService.java | 24 +--- .../ota/IotOtaUpgradeRecordServiceImpl.java | 121 ++++++++-------- .../service/ota/IotOtaUpgradeTaskService.java | 6 +- .../ota/IotOtaUpgradeTaskServiceImpl.java | 134 ++++++------------ .../bo/IotOtaUpgradeRecordCreateReqBO.java | 79 ----------- .../bo/IotOtaUpgradeRecordUpdateReqBO.java | 46 ------ 21 files changed, 201 insertions(+), 600 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordCreateReqBO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordUpdateReqBO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 3d12c4b59..f9081e1fa 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -56,16 +56,15 @@ public interface ErrorCodeConstants { ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在"); ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复"); - // TODO @li:1_050_008_100,这样有点间隔? - ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_002, "升级任务不存在"); - ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_003, "升级任务名称重复"); - ErrorCode OTA_UPGRADE_TASK_PARAMS_INVALID = new ErrorCode(1_050_008_004, "升级任务参数无效"); - ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_005, "升级任务不能取消"); + ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在"); + ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "升级任务名称重复"); + ErrorCode OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY = new ErrorCode(1_050_008_102, "设备编号列表不能为空"); + ErrorCode OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY = new ErrorCode(1_050_008_103, "设备列表不能为空"); + ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_104, "升级任务不能取消"); - // TODO @li:1_050_008_200 - ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_006, "升级记录不存在"); - ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_007, "升级记录重复"); - ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_008, "升级记录不能重试"); + ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在"); + ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复"); + ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试"); // ========== MQTT 通信相关 1-050-009-000 ========== ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java index dcff39648..519d6b9ab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java @@ -64,8 +64,7 @@ public class IotOtaUpgradeRecordController { return success(BeanUtils.toBean(upgradeRecord, IotOtaUpgradeRecordRespVO.class)); } - // TODO @li:使用 Putmapping - @PostMapping("/retry") + @PutMapping("/retry") @Operation(summary = "重试升级记录") @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:retry')") @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java index 4f560d5b5..5486102e6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java @@ -44,11 +44,10 @@ public class IotOtaUpgradeTaskController { return success(true); } - // TODO @li:get 接口,不是 @RequestBody 哈 @GetMapping("/page") @Operation(summary = "获得升级任务分页") @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')") - public CommonResult> getUpgradeTaskPage(@Valid @RequestBody IotOtaUpgradeTaskPageReqVO pageReqVO) { + public CommonResult> getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO) { PageResult pageResult = upgradeTaskService.getUpgradeTaskPage(pageReqVO); return success(BeanUtils.toBean(pageResult, IotOtaUpgradeTaskRespVO.class)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java deleted file mode 100644 index 2799907ce..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCommonReqVO.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; - -import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; - -// TODO @li:因为 create 和 update 可以公用的字段比较少,建议不用 IotOtaFirmwareCommonReqVO -@Data -@Schema(description = "管理后台 - OTA固件信息 Request VO") -public class IotOtaFirmwareCommonReqVO { - - /** - * 固件名称 - */ - @NotEmpty(message = "固件名称不能为空") - @Schema(description = "固件名称", requiredMode = REQUIRED, example = "智能开关固件") - private String name; - - /** - * 固件描述 - */ - @Schema(description = "固件描述", example = "某品牌型号固件,测试用") - private String description; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java index b194cde77..98b99351d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java @@ -7,72 +7,32 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; -// TODO @li:中英文之间,有个空格。中文写作习惯哈。 -@Schema(description = "管理后台 - OTA固件创建 Request VO") +@Schema(description = "管理后台 - OTA 固件创建 Request VO") @Data -public class IotOtaFirmwareCreateReqVO extends IotOtaFirmwareCommonReqVO { +public class IotOtaFirmwareCreateReqVO { + + @Schema(description = "固件名称", requiredMode = REQUIRED, example = "智能开关固件") + @NotEmpty(message = "固件名称不能为空") + private String name; + + @Schema(description = "固件描述", example = "某品牌型号固件,测试用") + private String description; - // TODO @li:因为有了注解,注释可以不写哈 - // TODO @li:swagger 注解,写在 validator 注解之前,保持项目统一哈。 - /** - * 版本号 - */ - @NotEmpty(message = "版本号不能为空") @Schema(description = "版本号", requiredMode = REQUIRED, example = "1.0.0") + @NotEmpty(message = "版本号不能为空") private String version; - /** - * 产品编号 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} - */ - @NotNull(message = "产品编号不能为空") @Schema(description = "产品编号", requiredMode = REQUIRED, example = "1024") + @NotNull(message = "产品编号不能为空") private String productId; - // TODO @li:productId 即可,而 productKey 通过 productId 查询 - /** - * 产品标识 - *

- * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()} - */ - @NotEmpty(message = "产品标识不能为空") - @Schema(description = "产品标识", requiredMode = REQUIRED, example = "yudao") - private String productKey; - - /** - * 签名方式 - *

- * 例如说:MD5、SHA256 - */ @Schema(description = "签名方式", example = "MD5") private String signMethod; - // TODO @li:fileSign、fileSize 通过后端下载文件,计算出来。对前端屏蔽这个细节。 - - /** - * 固件文件签名 - */ - @Schema(description = "固件文件签名", example = "d41d8cd98f00b204e9800998ecf8427e") - private String fileSign; - - /** - * 固件文件大小 - */ - @NotNull(message = "固件文件大小不能为空") - @Schema(description = "固件文件大小(单位:byte)", example = "1024") - private Long fileSize; - - /** - * 固件文件 URL - */ - @NotEmpty(message = "固件文件 URL 不能为空") @Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn/yudao-firmware.zip") + @NotEmpty(message = "固件文件 URL 不能为空") private String fileUrl; - /** - * 自定义信息,建议使用 JSON 格式 - */ @Schema(description = "自定义信息,建议使用 JSON 格式", example = "{\"key1\":\"value1\",\"key2\":\"value2\"}") private String information; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java index eacbfd2dd..88b7cde5c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java @@ -1,20 +1,25 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; -@Data @Schema(description = "管理后台 - OTA固件更新 Request VO") -public class IotOtaFirmwareUpdateReqVO extends IotOtaFirmwareCommonReqVO { +@Data +public class IotOtaFirmwareUpdateReqVO { - /** - * 固件编号 - */ - @NotNull(message = "固件编号不能为空") @Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024") + @NotNull(message = "固件编号不能为空") private Long id; + @Schema(description = "固件名称", requiredMode = REQUIRED, example = "智能开关固件") + @NotEmpty(message = "固件名称不能为空") + private String name; + + @Schema(description = "固件描述", example = "某品牌型号固件,测试用") + private String description; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java index 6e083a332..e28024085 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java @@ -11,32 +11,6 @@ import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Schema(description = "管理后台 - OTA升级记录分页 Request VO") public class IotOtaUpgradeRecordPageReqVO extends PageParam { - // TODO @li:使用 IotOtaUpgradeRecordStatusEnum 枚举哈 - /** - * 待处理状态 - */ - public static final Integer PENDING = 0; - /** - * 已推送状态 - */ - public static final Integer PUSHED = 10; - /** - * 正在升级状态 - */ - public static final Integer UPGRADING = 20; - /** - * 升级成功状态 - */ - public static final Integer SUCCESS = 30; - /** - * 升级失败状态 - */ - public static final Integer FAILURE = 40; - /** - * 升级已取消状态 - */ - public static final Integer CANCELED = 50; - /** * 升级任务编号字段。 *

diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java index 7cb25299f..e2fbd8efe 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java @@ -57,13 +57,4 @@ public class IotOtaUpgradeTaskSaveReqVO { @Schema(description = "选中的设备编号数组", requiredMode = REQUIRED, example = "[1,2,3,4]") private List deviceIds; - // TODO @li:通过 deviceIds 查询 deviceNames,前端不传递哈 - /** - * 选中的设备名字数组 - *

- * 关联 {@link IotDeviceDO#getDeviceName()} - */ - @Schema(description = "选中的设备名字数组", requiredMode = REQUIRED, example = "[设备1,设备2,设备3,设备4]") - private List deviceNames; - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java index 2da9315f7..fe5279b3c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java @@ -1,35 +1,11 @@ package cn.iocoder.yudao.module.iot.convert.ota; -import cn.hutool.core.convert.Convert; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; -import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordCreateReqBO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; -import java.util.List; - @Mapper public interface IotOtaUpgradeRecordConvert { IotOtaUpgradeRecordConvert INSTANCE = Mappers.getMapper(IotOtaUpgradeRecordConvert.class); - // TODO @li:一般情况下,这种 convert 直接写 service 就好啦。不用特别写一个哈 - default List convertBOList(IotOtaUpgradeTaskDO upgradeTask, IotOtaFirmwareDO firmware, List deviceList) { - return deviceList.stream().map(device -> { - IotOtaUpgradeRecordCreateReqBO createReqBO = new IotOtaUpgradeRecordCreateReqBO(); - createReqBO.setFirmwareId(firmware.getId()); - createReqBO.setTaskId(upgradeTask.getId()); - createReqBO.setProductKey(device.getProductKey()); - createReqBO.setDeviceName(device.getDeviceName()); - createReqBO.setDeviceId(Convert.toStr(device.getId())); - createReqBO.setFromFirmwareId(Convert.toLong(device.getFirmwareId())); - createReqBO.setStatus(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); - createReqBO.setProgress(0); - return createReqBO; - }).toList(); - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java index e98e6c15c..6cc80e2b7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java @@ -71,13 +71,4 @@ public class IotOtaUpgradeTaskDO extends BaseDO { @TableField(typeHandler = JacksonTypeHandler.class) private List deviceIds; - // TODO @li:这个通过查询,不用冗余 - /** - * 选中的设备名字数组 - *

- * 关联 {@link IotDeviceDO#getDeviceName()} - */ - @TableField(typeHandler = JacksonTypeHandler.class) - private List deviceNames; - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java index b48131c61..46ac87084 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -8,8 +8,10 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.List; +import java.util.Map; /** * OTA 升级记录 Mapper @@ -36,36 +38,42 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX() - .eqIfPresent(IotOtaUpgradeRecordDO::getTaskId, taskId) - .likeIfPresent(IotOtaUpgradeRecordDO::getDeviceId, deviceName) - .eqIfPresent(IotOtaUpgradeRecordDO::getStatus, status)); - } + @Select("select count(case when status = 0 then 1 else 0) as `0` " + + "count(case when status = 1 then 1 else 0) as `1` " + + "count(case when status = 2 then 1 else 0) as `2` " + + "count(case when status = 3 then 1 else 0) as `3` " + + "count(case when status = 4 then 1 else 0) as `4` " + + "count(case when status = 5 then 1 else 0) as `5` " + + "from iot_ota_upgrade_record " + + "where task_id = #{taskId} " + + "and device_name like concat('%', #{deviceName}, '%') " + + "and status = #{status}") + List> selectOtaUpgradeRecordCount(@Param("taskId") Long taskId, + @Param("deviceName") String deviceName); /** - * 获取OTA升级记录的统计信息 + * 根据固件ID查询OTA升级记录的状态统计信息。 + * 该函数通过SQL查询统计不同状态(0到5)的记录数量,并返回一个包含统计结果的Map列表。 * - * @param firmwareId 固件ID,用于筛选特定固件的升级记录 - * @param status 状态,用于筛选特定状态的升级记录 - * @return 返回符合条件的OTA升级记录的统计信息 + * @param firmwareId 固件ID,用于筛选特定固件的OTA升级记录。 + * @return 返回一个Map列表,每个Map包含不同状态(0到5)的记录数量。 */ - default Long getOtaUpgradeRecordStatistics(@Param("firmwareId") Long firmwareId, - @Param("status") Integer status) { - return selectCount(new LambdaQueryWrapperX() - .eqIfPresent(IotOtaUpgradeRecordDO::getFirmwareId, firmwareId) - .eqIfPresent(IotOtaUpgradeRecordDO::getStatus, status)); - } - + @Select("select count(case when status = 0 then 1 else 0) as `0` " + + "count(case when status = 1 then 1 else 0) as `1` " + + "count(case when status = 2 then 1 else 0) as `2` " + + "count(case when status = 3 then 1 else 0) as `3` " + + "count(case when status = 4 then 1 else 0) as `4` " + + "count(case when status = 5 then 1 else 0) as `5` " + + "from iot_ota_upgrade_record " + + "where firmware_id = #{firmwareId}") + List> selectOtaUpgradeRecordStatistics(Long firmwareId); /** * 根据分页查询条件获取IOT OTA升级记录的分页结果 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java deleted file mode 100644 index 86c44db8b..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeRecordJob.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.iot.job.ota; - -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; -import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; -import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Component; - -import java.util.List; - -@Component -public class IotOtaUpgradeRecordJob implements JobHandler { - - @Resource - private IotOtaUpgradeRecordService upgradeRecordService; - - @Override - @TenantJob - public String execute(String param) throws Exception { - // 1. 查询待处理的升级记录 - List upgradeRecords = upgradeRecordService - .getUpgradeRecordListByState(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); - - // TODO @芋艿 2.执行升级动作 - // TODO @li:应该是逐条 push,逐条更新。不用批量哈 - - // 3. 最终,更新升级记录状态 - List ids = upgradeRecords.stream().map(IotOtaUpgradeRecordDO::getId).toList(); - upgradeRecordService.updateUpgradeRecordStatus(ids, IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus()); - return ""; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java deleted file mode 100644 index 5465161f9..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/ota/IotOtaUpgradeTaskJob.java +++ /dev/null @@ -1,72 +0,0 @@ -package cn.iocoder.yudao.module.iot.job.ota; - -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; -import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum; -import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService; -import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeTaskService; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.util.List; - -// TODO @li:也不用通过 job 去统计。可以通过 record update status 后,主动去更新 task 的状态。 -@Slf4j -@Component -public class IotOtaUpgradeTaskJob implements JobHandler { - - @Resource - private IotOtaUpgradeTaskService upgradeTaskService; - @Resource - private IotOtaUpgradeRecordService upgradeRecordService; - - @Override - @TenantJob - public String execute(String param) throws Exception { - // 1.这个任务主要是为了检查并更新升级任务的状态 - List upgradeTasks = upgradeTaskService - .getUpgradeTaskByState(IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus()); - // 2.遍历并且确定升级任务的状态 - upgradeTasks.forEach(this::checkUpgradeTaskState); - // TODO @芋艿: 其他的一些业务逻辑 - return ""; - } - - private void checkUpgradeTaskState(IotOtaUpgradeTaskDO upgradeTask) { - // 1.查询任务所有的升级记录 - List upgradeRecords = - upgradeRecordService.getUpgradeRecordListByTaskId(upgradeTask.getId()); - if (upgradeRecords.stream().anyMatch(upgradeRecord -> - ObjectUtils.equalsAny(upgradeRecord.getStatus(), - IotOtaUpgradeRecordStatusEnum.PENDING.getStatus(), - IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus(), - IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus()))) { - // 如果存在正在升级的升级记录,则升级任务的状态为进行中 - log.debug("升级任务 {} 状态为进行中", upgradeTask.getId()); - } else if (upgradeRecords.stream().allMatch(upgradeRecord -> - ObjectUtils.equalsAny(upgradeRecord.getStatus(), - IotOtaUpgradeRecordStatusEnum.SUCCESS.getStatus()))) { - // 如果全部升级成功,则升级任务的状态为已完成 - upgradeTaskService.updateUpgradeTaskStatus(upgradeTask.getId(), - IotOtaUpgradeTaskStatusEnum.COMPLETED.getStatus()); - } else if (upgradeRecords.stream().noneMatch(upgradeRecord -> - ObjectUtils.equalsAny(upgradeRecord.getStatus(), - IotOtaUpgradeRecordStatusEnum.PENDING.getStatus(), - IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus(), - IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus())) && - upgradeRecords.stream().anyMatch(upgradeRecord -> - ObjectUtils.equalsAny(upgradeRecord.getStatus(), - IotOtaUpgradeRecordStatusEnum.FAILURE.getStatus(), - IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()))) { - // 如果全部升级完毕,但是存在升级失败或者取消的升级记录,则升级任务的状态为失败 - upgradeTaskService.updateUpgradeTaskStatus(upgradeTask.getId(), - IotOtaUpgradeTaskStatusEnum.INCOMPLETE.getStatus()); - } - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java index 67e14ce6a..124c803b3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java @@ -7,10 +7,10 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import jakarta.validation.Valid; -// TODO @li:类、方法注释有点冗余,可以参考别的模块哈 /** - * OTA固件管理服务接口 - * 提供OTA固件的创建、更新和查询等功能 + * OTA 固件管理 Service + * + * @author Shelly Chan */ public interface IotOtaFirmwareService { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java index 56a830b91..d66ce0e4f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java @@ -1,14 +1,19 @@ package cn.iocoder.yudao.module.iot.service.ota; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaFirmwareMapper; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -26,23 +31,28 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @Resource private IotOtaFirmwareMapper otaFirmwareMapper; + @Lazy + @Resource + private IotProductService productService; @Override public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) { // 1. 校验固件产品 + 版本号不能重复 - // TODO @li:需要考虑设备也存在 validateProductAndVersionDuplicate(saveReqVO.getProductId(), saveReqVO.getVersion()); - - // 2.转化数据格式,准备存储到数据库中 + // 2.1.转化数据格式,准备存储到数据库中 IotOtaFirmwareDO firmware = BeanUtils.toBean(saveReqVO, IotOtaFirmwareDO.class); + // 2.2.查询ProductKey + IotProductDO product = productService.getProduct(Convert.toLong(firmware.getProductId())); + firmware.setProductKey(Objects.requireNonNull(product).getProductKey()); + // TODO @芋艿: 附件、附件签名等属性的计算 + otaFirmwareMapper.insert(firmware); return firmware.getId(); } @Override public void updateOtaFirmware(IotOtaFirmwareUpdateReqVO updateReqVO) { - // TODO @li:如果序号只有一个,直接写 1. 更好哈 - // 1.1. 校验存在 + // 1. 校验存在 validateFirmwareExists(updateReqVO.getId()); // 2. 更新数据 @@ -84,8 +94,7 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { // 查询数据库中是否存在具有相同产品ID和版本号的固件信息 List list = otaFirmwareMapper.selectByProductIdAndVersion(productId, version); // 如果查询结果非空且不为null,则抛出异常,提示固件信息已存在 - // TODO @li:使用 isNotEmpty 这种 方法,简化 - if (Objects.nonNull(list) && !list.isEmpty()) { + if (CollUtil.isNotEmpty(list)) { throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java index ea5de4a42..86bc18b84 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; -import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordCreateReqBO; -import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordUpdateReqBO; import jakarta.validation.Valid; import java.util.List; @@ -16,25 +14,15 @@ import java.util.Map; */ public interface IotOtaUpgradeRecordService { - // TODO @createOtaUpgradeRecordBatch 哈,需要补充方法里,缺少 Ota 关键字的 - /** - * 批量创建物联网OTA升级记录 - *

- * 该函数用于处理一组物联网OTA升级记录的创建请求,并将这些记录批量保存到系统中。 + * 批量创建OTA升级记录。 + * 该函数用于为指定的设备列表、固件ID和升级任务ID创建OTA升级记录。 * - * @param createList 包含多个物联网OTA升级记录创建请求的列表,每个请求对象都经过校验(@Valid注解确保) - * 列表中的每个元素都是IotOtaUpgradeRecordCreateReqBO类型的对象,表示一个独立的升级记录创建请求。 + * @param deviceIds 设备ID列表,表示需要升级的设备集合。 + * @param firmwareId 固件ID,表示要升级到的固件版本。 + * @param upgradeTaskId 升级任务ID,表示此次升级任务的唯一标识。 */ - void createUpgradeRecordBatch(@Valid List createList); - - // TODO @li:尽量避免写比较大的通用 update。而是根据场景提供,这样才能收敛 - /** - * 更新现有的 OTA 升级记录 - * - * @param updateReqBO 包含更新升级记录所需信息的请求对象,必须经过验证。 - */ - void updateUpgradeRecord(@Valid IotOtaUpgradeRecordUpdateReqBO updateReqBO); + void createOtaUpgradeRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId); /** * 获取OTA升级记录的数量统计。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java index 5738f5763..c04750e00 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java @@ -1,25 +1,31 @@ package cn.iocoder.yudao.module.iot.service.ota; +import cn.hutool.core.convert.Convert; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeRecordMapper; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; -import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordCreateReqBO; -import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordUpdateReqBO; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum.CANCELED; @Slf4j @Service @@ -28,27 +34,40 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Resource private IotOtaUpgradeRecordMapper upgradeRecordMapper; + @Lazy + @Resource + private IotDeviceService deviceService; + @Lazy + @Resource + private IotOtaFirmwareService firmwareService; + @Lazy + @Resource + private IotOtaUpgradeTaskService upgradeTaskService; @Override - public void createUpgradeRecordBatch(List createList) { - // 1. 批量校验参数信息 - createList.forEach(saveBO -> validateUpgradeRecordDuplicate(saveBO.getFirmwareId(), saveBO.getTaskId(), saveBO.getDeviceId())); + public void createOtaUpgradeRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId) { + // 1.校验升级记录信息是否存在,并且已经取消的任务可以重新开始 + deviceIds.forEach(deviceId -> validateUpgradeRecordDuplicate(firmwareId, upgradeTaskId, String.valueOf(deviceId))); + // 2.初始化OTA升级记录列表信息 + IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(upgradeTaskId); + IotOtaFirmwareDO firmware = firmwareService.getOtaFirmware(firmwareId); + List deviceList = deviceService.getDeviceListByIdList(deviceIds); + List upgradeRecordList = deviceList.stream().map(device -> { + IotOtaUpgradeRecordDO upgradeRecord = new IotOtaUpgradeRecordDO(); + upgradeRecord.setFirmwareId(firmware.getId()); + upgradeRecord.setTaskId(upgradeTask.getId()); + upgradeRecord.setProductKey(device.getProductKey()); + upgradeRecord.setDeviceName(device.getDeviceName()); + upgradeRecord.setDeviceId(Convert.toStr(device.getId())); + upgradeRecord.setFromFirmwareId(Convert.toLong(device.getFirmwareId())); + upgradeRecord.setStatus(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); + upgradeRecord.setProgress(0); + return upgradeRecord; + }).toList(); + // 3.保存数据 + upgradeRecordMapper.insertBatch(upgradeRecordList); + // TODO @芋艿:在这里需要处理推送升级任务的逻辑 - // 2. 将数据批量存储到数据库里 - List upgradeRecords = BeanUtils.toBean(createList, IotOtaUpgradeRecordDO.class); - upgradeRecordMapper.insertBatch(upgradeRecords); - } - - @Override - @Transactional - public void updateUpgradeRecord(IotOtaUpgradeRecordUpdateReqBO updateReqBO) { - // 1. 校验升级记录信息是否存在 - validateUpgradeRecordExists(updateReqBO.getId()); - - // 2. 将数据转化成数据库存储的格式 - IotOtaUpgradeRecordDO updateRecord = BeanUtils.toBean(updateReqBO, IotOtaUpgradeRecordDO.class); - upgradeRecordMapper.updateById(updateRecord); - // TODO @芋艿: 更新升级记录触发的其他Action } /** @@ -62,21 +81,14 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Transactional public Map getOtaUpgradeRecordCount(IotOtaUpgradeRecordPageReqVO pageReqVO) { // 分别查询不同状态的OTA升级记录数量 - // TODO @li: 通过 groupby 统计下; - Long pending = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); - Long pushed = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus()); - Long upgrading = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus()); - Long success = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.SUCCESS.getStatus()); - Long failure = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.FAILURE.getStatus()); - Long canceled = upgradeRecordMapper.getOtaUpgradeRecordCount(pageReqVO.getTaskId(), pageReqVO.getDeviceName(), IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()); - // 将各状态的数量封装到Map中返回 - // TODO @li:使用 MapUtil,因为 Map.of 是 jdk9 才有,后续不好同步到 master 的 jdk8; - return Map.of(IotOtaUpgradeRecordPageReqVO.PENDING, pending, - IotOtaUpgradeRecordPageReqVO.PUSHED, pushed, - IotOtaUpgradeRecordPageReqVO.UPGRADING, upgrading, - IotOtaUpgradeRecordPageReqVO.SUCCESS, success, - IotOtaUpgradeRecordPageReqVO.FAILURE, failure, - IotOtaUpgradeRecordPageReqVO.CANCELED, canceled); + List> upgradeRecordCountList = upgradeRecordMapper.selectOtaUpgradeRecordCount( + pageReqVO.getTaskId(), pageReqVO.getDeviceName()); + Map upgradeRecordCountMap = ObjectUtils.defaultIfNull(upgradeRecordCountList.get(0)); + Objects.requireNonNull(upgradeRecordCountMap); + return upgradeRecordCountMap.entrySet().stream().collect(Collectors.toMap( + entry -> Convert.toInt(entry.getKey()), + entry -> Convert.toLong(entry.getValue()) + )); } /** @@ -90,20 +102,13 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Transactional public Map getOtaUpgradeRecordStatistics(Long firmwareId) { // 查询并统计不同状态的OTA升级记录数量 - // TODO @li: 通过 groupby 统计下; - Long pending = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); - Long pushed = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus()); - Long upgrading = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus()); - Long success = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.SUCCESS.getStatus()); - Long failure = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.FAILURE.getStatus()); - Long canceled = upgradeRecordMapper.getOtaUpgradeRecordStatistics(firmwareId, IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus()); - // 将统计结果封装为Map并返回 - return Map.of(IotOtaUpgradeRecordPageReqVO.PENDING, pending, - IotOtaUpgradeRecordPageReqVO.PUSHED, pushed, - IotOtaUpgradeRecordPageReqVO.UPGRADING, upgrading, - IotOtaUpgradeRecordPageReqVO.SUCCESS, success, - IotOtaUpgradeRecordPageReqVO.FAILURE, failure, - IotOtaUpgradeRecordPageReqVO.CANCELED, canceled); + List> upgradeRecordStatisticsList = upgradeRecordMapper.selectOtaUpgradeRecordStatistics(firmwareId); + Map upgradeRecordStatisticsMap = ObjectUtils.defaultIfNull(upgradeRecordStatisticsList.get(0)); + Objects.requireNonNull(upgradeRecordStatisticsMap); + return upgradeRecordStatisticsMap.entrySet().stream().collect(Collectors.toMap( + entry -> Convert.toInt(entry.getKey()), + entry -> Convert.toLong(entry.getValue()) + )); } @Override @@ -117,8 +122,6 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic upgradeRecordMapper.updateById(new IotOtaUpgradeRecordDO() .setId(upgradeRecord.getId()).setProgress(0) .setStatus(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus())); - // TODO @芋艿: 重试升级记录触发的其他Action - // TODO 如果一个升级记录被取消或者已经执行失败,重试成功,是否会对升级任务的状态有影响? } @Override @@ -135,7 +138,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic public void cancelUpgradeRecordByTaskId(Long taskId) { // 暂定只有待推送的升级记录可以取消 upgradeRecordMapper.updateUpgradeRecordStatusByTaskIdAndStatus( - IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus(), taskId, + CANCELED.getStatus(), taskId, IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); } @@ -173,21 +176,23 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic } /** - * 验证固件升级记录是否存在。 + * 校验固件升级记录是否重复。 *

- * 该函数通过给定的固件ID、任务ID和设备ID查询升级记录,如果查询结果为空,则抛出异常。 + * 该函数用于检查给定的固件ID、任务ID和设备ID是否已经存在未取消的升级记录。 + * 如果存在未取消的记录,则抛出异常,提示升级记录重复。 * * @param firmwareId 固件ID,用于标识特定的固件版本 * @param taskId 任务ID,用于标识特定的升级任务 * @param deviceId 设备ID,用于标识特定的设备 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出OTA_UPGRADE_RECORD_NOT_EXISTS异常 */ private void validateUpgradeRecordDuplicate(Long firmwareId, Long taskId, String deviceId) { // 根据条件查询升级记录 IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); - // 如果查询结果为空,抛出异常 + // 如果查询到升级记录且状态不是已取消,则抛出异常 if (upgradeRecord != null) { - throw exception(OTA_UPGRADE_RECORD_DUPLICATE); + if (!CANCELED.getStatus().equals(upgradeRecord.getStatus())) { + throw exception(OTA_UPGRADE_RECORD_DUPLICATE); + } } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java index 1f5476df1..a2a810bf0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java @@ -8,10 +8,10 @@ import jakarta.validation.Valid; import java.util.List; -// TODO @li:类、方法注释有点冗余,可以参考别的模块哈 /** - * IoT OTA升级任务服务接口 - * 提供OTA升级任务的创建、取消和查询功能 + * IoT OTA升级任务 Service 接口 + * + * @author Shelly Chan */ public interface IotOtaUpgradeTaskService { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java index cef1448e9..d20f27e8c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java @@ -3,9 +3,9 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; -import cn.iocoder.yudao.module.iot.convert.ota.IotOtaUpgradeRecordConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; @@ -13,7 +13,6 @@ import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeTaskMapper; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.ota.bo.IotOtaUpgradeRecordCreateReqBO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; @@ -23,6 +22,7 @@ import org.springframework.validation.annotation.Validated; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @@ -52,21 +52,13 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { validateFirmwareTaskDuplicate(createReqVO.getFirmwareId(), createReqVO.getName()); // 1.2 校验固件信息是否存在 IotOtaFirmwareDO firmware = firmwareService.validateFirmwareExists(createReqVO.getFirmwareId()); - // 1.3 校验升级范围=2(指定设备时),deviceIds deviceNames不为空并且长度相等 - // TODO @li:deviceNames 应该后端查询 - validateScopeAndDevice(createReqVO.getScope(), createReqVO.getDeviceIds(), createReqVO.getDeviceNames()); - // TODO @li:如果全部范围,但是没设备可以升级,需要报错 - + // 1.3 补全设备范围信息,并且校验是否又设备可以升级,如果没有设备可以升级,则报错 + validateScopeAndDevice(createReqVO.getScope(), createReqVO.getDeviceIds(), firmware.getProductId()); // 2. 保存 OTA 升级任务信息到数据库 - IotOtaUpgradeTaskDO upgradeTask = initUpgradeTask(createReqVO, firmware.getProductId()); + IotOtaUpgradeTaskDO upgradeTask = initOtaUpgradeTask(createReqVO, firmware.getProductId()); upgradeTaskMapper.insert(upgradeTask); - // 3. 生成设备升级记录信息并存储,等待定时任务轮询 - List upgradeRecordList = initUpgradeRecordList( - upgradeTask, firmware, createReqVO.getDeviceIds()); - // TODO @li:只需要传递 deviceIds、firewareId、剩余的 upgradeRecordService 里面自己处理;这样,后续 record 加字段,都不需要透传太多;解耦 - upgradeRecordService.createUpgradeRecordBatch(upgradeRecordList); - // TODO @芋艿: 创建任务触发的其他Action + upgradeRecordService.createOtaUpgradeRecordBatch(upgradeTask.getDeviceIds(), firmware.getId(), upgradeTask.getId()); return upgradeTask.getId(); } @@ -76,16 +68,17 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { // 1.1 校验升级任务是否存在 IotOtaUpgradeTaskDO upgradeTask = validateUpgradeTaskExists(id); // 1.2 校验升级任务是否可以取消 - // TODO @li:这种一次性的,可以不考虑拆分方法 - validateUpgradeTaskCanCancel(upgradeTask); - + // 检查升级任务的状态是否为进行中,只有此状态下的任务才允许取消 + if (!Objects.equals(upgradeTask.getStatus(), IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus())) { + // 只有进行中的任务才可以取消 + throw exception(OTA_UPGRADE_TASK_CANNOT_CANCEL); + } // 2. 更新 OTA 升级任务状态为已取消 upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder() .id(id).status(IotOtaUpgradeTaskStatusEnum.CANCELED.getStatus()) .build()); // 3. 更新 OTA 升级记录状态为已取消 upgradeRecordService.cancelUpgradeRecordByTaskId(id); - // TODO @芋艿: 取消任务触发的其他Action } @Override @@ -131,19 +124,27 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { } /** - * 验证升级任务的范围和设备参数是否有效 - * 当选择特定设备进行升级时,确保提供的设备ID和设备名称列表有效且对应 + * 验证升级任务的范围和设备列表的有效性。 + *

+ * 根据升级任务的范围(scope),验证设备列表(deviceIds)或产品ID(productId)是否有效。 + * 如果范围是“选择设备”(SELECT),则必须提供设备列表;如果范围是“所有设备”(ALL),则必须根据产品ID获取设备列表,并确保列表不为空。 * - * @param scope 升级任务的范围,表示是选择特定设备还是其他范围 - * @param deviceIds 设备ID列表,用于标识参与升级的设备 - * @param deviceNames 设备名称列表,与设备ID列表对应 + * @param scope 升级任务的范围,参考 IotOtaUpgradeTaskScopeEnum 枚举值 + * @param deviceIds 设备ID列表,当范围为“选择设备”时,该列表不能为空 + * @param productId 产品ID,当范围为“所有设备”时,用于获取设备列表 + * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,抛出相应的异常 */ - private void validateScopeAndDevice(Integer scope, List deviceIds, List deviceNames) { - // 当升级任务范围为选择特定设备时 + private void validateScopeAndDevice(Integer scope, List deviceIds, String productId) { + // 验证范围为“选择设备”时,设备列表不能为空 if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { - // 检查设备ID列表和设备名称列表是否为空或长度不一致,若不符合要求,则抛出异常 - if (CollUtil.isEmpty(deviceIds) || CollUtil.isEmpty(deviceNames) || deviceIds.size() != deviceNames.size()) { - throw exception(OTA_UPGRADE_TASK_PARAMS_INVALID); + if (CollUtil.isEmpty(deviceIds)) { + throw exception(OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY); + } + } else if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.ALL.getScope())) { + // 验证范围为“所有设备”时,根据产品ID获取的设备列表不能为空 + List deviceList = deviceService.getDeviceListByProductId(Convert.toLong(productId)); + if (CollUtil.isEmpty(deviceList)) { + throw exception(OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY); } } } @@ -166,25 +167,6 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { return upgradeTask; } - /** - * 验证升级任务是否可以被取消 - *

- * 此方法旨在确保只有当升级任务处于进行中状态时,才可以执行取消操作 - * 它通过比较任务的当前状态与预定义的进行中状态来判断是否允许取消操作 - * 如果任务状态不符合条件,则抛出异常,表明该任务无法取消 - * - * @param upgradeTask 待验证的升级任务对象,包含任务的详细信息,如状态等 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 如果任务状态不是进行中,则抛出此异常,表明任务无法取消 - */ - private void validateUpgradeTaskCanCancel(IotOtaUpgradeTaskDO upgradeTask) { - // 检查升级任务的状态是否为进行中,只有此状态下的任务才允许取消 - if (!Objects.equals(upgradeTask.getStatus(), IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus())) { - // 只有进行中的任务才可以取消 - throw exception(OTA_UPGRADE_TASK_CANNOT_CANCEL); - } - } - - // TODO @li:一次性,不复用的,可以直接写在对应的逻辑里; /** * 初始化升级任务 *

@@ -195,55 +177,29 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { * @param createReqVO 升级任务保存请求对象,包含创建升级任务所需的信息 * @return 返回初始化后的升级任务对象 */ - private IotOtaUpgradeTaskDO initUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, String productId) { - // 配置各项参数 - IotOtaUpgradeTaskDO upgradeTask = IotOtaUpgradeTaskDO.builder() - // TODO @li:不用每个占一行。最好相同类型的,放在一行里; - .name(createReqVO.getName()) - .description(createReqVO.getDescription()) - .firmwareId(createReqVO.getFirmwareId()) - .scope(createReqVO.getScope()) - .deviceIds(createReqVO.getDeviceIds()) - .deviceNames(createReqVO.getDeviceNames()) - .deviceCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds()))) - .status(IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus()) - .build(); + private IotOtaUpgradeTaskDO initOtaUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, String productId) { + // 将请求参数转换为升级任务对象 + IotOtaUpgradeTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaUpgradeTaskDO.class); + // 初始化的时候,设置设备数量和状态 + upgradeTask.setDeviceCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds()))) + .setStatus(IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus()); // 如果选择全选,则需要查询设备数量 if (Objects.equals(createReqVO.getScope(), IotOtaUpgradeTaskScopeEnum.ALL.getScope())) { // 根据产品ID查询设备数量 - Long deviceCount = deviceService.getDeviceCountByProductId(Convert.toLong(productId)); + List deviceList = deviceService.getDeviceListByProductId(Convert.toLong(productId)); // 设置升级任务的设备数量 - upgradeTask.setDeviceCount(deviceCount); + upgradeTask.setDeviceCount((long) deviceList.size()); + upgradeTask.setDeviceIds( + deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList())); + upgradeTask.setDeviceNames( + deviceList.stream().map(IotDeviceDO::getDeviceName).collect(Collectors.toList())); + } else if (Objects.equals(createReqVO.getScope(), IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { + List deviceList = deviceService.getDeviceListByIdList(createReqVO.getDeviceIds()); + upgradeTask.setDeviceNames( + deviceList.stream().map(IotDeviceDO::getDeviceName).collect(Collectors.toList())); } // 返回初始化后的升级任务对象 return upgradeTask; } - /** - * 初始化升级记录列表 - *

- * 根据升级任务的范围(选择设备或按产品ID)获取设备列表,并将其转换为升级记录请求对象列表。 - * - * @param upgradeTask 升级任务对象,包含升级任务的相关信息 - * @param firmware 固件对象,包含固件的相关信息 - * @param deviceIds 设备ID列表,仅在升级任务范围为选择设备时使用 - * @return 升级记录请求对象列表,包含每个设备的升级记录信息 - */ - private List initUpgradeRecordList( - IotOtaUpgradeTaskDO upgradeTask, IotOtaFirmwareDO firmware, List deviceIds) { - // TODO @li:需要考虑,如果创建多个任务,相互之间不能重复; - // 1)指定设备的时候,进行校验;2)如果是全部,则过滤其它已经发起的;;;;;另外,需要排除掉 cancel 的哈。因为 cancal 之后,还可以发起 - // 根据升级任务的范围确定设备列表 - List deviceList; - if (Objects.equals(upgradeTask.getScope(), IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { - // 如果升级任务范围为选择设备,则根据设备ID列表获取设备信息 - deviceList = deviceService.getDeviceListByIdList(deviceIds); - } else { - // 如果升级任务范围为按产品ID,则根据固件的产品ID获取设备信息 - deviceList = deviceService.getDeviceListByProductId(Convert.toLong(firmware.getProductId())); - } - // 将升级任务、固件和设备列表转换为升级记录请求对象列表 - return IotOtaUpgradeRecordConvert.INSTANCE.convertBOList(upgradeTask, firmware, deviceList); - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordCreateReqBO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordCreateReqBO.java deleted file mode 100644 index 2567be529..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordCreateReqBO.java +++ /dev/null @@ -1,79 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.ota.bo; - -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -import java.time.LocalDateTime; - -@Data -public class IotOtaUpgradeRecordCreateReqBO { - - /** - * 固件编号 - *

- * 关联 {@link IotOtaFirmwareDO#getId()} - */ - @NotNull(message = "固件编号不能为空") - private Long firmwareId; - /** - * 任务编号 - *

- * 关联 {@link IotOtaUpgradeTaskDO#getId()} - */ - @NotNull(message = "任务编号不能为空") - private Long taskId; - /** - * 产品标识 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} - */ - private String productKey; - /** - * 设备名称 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} - */ - private String deviceName; - /** - * 设备编号 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} - */ - @NotNull(message = "设备编号不能为空") - private String deviceId; - /** - * 来源的固件编号 - *

- * 关联 {@link IotDeviceDO#getFirmwareId()} - */ - private Long fromFirmwareId; - /** - * 升级状态 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum} - */ - private Integer status; - /** - * 升级进度,百分比 - */ - private Integer progress; - /** - * 升级进度描述 - *

- * 注意,只记录设备最后一次的升级进度描述 - * 如果想看历史记录,可以查看 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO} 设备日志 - */ - private String description; - /** - * 升级开始时间 - */ - private LocalDateTime startTime; - /** - * 升级结束时间 - */ - private LocalDateTime endTime; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordUpdateReqBO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordUpdateReqBO.java deleted file mode 100644 index ac73aa884..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/bo/IotOtaUpgradeRecordUpdateReqBO.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.ota.bo; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; -import jakarta.validation.constraints.NotNull; -import lombok.Data; -import org.hibernate.validator.constraints.Range; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -// TODO @li:这个类,貌似没用? -@Data -public class IotOtaUpgradeRecordUpdateReqBO { - - /** - * 升级记录编号 - */ - @NotNull(message = "升级记录编号不能为空") - private Long id; - /** - * 升级状态 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum} - */ - @InEnum(IotOtaUpgradeRecordStatusEnum.class) - private Integer status; - /** - * 升级进度,百分比 - */ - @Range(min = 0, max = 100, message = "升级进度必须介于 0-100 之间") - private Integer progress; - /** - * 升级开始时间 - */ - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime startTime; - /** - * 升级结束时间 - */ - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime endTime; - -} From 37c725c1a3d7970fdd8f9c35b02a12439725a092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E7=8E=84=E7=A4=BC?= Date: Thu, 13 Mar 2025 22:23:28 +0800 Subject: [PATCH 214/228] =?UTF-8?q?refactor(iot):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=E4=BB=BB=E5=8A=A1=E4=B8=AD=E7=9A=84=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=90=8D=E7=A7=B0=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除了创建升级任务时设置设备名称的代码逻辑 - 优化了升级任务初始化过程,减少了不必要的设备名称查询和设置操作 --- .../iot/service/ota/IotOtaUpgradeTaskServiceImpl.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java index d20f27e8c..ca74481ff 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java @@ -191,12 +191,6 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { upgradeTask.setDeviceCount((long) deviceList.size()); upgradeTask.setDeviceIds( deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList())); - upgradeTask.setDeviceNames( - deviceList.stream().map(IotDeviceDO::getDeviceName).collect(Collectors.toList())); - } else if (Objects.equals(createReqVO.getScope(), IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { - List deviceList = deviceService.getDeviceListByIdList(createReqVO.getDeviceIds()); - upgradeTask.setDeviceNames( - deviceList.stream().map(IotDeviceDO::getDeviceName).collect(Collectors.toList())); } // 返回初始化后的升级任务对象 return upgradeTask; From 966357b44e4db079d2db207254148e62463c035c Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 14 Mar 2025 17:34:16 +0800 Subject: [PATCH 215/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81=E6=8A=BD=E7=A6=BB=E5=88=B0?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/IotDataBridgeAbstractConfig.java | 12 +- .../databridge/IotDataBridgeExecute.java | 1 - .../IotKafkaMQDataBridgeExecute.java | 36 ---- .../IotRabbitMQDataBridgeExecute.java | 40 ----- .../IotRedisStreamMQDataBridgeExecute.java | 39 +---- .../IotRocketMQDataBridgeExecute.java | 37 ---- .../databridge/IotDataBridgeExecuteTest.java | 159 ++++++++++++++++++ yudao-server/pom.xml | 25 ++- 8 files changed, 178 insertions(+), 171 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java index 06219f723..550550d19 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java @@ -15,12 +15,12 @@ import lombok.Data; @Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true) @JsonSubTypes({ - @JsonSubTypes.Type(value = IotDataBridgeHttpConfig.class, name = "HTTP"), - @JsonSubTypes.Type(value = IotDataBridgeKafkaMQConfig.class, name = "KAFKA"), - @JsonSubTypes.Type(value = IotDataBridgeMqttConfig.class, name = "MQTT"), - @JsonSubTypes.Type(value = IotDataBridgeRabbitMQConfig.class, name = "RABBITMQ"), - @JsonSubTypes.Type(value = IotDataBridgeRedisStreamMQConfig.class, name = "REDIS_STREAM"), - @JsonSubTypes.Type(value = IotDataBridgeRocketMQConfig.class, name = "ROCKETMQ"), + @JsonSubTypes.Type(value = IotDataBridgeHttpConfig.class, name = "1"), + @JsonSubTypes.Type(value = IotDataBridgeMqttConfig.class, name = "10"), + @JsonSubTypes.Type(value = IotDataBridgeRedisStreamMQConfig.class, name = "21"), + @JsonSubTypes.Type(value = IotDataBridgeRocketMQConfig.class, name = "30"), + @JsonSubTypes.Type(value = IotDataBridgeRabbitMQConfig.class, name = "31"), + @JsonSubTypes.Type(value = IotDataBridgeKafkaMQConfig.class, name = "32"), }) public abstract class IotDataBridgeAbstractConfig { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java index 1e8d939ec..ce3d0f193 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index 3b7f99bf4..5674c7d60 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeKafkaMQConfig; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import lombok.extern.slf4j.Slf4j; @@ -13,7 +12,6 @@ import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; import java.time.Duration; -import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -77,38 +75,4 @@ public class IotKafkaMQDataBridgeExecute extends producer.destroy(); } - // TODO @芋艿:测试代码,后续清理 - public static void main(String[] args) { - // 1. 创建一个共享的实例 - IotKafkaMQDataBridgeExecute action = new IotKafkaMQDataBridgeExecute(); - - // 2. 创建共享的配置 - IotDataBridgeKafkaMQConfig config = new IotDataBridgeKafkaMQConfig(); - config.setBootstrapServers("127.0.0.1:9092"); - config.setTopic("test-topic"); - config.setSsl(false); - config.setUsername(null); - config.setPassword(null); - - // 3. 创建共享的消息 - IotDeviceMessage message = IotDeviceMessage.builder() - .requestId("TEST-001") - .productKey("testProduct") - .deviceName("testDevice") - .deviceKey("testDeviceKey") - .type("property") - .identifier("temperature") - .data("{\"value\": 60}") - .reportTime(LocalDateTime.now()) - .tenantId(1L) - .build(); - - // 4. 执行两次测试,验证缓存 - log.info("[main][第一次执行,应该会创建新的 producer]"); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - - log.info("[main][第二次执行,应该会复用缓存的 producer]"); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java index 54485c091..efe08b1fc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRabbitMQDataBridgeExecute.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeRabbitMQConfig; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import com.rabbitmq.client.Channel; @@ -12,7 +11,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets; -import java.time.LocalDateTime; /** * RabbitMQ 的 {@link IotDataBridgeExecute} 实现类 @@ -76,42 +74,4 @@ public class IotRabbitMQDataBridgeExecute extends } } - // TODO @芋艿:测试代码,后续清理 - public static void main(String[] args) { - // 1. 创建一个共享的实例 - IotRabbitMQDataBridgeExecute action = new IotRabbitMQDataBridgeExecute(); - - // 2. 创建共享的配置 - IotDataBridgeRabbitMQConfig config = new IotDataBridgeRabbitMQConfig(); - config.setHost("localhost"); - config.setPort(5672); - config.setVirtualHost("/"); - config.setUsername("admin"); - config.setPassword("123456"); - config.setExchange("test-exchange"); - config.setRoutingKey("test-key"); - config.setQueue("test-queue"); - - // 3. 创建共享的消息 - IotDeviceMessage message = IotDeviceMessage.builder() - .requestId("TEST-001") - .productKey("testProduct") - .deviceName("testDevice") - .deviceKey("testDeviceKey") - .type("property") - .identifier("temperature") - .data("{\"value\": 60}") - .reportTime(LocalDateTime.now()) - .tenantId(1L) - .build(); - - // 4. 执行两次测试,验证缓存 - // 4. 执行两次测试,验证缓存 - log.info("[main][第一次执行,应该会创建新的 producer]"); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - - log.info("[main][第二次执行,应该会复用缓存的 producer]"); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java index 5616c7e64..2aac76619 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRedisStreamMQDataBridgeExecute.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeRedisStreamMQConfig; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import com.fasterxml.jackson.databind.ObjectMapper; @@ -21,8 +20,6 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.stereotype.Component; -import java.time.LocalDateTime; - /** * Redis Stream MQ 的 {@link IotDataBridgeExecute} 实现类 * @@ -96,38 +93,4 @@ public class IotRedisStreamMQDataBridgeExecute extends return json; } - // TODO @芋艿:测试代码,后续清理 - public static void main(String[] args) { - // 1. 创建一个共享的实例 - IotRedisStreamMQDataBridgeExecute action = new IotRedisStreamMQDataBridgeExecute(); - - // 2. 创建共享的配置 - IotDataBridgeRedisStreamMQConfig config = new IotDataBridgeRedisStreamMQConfig(); - config.setHost("127.0.0.1"); - config.setPort(6379); - config.setDatabase(0); - config.setPassword("123456"); - config.setTopic("test-stream"); - - // 3. 创建共享的消息 - IotDeviceMessage message = IotDeviceMessage.builder() - .requestId("TEST-001") - .productKey("testProduct") - .deviceName("testDevice") - .deviceKey("testDeviceKey") - .type("property") - .identifier("temperature") - .data("{\"value\": 60}") - .reportTime(LocalDateTime.now()) - .tenantId(1L) - .build(); - - // 4. 执行两次测试,验证缓存 - log.info("[main][第一次执行,应该会创建新的 producer]"); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - - log.info("[main][第二次执行,应该会复用缓存的 producer]"); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - } - -} \ No newline at end of file +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java index c3e729dda..d3ac77227 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeRocketMQConfig; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import lombok.extern.slf4j.Slf4j; @@ -13,8 +12,6 @@ import org.apache.rocketmq.remoting.common.RemotingHelper; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.stereotype.Component; -import java.time.LocalDateTime; - /** * RocketMQ 的 {@link IotDataBridgeExecute} 实现类 * @@ -65,38 +62,4 @@ public class IotRocketMQDataBridgeExecute extends producer.shutdown(); } - // TODO @芋艿:测试代码,后续清理 - // TODO @puhui999:搞到测试类里。 - public static void main(String[] args) { - // 1. 创建一个共享的实例 - IotRocketMQDataBridgeExecute action = new IotRocketMQDataBridgeExecute(); - - // 2. 创建共享的配置 - IotDataBridgeRocketMQConfig config = new IotDataBridgeRocketMQConfig(); - config.setNameServer("127.0.0.1:9876"); - config.setGroup("test-group"); - config.setTopic("test-topic"); - config.setTags("test-tag"); - - // 3. 创建共享的消息 - IotDeviceMessage message = IotDeviceMessage.builder() - .requestId("TEST-001") - .productKey("testProduct") - .deviceName("testDevice") - .deviceKey("testDeviceKey") - .type("property") - .identifier("temperature") - .data("{\"value\": 60}") - .reportTime(LocalDateTime.now()) - .tenantId(1L) - .build(); - - // 4. 执行两次测试,验证缓存 - log.info("[main][第一次执行,应该会创建新的 producer]"); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - - log.info("[main][第二次执行,应该会复用缓存的 producer]"); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java new file mode 100644 index 000000000..03ea33d68 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java @@ -0,0 +1,159 @@ +package cn.iocoder.yudao.module.iot.service.rule.action.databridge; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import java.time.LocalDateTime; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; + +/** + * {@link IotDataBridgeExecute} 实现类的测试 + * + * @author HUIHUI + */ +@Disabled // 默认禁用,需要手动启用测试 +@Slf4j +public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { + + private IotDeviceMessage message; + + @Mock + private RestTemplate restTemplate; + + @InjectMocks + private IotHttpDataBridgeExecute httpDataBridgeExecute; + + @BeforeEach + public void setUp() { + // 创建共享的测试消息 + message = IotDeviceMessage.builder() + .requestId("TEST-001") + .productKey("testProduct") + .deviceName("testDevice") + .deviceKey("testDeviceKey") + .type("property") + .identifier("temperature") + .data("{\"value\": 60}") + .reportTime(LocalDateTime.now()) + .tenantId(1L) + .build(); + + // 配置 RestTemplate mock 返回成功响应 + Mockito.when(restTemplate.exchange(anyString(), any(HttpMethod.class), any(), any(Class.class))) + .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); + } + + @Test + public void testKafkaMQDataBridge() { + // 1. 创建执行器实例 + IotKafkaMQDataBridgeExecute action = new IotKafkaMQDataBridgeExecute(); + + // 2. 创建配置 + IotDataBridgeKafkaMQConfig config = new IotDataBridgeKafkaMQConfig(); + config.setBootstrapServers("127.0.0.1:9092"); + config.setTopic("test-topic"); + config.setSsl(false); + config.setUsername(null); + config.setPassword(null); + + // 3. 执行两次测试,验证缓存 + log.info("[testKafkaMQDataBridge][第一次执行,应该会创建新的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + + log.info("[testKafkaMQDataBridge][第二次执行,应该会复用缓存的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + } + + @Test + public void testRabbitMQDataBridge() { + // 1. 创建执行器实例 + IotRabbitMQDataBridgeExecute action = new IotRabbitMQDataBridgeExecute(); + + // 2. 创建配置 + IotDataBridgeRabbitMQConfig config = new IotDataBridgeRabbitMQConfig(); + config.setHost("localhost"); + config.setPort(5672); + config.setVirtualHost("/"); + config.setUsername("admin"); + config.setPassword("123456"); + config.setExchange("test-exchange"); + config.setRoutingKey("test-key"); + config.setQueue("test-queue"); + + // 3. 执行两次测试,验证缓存 + log.info("[testRabbitMQDataBridge][第一次执行,应该会创建新的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + + log.info("[testRabbitMQDataBridge][第二次执行,应该会复用缓存的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + } + + @Test + public void testRedisStreamMQDataBridge() { + // 1. 创建执行器实例 + IotRedisStreamMQDataBridgeExecute action = new IotRedisStreamMQDataBridgeExecute(); + + // 2. 创建配置 + IotDataBridgeRedisStreamMQConfig config = new IotDataBridgeRedisStreamMQConfig(); + config.setHost("127.0.0.1"); + config.setPort(6379); + config.setDatabase(0); + config.setPassword("123456"); + config.setTopic("test-stream"); + + // 3. 执行两次测试,验证缓存 + log.info("[testRedisStreamMQDataBridge][第一次执行,应该会创建新的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + + log.info("[testRedisStreamMQDataBridge][第二次执行,应该会复用缓存的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + } + + @Test + public void testRocketMQDataBridge() { + // 1. 创建执行器实例 + IotRocketMQDataBridgeExecute action = new IotRocketMQDataBridgeExecute(); + + // 2. 创建配置 + IotDataBridgeRocketMQConfig config = new IotDataBridgeRocketMQConfig(); + config.setNameServer("127.0.0.1:9876"); + config.setGroup("test-group"); + config.setTopic("test-topic"); + config.setTags("test-tag"); + + // 3. 执行两次测试,验证缓存 + log.info("[testRocketMQDataBridge][第一次执行,应该会创建新的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + + log.info("[testRocketMQDataBridge][第二次执行,应该会复用缓存的 producer]"); + action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + } + + @Test + public void testHttpDataBridge() throws Exception { + // 创建配置 + IotDataBridgeHttpConfig config = new IotDataBridgeHttpConfig(); + config.setUrl("https://doc.iocoder.cn/"); + config.setMethod(HttpMethod.GET.name()); + + // 执行测试 + log.info("[testHttpDataBridge][执行HTTP数据桥接测试]"); + httpDataBridgeExecute.execute(message, new IotDataBridgeDO().setType(httpDataBridgeExecute.getType()).setConfig(config)); + } + +} diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index f408ca3e5..0251e7b64 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -115,19 +115,18 @@ ${revision} - - - org.apache.rocketmq - rocketmq-spring-boot-starter - - - org.springframework.kafka - spring-kafka - - - org.springframework.boot - spring-boot-starter-amqp - + + + + + + + + + + + + From 3756830b9c672f2a035b6aa0a29f2a8b1fbb6cac Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 14 Mar 2025 17:40:19 +0800 Subject: [PATCH 216/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/rule/IotDataBridgeController.java | 22 ------------------- .../vo/databridge/IotDataBridgePageReqVO.java | 11 ---------- .../vo/databridge/IotDataBridgeRespVO.java | 18 --------------- .../vo/databridge/IotDataBridgeSaveReqVO.java | 8 ++++++- .../dal/dataobject/rule/IotDataBridgeDO.java | 3 ++- 5 files changed, 9 insertions(+), 53 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java index f6ba16123..95e50a4a2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java @@ -1,11 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule; -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeRespVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; @@ -15,16 +12,11 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.io.IOException; -import java.util.List; - -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - IoT 数据桥梁") @@ -77,18 +69,4 @@ public class IotDataBridgeController { return success(BeanUtils.toBean(pageResult, IotDataBridgeRespVO.class)); } - // TODO @puhui999:不用导出哈。相关的 IotDataBridgeRespVO 里的导出也注释掉哈 - @GetMapping("/export-excel") - @Operation(summary = "导出数据桥梁 Excel") - @PreAuthorize("@ss.hasPermission('iot:data-bridge:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportDataBridgeExcel(@Valid IotDataBridgePageReqVO pageReqVO, - HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = dataBridgeService.getDataBridgePage(pageReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "IoT 数据桥梁.xls", "数据", IotDataBridgeRespVO.class, - BeanUtils.toBean(list, IotDataBridgeRespVO.class)); - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java index a3f8007c3..401f796f6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java @@ -20,22 +20,11 @@ public class IotDataBridgePageReqVO extends PageParam { @Schema(description = "桥梁名称", example = "赵六") private String name; - // TODO @puhui999:description、direction、type 不过滤哈 - @Schema(description = "桥梁描述", example = "随便") - private String description; - @Schema(description = "桥梁状态", example = "2") private Integer status; - @Schema(description = "桥梁方向") - private Integer direction; - - @Schema(description = "桥梁类型", example = "1") - private Integer type; - @Schema(description = "创建时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java index a8faf40d6..1db10a762 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java @@ -1,57 +1,39 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; -import static cn.iocoder.yudao.module.iot.enums.DictTypeConstants.IOT_DATA_BRIDGE_DIRECTION_ENUM; -import static cn.iocoder.yudao.module.iot.enums.DictTypeConstants.IOT_DATA_BRIDGE_TYPE_ENUM; -import static cn.iocoder.yudao.module.system.enums.DictTypeConstants.COMMON_STATUS; - @Schema(description = "管理后台 - IoT 数据桥梁 Response VO") @Data @ExcelIgnoreUnannotated public class IotDataBridgeRespVO { @Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564") - @ExcelProperty("桥梁编号") private Long id; @Schema(description = "桥梁名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") - @ExcelProperty("桥梁名称") private String name; @Schema(description = "桥梁描述", example = "随便") - @ExcelProperty("桥梁描述") private String description; @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @ExcelProperty(value = "桥梁状态", converter = DictConvert.class) - @DictFormat(COMMON_STATUS) private Integer status; @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty(value = "桥梁方向", converter = DictConvert.class) - @DictFormat(IOT_DATA_BRIDGE_DIRECTION_ENUM) private Integer direction; @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty(value = "桥梁类型", converter = DictConvert.class) - @DictFormat(IOT_DATA_BRIDGE_TYPE_ENUM) private Integer type; @Schema(description = "桥梁配置") - @ExcelProperty("桥梁配置") private IotDataBridgeAbstractConfig config; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") private LocalDateTime createTime; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java index 37dc9b218..8441701af 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java @@ -1,6 +1,10 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -22,15 +26,17 @@ public class IotDataBridgeSaveReqVO { @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @NotNull(message = "桥梁状态不能为空") + @InEnum(CommonStatusEnum.class) private Integer status; - // TODO @puhui999:枚举的校验 @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "桥梁方向不能为空") + @InEnum(IotDataBridgeDirectionEnum.class) private Integer direction; @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "桥梁类型不能为空") + @InEnum(IotDataBridgeTypeEnum.class) private Integer type; @Schema(description = "桥梁配置") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index 488c451aa..5697007b3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum; @@ -42,7 +43,7 @@ public class IotDataBridgeDO extends BaseDO { /** * 桥梁状态 * - * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + * 枚举 {@link CommonStatusEnum} */ private Integer status; /** From acd32f7b4eef7ad0a9ae711f85a03c27ed763501 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 14 Mar 2025 17:41:12 +0800 Subject: [PATCH 217/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT:=20=E6=95=B0=E6=8D=AE=E6=A1=A5=E6=A2=81?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java index 1609aec34..303579116 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java @@ -18,10 +18,7 @@ public interface IotDataBridgeMapper extends BaseMapperX { default PageResult selectPage(IotDataBridgePageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(IotDataBridgeDO::getName, reqVO.getName()) - .likeIfPresent(IotDataBridgeDO::getDescription, reqVO.getDescription()) .eqIfPresent(IotDataBridgeDO::getStatus, reqVO.getStatus()) - .eqIfPresent(IotDataBridgeDO::getDirection, reqVO.getDirection()) - .eqIfPresent(IotDataBridgeDO::getType, reqVO.getType()) .betweenIfPresent(IotDataBridgeDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(IotDataBridgeDO::getId)); } From 348c138749cbdc3a6dd874098ec1a1a46b2216e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 15 Mar 2025 00:26:44 +0800 Subject: [PATCH 218/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT=EF=BC=9A=E5=BC=95=E5=85=A5=20IotStandardR?= =?UTF-8?q?esponse=20=E5=AE=9E=E4=BD=93=E7=B1=BB=EF=BC=8C=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E5=A4=84=E7=90=86=E5=99=A8=E7=9A=84=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=EF=BC=8C=E4=BC=98=E5=8C=96=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotDeviceConfigSetVertxHandler.java | 23 ++++- .../IotDeviceOtaUpgradeVertxHandler.java | 23 ++++- .../IotDevicePropertyGetVertxHandler.java | 23 ++++- .../IotDevicePropertySetVertxHandler.java | 23 ++++- .../IotDeviceServiceInvokeVertxHandler.java | 27 +++++- .../common/pojo/IotStandardResponse.java | 94 +++++++++++++++++++ .../common/util/IotPluginCommonUtils.java | 49 ++++++---- .../router/IotDeviceAuthVertxHandler.java | 16 +++- .../router/IotDeviceMqttMessageHandler.java | 64 +++++++++---- .../router/IotDeviceWebhookVertxHandler.java | 12 ++- .../IotDeviceEventReportVertxHandler.java | 70 ++++++++++---- .../IotDevicePropertyReportVertxHandler.java | 82 ++++++++++++---- 12 files changed, 415 insertions(+), 91 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java index 5051965b2..6d2b3b5ba 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; @@ -25,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC public class IotDeviceConfigSetVertxHandler implements Handler { public static final String PATH = "/sys/:productKey/:deviceName/thing/service/config/set"; + public static final String METHOD = "thing.service.config.set"; private final IotDeviceDownstreamHandler deviceDownstreamHandler; @@ -44,17 +46,32 @@ public class IotDeviceConfigSetVertxHandler implements Handler { .setConfig(config); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + // 使用IotStandardResponse实体类返回错误 + IotStandardResponse errorResponse = IotStandardResponse.error( + null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); return; } // 2. 调用处理器 try { CommonResult result = deviceDownstreamHandler.setDeviceConfig(reqDTO); - IotPluginCommonUtils.writeJson(routingContext, result); + + // 使用IotStandardResponse实体类返回结果 + IotStandardResponse response; + if (result.isSuccess()) { + response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); + } else { + response = IotStandardResponse.error( + reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); + } + IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 配置设置异常]", reqDTO, e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + // 使用IotStandardResponse实体类返回错误 + IotStandardResponse errorResponse = IotStandardResponse.error( + reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java index 0d52dad49..888677d8b 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceOtaUpgradeReqDTO; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; @@ -23,6 +24,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC public class IotDeviceOtaUpgradeVertxHandler implements Handler { public static final String PATH = "/ota/:productKey/:deviceName/upgrade"; + public static final String METHOD = "ota.device.upgrade"; private final IotDeviceDownstreamHandler deviceDownstreamHandler; @@ -49,17 +51,32 @@ public class IotDeviceOtaUpgradeVertxHandler implements Handler .setInformation(information); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + // 使用IotStandardResponse实体类返回错误 + IotStandardResponse errorResponse = IotStandardResponse.error( + null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); return; } // 2. 调用处理器 try { CommonResult result = deviceDownstreamHandler.upgradeDeviceOta(reqDTO); - IotPluginCommonUtils.writeJson(routingContext, result); + + // 使用IotStandardResponse实体类返回结果 + IotStandardResponse response; + if (result.isSuccess()) { + response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); + } else { + response = IotStandardResponse.error( + reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); + } + IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) OTA 升级异常]", reqDTO, e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + // 使用IotStandardResponse实体类返回错误 + IotStandardResponse errorResponse = IotStandardResponse.error( + reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); } } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java index 2e99a1b62..dc2a8acfe 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; @@ -25,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC public class IotDevicePropertyGetVertxHandler implements Handler { public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/get"; + public static final String METHOD = "thing.service.property.get"; private final IotDeviceDownstreamHandler deviceDownstreamHandler; @@ -44,17 +46,32 @@ public class IotDevicePropertyGetVertxHandler implements Handler .setIdentifiers(identifiers); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + // 使用IotStandardResponse实体类返回错误 + IotStandardResponse errorResponse = IotStandardResponse.error( + null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); return; } // 2. 调用处理器 try { CommonResult result = deviceDownstreamHandler.getDeviceProperty(reqDTO); - IotPluginCommonUtils.writeJson(routingContext, result); + + // 使用IotStandardResponse实体类返回结果 + IotStandardResponse response; + if (result.isSuccess()) { + response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); + } else { + response = IotStandardResponse.error( + reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); + } + IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 属性获取异常]", reqDTO, e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + // 使用IotStandardResponse实体类返回错误 + IotStandardResponse errorResponse = IotStandardResponse.error( + reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java index ddcebccff..4f0afdccf 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; @@ -25,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC public class IotDevicePropertySetVertxHandler implements Handler { public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/set"; + public static final String METHOD = "thing.service.property.set"; private final IotDeviceDownstreamHandler deviceDownstreamHandler; @@ -44,17 +46,32 @@ public class IotDevicePropertySetVertxHandler implements Handler .setProperties(properties); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + // 使用IotStandardResponse实体类返回错误 + IotStandardResponse errorResponse = IotStandardResponse.error( + null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); return; } // 2. 调用处理器 try { CommonResult result = deviceDownstreamHandler.setDeviceProperty(reqDTO); - IotPluginCommonUtils.writeJson(routingContext, result); + + // 使用IotStandardResponse实体类返回结果 + IotStandardResponse response; + if (result.isSuccess()) { + response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); + } else { + response = IotStandardResponse.error( + reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); + } + IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 属性设置异常]", reqDTO, e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + // 使用IotStandardResponse实体类返回错误 + IotStandardResponse errorResponse = IotStandardResponse.error( + reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java index c4fd2e504..3a52f212c 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; @@ -25,6 +26,8 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC public class IotDeviceServiceInvokeVertxHandler implements Handler { public static final String PATH = "/sys/:productKey/:deviceName/thing/service/:identifier"; + public static final String METHOD_PREFIX = "thing.service."; + public static final String METHOD_SUFFIX = ""; private final IotDeviceDownstreamHandler deviceDownstreamHandler; @@ -45,17 +48,35 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler result = deviceDownstreamHandler.invokeDeviceService(reqDTO); - IotPluginCommonUtils.writeJson(routingContext, result); + + // 使用IotStandardResponse实体类返回结果 + String method = METHOD_PREFIX + reqDTO.getIdentifier() + METHOD_SUFFIX; + IotStandardResponse response; + if (result.isSuccess()) { + response = IotStandardResponse.success(reqDTO.getRequestId(), method, result.getData()); + } else { + response = IotStandardResponse.error( + reqDTO.getRequestId(), method, result.getCode(), result.getMsg()); + } + IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 服务调用异常]", reqDTO, e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + // 使用IotStandardResponse实体类返回错误 + String method = METHOD_PREFIX + reqDTO.getIdentifier() + METHOD_SUFFIX; + IotStandardResponse errorResponse = IotStandardResponse.error( + reqDTO.getRequestId(), method, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java new file mode 100644 index 000000000..a006f3a6a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.iot.plugin.common.pojo; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * IoT 标准协议响应实体类 + *

+ * 用于统一 MQTT 和 HTTP 的响应格式 + * + * @author haohao + */ +@Data +@Accessors(chain = true) +public class IotStandardResponse { + + /** + * 消息ID + */ + private String id; + + /** + * 状态码 + */ + private Integer code; + + /** + * 响应数据 + */ + private Object data; + + /** + * 响应消息 + */ + private String message; + + /** + * 方法名 + */ + private String method; + + /** + * 协议版本 + */ + private String version; + + /** + * 创建成功响应 + * + * @param id 消息ID + * @param method 方法名 + * @return 成功响应 + */ + public static IotStandardResponse success(String id, String method) { + return success(id, method, null); + } + + /** + * 创建成功响应 + * + * @param id 消息ID + * @param method 方法名 + * @param data 响应数据 + * @return 成功响应 + */ + public static IotStandardResponse success(String id, String method, Object data) { + return new IotStandardResponse() + .setId(id) + .setCode(200) + .setData(data) + .setMessage("success") + .setMethod(method) + .setVersion("1.0"); + } + + /** + * 创建错误响应 + * + * @param id 消息ID + * @param method 方法名 + * @param code 错误码 + * @param message 错误消息 + * @return 错误响应 + */ + public static IotStandardResponse error(String id, String method, Integer code, String message) { + return new IotStandardResponse() + .setId(id) + .setCode(code) + .setData(null) + .setMessage(message) + .setMethod(method) + .setVersion("1.0"); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java index d60df9cc0..2e09c3c5c 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.iot.plugin.common.util; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.system.SystemUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; import io.vertx.core.http.HttpHeaders; import io.vertx.ext.web.RoutingContext; import org.springframework.http.MediaType; @@ -12,7 +12,7 @@ import org.springframework.http.MediaType; /** * IoT 插件的通用工具类 * - * 芋道源码 + * @author 芋道源码 */ public class IotPluginCommonUtils { @@ -33,34 +33,43 @@ public class IotPluginCommonUtils { SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID(), IdUtil.fastSimpleUUID()); } - @SuppressWarnings("deprecation") - public static void writeJson(RoutingContext routingContext, CommonResult result) { - routingContext.response() - .setStatusCode(200) - .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) - .end(JsonUtils.toJsonString(result)); - } - - @SuppressWarnings("deprecation") - public static void writeJson(RoutingContext routingContext, String result) { - routingContext.response() - .setStatusCode(200) - .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) - .end(result); - } - /** - * 将对象转换为 JSON 字符串后写入响应 + * 将对象转换为JSON字符串后写入HTTP响应 * * @param routingContext 路由上下文 * @param data 数据对象 */ @SuppressWarnings("deprecation") - public static void writeJson(RoutingContext routingContext, Object data) { + public static void writeJsonResponse(RoutingContext routingContext, Object data) { routingContext.response() .setStatusCode(200) .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) .end(JsonUtils.toJsonString(data)); } + /** + * 生成标准JSON格式的响应并写入HTTP响应(基于IotStandardResponse) + *

+ * 推荐使用此方法,统一MQTT和HTTP的响应格式。使用方式: + * + *

+     * // 成功响应
+     * IotStandardResponse response = IotStandardResponse.success(requestId, method, data);
+     * IotPluginCommonUtils.writeJsonResponse(routingContext, response);
+     *
+     * // 错误响应
+     * IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, code, message);
+     * IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse);
+     * 
+ * + * @param routingContext 路由上下文 + * @param response IotStandardResponse响应对象 + */ + @SuppressWarnings("deprecation") + public static void writeJsonResponse(RoutingContext routingContext, IotStandardResponse response) { + routingContext.response() + .setStatusCode(200) + .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .end(JsonUtils.toJsonString(response)); + } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java index 3f3cf94e9..472eb83f7 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java @@ -14,7 +14,12 @@ import java.util.Collections; /** * IoT Emqx 连接认证的 Vert.x Handler - * MQTT HTTP + * MQTT + * HTTP + * + * 注意:该处理器需要返回特定格式:{"result": "allow"} 或 {"result": "deny"}, + * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类。 * * @author haohao */ @@ -43,15 +48,18 @@ public class IotDeviceAuthVertxHandler implements Handler { // 调用认证 API CommonResult authResult = deviceUpstreamApi.authenticateEmqxConnection(authReqDTO); if (authResult.getCode() != 0 || !authResult.getData()) { - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "deny")); + // 注意:这里必须返回 {"result": "deny"} 格式,以符合 EMQX 认证插件的要求 + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "deny")); return; } // 响应结果 - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "allow")); + // 注意:这里必须返回 {"result": "allow"} 格式,以符合 EMQX 认证插件的要求 + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "allow")); } catch (Exception e) { log.error("[handle][EMQX 认证异常]", e); - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "deny")); + // 注意:这里必须返回 {"result": "deny"} 格式,以符合 EMQX 认证插件的要求 + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "deny")); } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java index 9851d1747..4af6877bf 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java @@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.netty.handler.codec.mqtt.MqttQoS; import io.vertx.core.buffer.Buffer; @@ -14,6 +16,8 @@ import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; /** * IoT 设备 MQTT 消息处理器 @@ -32,16 +36,16 @@ public class IotDeviceMqttMessageHandler { // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply // 设备上报事件 标准 JSON - // 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post - // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply + // 请求 + // Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post + // 响应 + // Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply private static final String SYS_TOPIC_PREFIX = "/sys/"; private static final String PROPERTY_POST_TOPIC = "/thing/event/property/post"; private static final String EVENT_POST_TOPIC_PREFIX = "/thing/event/"; private static final String EVENT_POST_TOPIC_SUFFIX = "/post"; private static final String REPLY_SUFFIX = "_reply"; - private static final int SUCCESS_CODE = 200; - private static final String SUCCESS_MESSAGE = "success"; private static final String PROPERTY_METHOD = "thing.event.property.post"; private static final String EVENT_METHOD_PREFIX = "thing.event."; private static final String EVENT_METHOD_SUFFIX = ".post"; @@ -211,27 +215,25 @@ public class IotDeviceMqttMessageHandler { * @param method 响应方法 * @param customData 自定义数据,可为null */ - private void sendResponse(String topic, JSONObject jsonObject, String method, JSONObject customData) { + private void sendResponse(String topic, JSONObject jsonObject, String method, Object customData) { String replyTopic = topic + REPLY_SUFFIX; - JSONObject data = customData != null ? customData : new JSONObject(); - JSONObject response = new JSONObject() - .set("id", jsonObject.getStr("id")) - .set("code", SUCCESS_CODE) - .set("data", data) - .set("message", SUCCESS_MESSAGE) - .set("method", method); + // 使用IotStandardResponse实体类构建响应 + IotStandardResponse response = IotStandardResponse.success( + jsonObject.getStr("id"), + method, + customData); try { mqttClient.publish(replyTopic, - Buffer.buffer(response.toString()), + Buffer.buffer(JsonUtils.toJsonString(response)), MqttQoS.AT_LEAST_ONCE, false, false); log.info("[sendResponse][发送响应消息成功][topic: {}]", replyTopic); } catch (Exception e) { log.error("[sendResponse][发送响应消息失败][topic: {}][response: {}]", - replyTopic, response.toString(), e); + replyTopic, response, e); } } @@ -249,7 +251,29 @@ public class IotDeviceMqttMessageHandler { reportReqDTO.setReportTime(LocalDateTime.now()); reportReqDTO.setProductKey(topicParts[2]); reportReqDTO.setDeviceName(topicParts[3]); - reportReqDTO.setProperties(jsonObject.getJSONObject("params")); + + // 只使用标准JSON格式处理属性数据 + JSONObject params = jsonObject.getJSONObject("params"); + if (params == null) { + log.warn("[buildPropertyReportDTO][消息格式不正确,缺少params字段][jsonObject: {}]", jsonObject); + params = new JSONObject(); + } + + // 将标准格式的params转换为平台需要的properties格式 + Map properties = new HashMap<>(); + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + Object valueObj = entry.getValue(); + + // 如果是复杂结构(包含value和time) + if (valueObj instanceof JSONObject valueJson) { + properties.put(key, valueJson.getOrDefault("value", valueObj)); + } else { + properties.put(key, valueObj); + } + } + reportReqDTO.setProperties(properties); + return reportReqDTO; } @@ -268,7 +292,15 @@ public class IotDeviceMqttMessageHandler { reportReqDTO.setProductKey(topicParts[2]); reportReqDTO.setDeviceName(topicParts[3]); reportReqDTO.setIdentifier(topicParts[6]); - reportReqDTO.setParams(jsonObject.getJSONObject("params")); + + // 只使用标准JSON格式处理事件参数 + JSONObject params = jsonObject.getJSONObject("params"); + if (params == null) { + log.warn("[buildEventReportDTO][消息格式不正确,缺少params字段][jsonObject: {}]", jsonObject); + params = new JSONObject(); + } + reportReqDTO.setParams(params); + return reportReqDTO; } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java index 31679fe05..6f1e8a11b 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java @@ -18,7 +18,11 @@ import java.util.Collections; /** * IoT Emqx Webhook 事件处理的 Vert.x Handler * - * EMQXWebhook + * EMQXWebhook + * + * 注意:该处理器需要返回特定格式:{"result": "success"} 或 {"result": "error"}, + * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。 * * @author haohao */ @@ -54,10 +58,12 @@ public class IotDeviceWebhookVertxHandler implements Handler { } // 返回成功响应 - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "success")); + // 注意:这里必须返回 {"result": "success"} 格式,以符合 EMQX Webhook 插件的要求 + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "success")); } catch (Exception e) { log.error("[handle][处理 Webhook 事件异常]", e); - IotPluginCommonUtils.writeJson(routingContext, Collections.singletonMap("result", "error")); + // 注意:这里必须返回 {"result": "error"} 格式,以符合 EMQX Webhook 插件的要求 + IotPluginCommonUtils.writeJsonResponse(routingContext, Collections.singletonMap("result", "error")); } } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java index bdb92b6ee..e4d1a7381 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; @@ -15,6 +16,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; +import java.util.HashMap; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; @@ -28,6 +30,9 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC public class IotDeviceEventReportVertxHandler implements Handler { public static final String PATH = "/sys/:productKey/:deviceName/thing/event/:identifier/post"; + private static final String VERSION = "1.0"; + private static final String EVENT_METHOD_PREFIX = "thing.event."; + private static final String EVENT_METHOD_SUFFIX = ".post"; private final IotDeviceUpstreamApi deviceUpstreamApi; @@ -36,40 +41,71 @@ public class IotDeviceEventReportVertxHandler implements Handler public void handle(RoutingContext routingContext) { // 1. 解析参数 IotDeviceEventReportReqDTO reportReqDTO; + String identifier = null; + String requestId = IdUtil.fastSimpleUUID(); try { String productKey = routingContext.pathParam("productKey"); String deviceName = routingContext.pathParam("deviceName"); - String identifier = routingContext.pathParam("identifier"); + identifier = routingContext.pathParam("identifier"); JsonObject body = routingContext.body().asJsonObject(); - String id = ObjUtil.defaultIfBlank(body.getString("id"), IdUtil.fastSimpleUUID()); - Map params = (Map) body.getMap().get("params"); - reportReqDTO = ((IotDeviceEventReportReqDTO) - new IotDeviceEventReportReqDTO().setRequestId(id) - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) - .setProductKey(productKey).setDeviceName(deviceName)) + requestId = ObjUtil.defaultIfBlank(body.getString("id"), requestId); + + // 按照标准JSON格式处理事件参数 + Map params; + + // 优先使用params字段,符合标准 + if (body.getJsonObject("params") != null) { + params = body.getJsonObject("params").getMap(); + } else { + // 兼容旧格式 + params = new HashMap<>(); + } + + reportReqDTO = ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId) + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) + .setProductKey(productKey).setDeviceName(deviceName)) .setIdentifier(identifier).setParams(params); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + // 使用IotStandardResponse实体类返回错误 + String method = identifier != null ? EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX + : "thing.event.unknown.post"; + IotStandardResponse errorResponse = IotStandardResponse.error( + requestId, method, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); return; } try { // 2. 设备上线 - deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) - new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) + deviceUpstreamApi.updateDeviceState( + ((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName())) - .setState(IotDeviceStateEnum.ONLINE.getState())); + .setState(IotDeviceStateEnum.ONLINE.getState())); - // 3.1 属性上报 + // 3.1 事件上报 CommonResult result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO); - // 3.2 返回结果 - IotPluginCommonUtils.writeJson(routingContext, result); + + // 3.2 返回结果 - 使用IotStandardResponse实体类 + String method = EVENT_METHOD_PREFIX + reportReqDTO.getIdentifier() + EVENT_METHOD_SUFFIX; + IotStandardResponse response; + if (result.isSuccess()) { + response = IotStandardResponse.success(reportReqDTO.getRequestId(), method, result.getData()); + } else { + response = IotStandardResponse.error( + reportReqDTO.getRequestId(), method, result.getCode(), result.getMsg()); + } + IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { - log.error("[handle][请求参数({}) 时间上报异常]", reportReqDTO, e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + log.error("[handle][请求参数({}) 事件上报异常]", reportReqDTO, e); + + // 构建错误响应 - 使用IotStandardResponse实体类 + String method = EVENT_METHOD_PREFIX + reportReqDTO.getIdentifier() + EVENT_METHOD_SUFFIX; + IotStandardResponse errorResponse = IotStandardResponse.error( + reportReqDTO.getRequestId(), method, + INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); } } - } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java index 22fb1be82..be3e0017a 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; @@ -15,6 +16,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.time.LocalDateTime; +import java.util.HashMap; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; @@ -31,6 +33,8 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC public class IotDevicePropertyReportVertxHandler implements Handler { public static final String PATH = "/sys/:productKey/:deviceName/thing/event/property/post"; + private static final String VERSION = "1.0"; + private static final String METHOD = "thing.event.property.post"; private final IotDeviceUpstreamApi deviceUpstreamApi; @@ -39,43 +43,89 @@ public class IotDevicePropertyReportVertxHandler implements Handler properties = (Map) body.getMap().get("properties"); - reportReqDTO = ((IotDevicePropertyReportReqDTO) - new IotDevicePropertyReportReqDTO().setRequestId(id) - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) - .setProductKey(productKey).setDeviceName(deviceName)) + requestId = ObjUtil.defaultIfBlank(body.getString("id"), requestId); + + // 按照标准JSON格式处理属性数据 + Map properties = new HashMap<>(); + + // 优先使用params字段,符合标准 + Map params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() + : null; + + if (params != null) { + // 将标准格式的params转换为平台需要的properties格式 + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + Object valueObj = entry.getValue(); + + // 如果是复杂结构(包含value和time) + if (valueObj instanceof Map) { + Map valueMap = (Map) valueObj; + if (valueMap.containsKey("value")) { + properties.put(key, valueMap.get("value")); + } else { + properties.put(key, valueObj); + } + } else { + properties.put(key, valueObj); + } + } + } else { + // 兼容旧格式,直接使用properties字段 + properties = body.getJsonObject("properties") != null ? body.getJsonObject("properties").getMap() + : new HashMap<>(); + } + + reportReqDTO = ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId) + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) + .setProductKey(productKey).setDeviceName(deviceName)) .setProperties(properties); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); + // 使用IotStandardResponse实体类返回错误 + IotStandardResponse errorResponse = IotStandardResponse.error( + requestId, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); return; } // TODO @芋艿:secret 校验。目前的想法: - // 方案一:请求的时候,带上 secret 参数,然后进行校验,减少请求的频次。不过可能要看下 mqtt 能不能复用! - // 方案二:本地有设备信息的缓存,异步刷新。这样可能 mqtt 的校验,和 http 校验都容易适配。 + // 方案一:请求的时候,带上 secret 参数,然后进行校验,减少请求的频次。不过可能要看下 mqtt 能不能复用! + // 方案二:本地有设备信息的缓存,异步刷新。这样可能 mqtt 的校验,和 http 校验都容易适配。 try { // 2. 设备上线 - deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) - new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) + deviceUpstreamApi.updateDeviceState( + ((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName())) - .setState(IotDeviceStateEnum.ONLINE.getState())); + .setState(IotDeviceStateEnum.ONLINE.getState())); // 3.1 属性上报 CommonResult result = deviceUpstreamApi.reportDeviceProperty(reportReqDTO); - // 3.2 返回结果 - IotPluginCommonUtils.writeJson(routingContext, result); + + // 3.2 返回结果 - 使用IotStandardResponse实体类 + IotStandardResponse response; + if (result.isSuccess()) { + response = IotStandardResponse.success(reportReqDTO.getRequestId(), METHOD, result.getData()); + } else { + response = IotStandardResponse.error( + reportReqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); + } + IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 属性上报异常]", reportReqDTO, e); - IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); + + // 构建错误响应 - 使用IotStandardResponse实体类 + IotStandardResponse errorResponse = IotStandardResponse.error( + reportReqDTO.getRequestId(), METHOD, + INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); } } - } From 81739186c971fdc508cf5cd115e5be49a26f38dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 15 Mar 2025 17:56:45 +0800 Subject: [PATCH 219/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E9=87=8D=E6=9E=84=E4=B8=8A?= =?UTF-8?q?=E8=A1=8C=E8=AF=B7=E6=B1=82=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E5=90=88=E5=B9=B6=E5=B1=9E=E6=80=A7=E5=92=8C=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E4=B8=8A=E6=8A=A5=E5=A4=84=E7=90=86=EF=BC=8C=E7=AE=80?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=EF=BC=8C=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E5=86=97=E4=BD=99=E5=A4=84=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/yudao-module-iot-biz/pom.xml | 11 -- .../IotKafkaMQDataBridgeExecute.java | 3 +- .../iot/plugin/emqx/config/IotEmqxPlugin.java | 9 +- .../IotDeviceDownstreamHandlerImpl.java | 1 + .../router/IotDeviceMqttMessageHandler.java | 1 + .../upstream/IotDeviceUpstreamServer.java | 13 +- .../IotDeviceEventReportVertxHandler.java | 111 ----------- .../IotDevicePropertyReportVertxHandler.java | 131 ------------- .../router/IotDeviceUpstreamVertxHandler.java | 185 ++++++++++++++++++ 9 files changed, 201 insertions(+), 264 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 1b897c5d7..d398aa7d8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -64,17 +64,6 @@ yudao-spring-boot-starter-excel
- - - - - - - - - - - org.apache.rocketmq diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index 3b7f99bf4..08dfec333 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -10,7 +10,6 @@ import org.apache.kafka.common.serialization.StringSerializer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.stereotype.Component; import java.time.Duration; import java.time.LocalDateTime; @@ -24,7 +23,7 @@ import java.util.concurrent.TimeUnit; * @author HUIHUI */ @ConditionalOnClass(name = "org.springframework.kafka.core.KafkaTemplate") -@Component +//@Component @Slf4j public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute> { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java index af2e56862..74a49c4f1 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java @@ -7,10 +7,13 @@ import org.pf4j.spring.SpringPlugin; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -// TODO @芋艿:完善注释 - /** - * 负责插件的启动和停止 + * EMQX 插件实现类 + * + * 基于 PF4J 插件框架,实现 EMQX 消息中间件的集成 + * 负责插件的生命周期管理,包括启动、停止和应用上下文的创建 + * + * @author 芋道源码 */ @Slf4j public class IotEmqxPlugin extends SpringPlugin { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java index aed677c49..977f0869c 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java @@ -27,6 +27,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle private static final String SYS_TOPIC_PREFIX = "/sys/"; // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。 + // 回复 都使用 Alink 格式,方便后续扩展。 // 设备服务调用 标准 JSON // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}_reply diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java index 4af6877bf..b92868582 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java @@ -31,6 +31,7 @@ import java.util.Map; public class IotDeviceMqttMessageHandler { // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。 + // 回复 都使用 Alink 格式,方便后续扩展。 // 设备上报属性 标准 JSON // 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java index 42da951a2..67129a4d1 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java @@ -2,8 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.http.upstream; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.plugin.http.config.IotPluginHttpProperties; -import cn.iocoder.yudao.module.iot.plugin.http.upstream.router.IotDeviceEventReportVertxHandler; -import cn.iocoder.yudao.module.iot.plugin.http.upstream.router.IotDevicePropertyReportVertxHandler; +import cn.iocoder.yudao.module.iot.plugin.http.upstream.router.IotDeviceUpstreamVertxHandler; import io.vertx.core.Vertx; import io.vertx.core.http.HttpServer; import io.vertx.ext.web.Router; @@ -32,10 +31,12 @@ public class IotDeviceUpstreamServer { // 创建 Router 实例 Router router = Router.router(vertx); router.route().handler(BodyHandler.create()); // 处理 Body - router.post(IotDevicePropertyReportVertxHandler.PATH) - .handler(new IotDevicePropertyReportVertxHandler(deviceUpstreamApi)); - router.post(IotDeviceEventReportVertxHandler.PATH) - .handler(new IotDeviceEventReportVertxHandler(deviceUpstreamApi)); + + // 使用统一的 Handler 处理所有上行请求 + IotDeviceUpstreamVertxHandler upstreamHandler = new IotDeviceUpstreamVertxHandler(deviceUpstreamApi); + router.post(IotDeviceUpstreamVertxHandler.PROPERTY_PATH).handler(upstreamHandler); + router.post(IotDeviceUpstreamVertxHandler.EVENT_PATH).handler(upstreamHandler); + // 创建 HttpServer 实例 this.server = vertx.createHttpServer().requestHandler(router); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java deleted file mode 100644 index e4d1a7381..000000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceEventReportVertxHandler.java +++ /dev/null @@ -1,111 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; - -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; -import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; -import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; -import io.vertx.core.Handler; -import io.vertx.core.json.JsonObject; -import io.vertx.ext.web.RoutingContext; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; - -/** - * IoT 设备事件上报的 Vert.x Handler - */ -@RequiredArgsConstructor -@Slf4j -public class IotDeviceEventReportVertxHandler implements Handler { - - public static final String PATH = "/sys/:productKey/:deviceName/thing/event/:identifier/post"; - private static final String VERSION = "1.0"; - private static final String EVENT_METHOD_PREFIX = "thing.event."; - private static final String EVENT_METHOD_SUFFIX = ".post"; - - private final IotDeviceUpstreamApi deviceUpstreamApi; - - @Override - @SuppressWarnings("unchecked") - public void handle(RoutingContext routingContext) { - // 1. 解析参数 - IotDeviceEventReportReqDTO reportReqDTO; - String identifier = null; - String requestId = IdUtil.fastSimpleUUID(); - try { - String productKey = routingContext.pathParam("productKey"); - String deviceName = routingContext.pathParam("deviceName"); - identifier = routingContext.pathParam("identifier"); - JsonObject body = routingContext.body().asJsonObject(); - requestId = ObjUtil.defaultIfBlank(body.getString("id"), requestId); - - // 按照标准JSON格式处理事件参数 - Map params; - - // 优先使用params字段,符合标准 - if (body.getJsonObject("params") != null) { - params = body.getJsonObject("params").getMap(); - } else { - // 兼容旧格式 - params = new HashMap<>(); - } - - reportReqDTO = ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId) - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) - .setProductKey(productKey).setDeviceName(deviceName)) - .setIdentifier(identifier).setParams(params); - } catch (Exception e) { - log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - // 使用IotStandardResponse实体类返回错误 - String method = identifier != null ? EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX - : "thing.event.unknown.post"; - IotStandardResponse errorResponse = IotStandardResponse.error( - requestId, method, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); - IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); - return; - } - - try { - // 2. 设备上线 - deviceUpstreamApi.updateDeviceState( - ((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) - .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName())) - .setState(IotDeviceStateEnum.ONLINE.getState())); - - // 3.1 事件上报 - CommonResult result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO); - - // 3.2 返回结果 - 使用IotStandardResponse实体类 - String method = EVENT_METHOD_PREFIX + reportReqDTO.getIdentifier() + EVENT_METHOD_SUFFIX; - IotStandardResponse response; - if (result.isSuccess()) { - response = IotStandardResponse.success(reportReqDTO.getRequestId(), method, result.getData()); - } else { - response = IotStandardResponse.error( - reportReqDTO.getRequestId(), method, result.getCode(), result.getMsg()); - } - IotPluginCommonUtils.writeJsonResponse(routingContext, response); - } catch (Exception e) { - log.error("[handle][请求参数({}) 事件上报异常]", reportReqDTO, e); - - // 构建错误响应 - 使用IotStandardResponse实体类 - String method = EVENT_METHOD_PREFIX + reportReqDTO.getIdentifier() + EVENT_METHOD_SUFFIX; - IotStandardResponse errorResponse = IotStandardResponse.error( - reportReqDTO.getRequestId(), method, - INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); - IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); - } - } -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java deleted file mode 100644 index be3e0017a..000000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java +++ /dev/null @@ -1,131 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; - -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; -import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; -import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; -import io.vertx.core.Handler; -import io.vertx.core.json.JsonObject; -import io.vertx.ext.web.RoutingContext; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; - -// TODO @芋艿:【待定 005】要不要简化成,解析后,统一处理?只有一个 Handler!!! -/** - * IoT 设备属性上报的 Vert.x Handler - * - * @author haohao - */ -@RequiredArgsConstructor -@Slf4j -public class IotDevicePropertyReportVertxHandler implements Handler { - - public static final String PATH = "/sys/:productKey/:deviceName/thing/event/property/post"; - private static final String VERSION = "1.0"; - private static final String METHOD = "thing.event.property.post"; - - private final IotDeviceUpstreamApi deviceUpstreamApi; - - @Override - @SuppressWarnings("unchecked") - public void handle(RoutingContext routingContext) { - // 1. 解析参数 - IotDevicePropertyReportReqDTO reportReqDTO; - String requestId = IdUtil.fastSimpleUUID(); - try { - String productKey = routingContext.pathParam("productKey"); - String deviceName = routingContext.pathParam("deviceName"); - JsonObject body = routingContext.body().asJsonObject(); - requestId = ObjUtil.defaultIfBlank(body.getString("id"), requestId); - - // 按照标准JSON格式处理属性数据 - Map properties = new HashMap<>(); - - // 优先使用params字段,符合标准 - Map params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() - : null; - - if (params != null) { - // 将标准格式的params转换为平台需要的properties格式 - for (Map.Entry entry : params.entrySet()) { - String key = entry.getKey(); - Object valueObj = entry.getValue(); - - // 如果是复杂结构(包含value和time) - if (valueObj instanceof Map) { - Map valueMap = (Map) valueObj; - if (valueMap.containsKey("value")) { - properties.put(key, valueMap.get("value")); - } else { - properties.put(key, valueObj); - } - } else { - properties.put(key, valueObj); - } - } - } else { - // 兼容旧格式,直接使用properties字段 - properties = body.getJsonObject("properties") != null ? body.getJsonObject("properties").getMap() - : new HashMap<>(); - } - - reportReqDTO = ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId) - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) - .setProductKey(productKey).setDeviceName(deviceName)) - .setProperties(properties); - } catch (Exception e) { - log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - // 使用IotStandardResponse实体类返回错误 - IotStandardResponse errorResponse = IotStandardResponse.error( - requestId, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); - IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); - return; - } - - // TODO @芋艿:secret 校验。目前的想法: - // 方案一:请求的时候,带上 secret 参数,然后进行校验,减少请求的频次。不过可能要看下 mqtt 能不能复用! - // 方案二:本地有设备信息的缓存,异步刷新。这样可能 mqtt 的校验,和 http 校验都容易适配。 - - try { - // 2. 设备上线 - deviceUpstreamApi.updateDeviceState( - ((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) - .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) - .setProductKey(reportReqDTO.getProductKey()).setDeviceName(reportReqDTO.getDeviceName())) - .setState(IotDeviceStateEnum.ONLINE.getState())); - - // 3.1 属性上报 - CommonResult result = deviceUpstreamApi.reportDeviceProperty(reportReqDTO); - - // 3.2 返回结果 - 使用IotStandardResponse实体类 - IotStandardResponse response; - if (result.isSuccess()) { - response = IotStandardResponse.success(reportReqDTO.getRequestId(), METHOD, result.getData()); - } else { - response = IotStandardResponse.error( - reportReqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); - } - IotPluginCommonUtils.writeJsonResponse(routingContext, response); - } catch (Exception e) { - log.error("[handle][请求参数({}) 属性上报异常]", reportReqDTO, e); - - // 构建错误响应 - 使用IotStandardResponse实体类 - IotStandardResponse errorResponse = IotStandardResponse.error( - reportReqDTO.getRequestId(), METHOD, - INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); - IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); - } - } -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java new file mode 100644 index 000000000..ce250f41e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java @@ -0,0 +1,185 @@ +package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; +import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse; +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; + +/** + * IoT 设备上行统一处理的 Vert.x Handler + *

+ * 统一处理设备属性上报和事件上报的请求 + * + * @author haohao + */ +@RequiredArgsConstructor +@Slf4j +public class IotDeviceUpstreamVertxHandler implements Handler { + + // 属性上报路径 + public static final String PROPERTY_PATH = "/sys/:productKey/:deviceName/thing/event/property/post"; + // 事件上报路径 + public static final String EVENT_PATH = "/sys/:productKey/:deviceName/thing/event/:identifier/post"; + + private static final String PROPERTY_METHOD = "thing.event.property.post"; + private static final String EVENT_METHOD_PREFIX = "thing.event."; + private static final String EVENT_METHOD_SUFFIX = ".post"; + + private final IotDeviceUpstreamApi deviceUpstreamApi; + + @Override + public void handle(RoutingContext routingContext) { + String path = routingContext.request().path(); + String requestId = IdUtil.fastSimpleUUID(); + + try { + // 1. 解析通用参数 + String productKey = routingContext.pathParam("productKey"); + String deviceName = routingContext.pathParam("deviceName"); + JsonObject body = routingContext.body().asJsonObject(); + requestId = ObjUtil.defaultIfBlank(body.getString("id"), requestId); + + // 2. 根据路径模式处理不同类型的请求 + CommonResult result; + String method; + + if (path.matches(".*/thing/event/property/post")) { + // 处理属性上报 + IotDevicePropertyReportReqDTO reportReqDTO = parsePropertyReportRequest(productKey, deviceName, requestId, body); + + // 设备上线 + updateDeviceState(reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); + + // 属性上报 + result = deviceUpstreamApi.reportDeviceProperty(reportReqDTO); + method = PROPERTY_METHOD; + } else if (path.matches(".*/thing/event/.+/post")) { + // 处理事件上报 + String identifier = routingContext.pathParam("identifier"); + IotDeviceEventReportReqDTO reportReqDTO = parseEventReportRequest(productKey, deviceName, identifier, requestId, body); + + // 设备上线 + updateDeviceState(reportReqDTO.getProductKey(), reportReqDTO.getDeviceName()); + + // 事件上报 + result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO); + method = EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX; + } else { + // 不支持的请求路径 + IotStandardResponse errorResponse = IotStandardResponse.error(requestId, "unknown", BAD_REQUEST.getCode(), "不支持的请求路径"); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); + return; + } + + // 3. 返回标准响应 + IotStandardResponse response; + if (result.isSuccess()) { + response = IotStandardResponse.success(requestId, method, result.getData()); + } else { + response = IotStandardResponse.error(requestId, method, result.getCode(), result.getMsg()); + } + IotPluginCommonUtils.writeJsonResponse(routingContext, response); + + } catch (Exception e) { + log.error("[handle][处理上行请求异常] path={}", path, e); + + // 构建错误响应 + String method = path.contains("/property/") ? PROPERTY_METHOD : EVENT_METHOD_PREFIX + (routingContext.pathParams().containsKey("identifier") ? routingContext.pathParam("identifier") : "unknown") + EVENT_METHOD_SUFFIX; + + IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); + IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); + } + } + + /** + * 更新设备状态 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + */ + private void updateDeviceState(String productKey, String deviceName) { + deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setState(IotDeviceStateEnum.ONLINE.getState())); + } + + /** + * 解析属性上报请求 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + * @param requestId 请求ID + * @param body 请求体 + * @return 属性上报请求DTO + */ + @SuppressWarnings("unchecked") + private IotDevicePropertyReportReqDTO parsePropertyReportRequest(String productKey, String deviceName, String requestId, JsonObject body) { + + // 按照标准JSON格式处理属性数据 + Map properties = new HashMap<>(); + + // 优先使用params字段,符合标准 + Map params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() : null; + + if (params != null) { + // 将标准格式的params转换为平台需要的properties格式 + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + Object valueObj = entry.getValue(); + + // 如果是复杂结构(包含value和time) + if (valueObj instanceof Map) { + Map valueMap = (Map) valueObj; + properties.put(key, valueMap.getOrDefault("value", valueObj)); + } else { + properties.put(key, valueObj); + } + } + } + + return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setProperties(properties); + } + + /** + * 解析事件上报请求 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + * @param identifier 事件标识符 + * @param requestId 请求ID + * @param body 请求体 + * @return 事件上报请求DTO + */ + @SuppressWarnings("unchecked") + private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, String requestId, JsonObject body) { + + // 按照标准JSON格式处理事件参数 + Map params; + + // 优先使用params字段,符合标准 + if (body.getJsonObject("params") != null) { + params = body.getJsonObject("params").getMap(); + } else { + // 兼容旧格式 + params = new HashMap<>(); + } + + return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); + } +} \ No newline at end of file From 86e4379e62908d938e9239cc14d69006075a28b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 15 Mar 2025 18:08:05 +0800 Subject: [PATCH 220/228] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT=EF=BC=9A=E6=96=B0=E5=A2=9E=20TDengine=20?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml | 3 +-- yudao-module-iot/yudao-module-iot-biz/pom.xml | 6 ++++++ .../rule/action/databridge/IotKafkaMQDataBridgeExecute.java | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml index 95ab6f7a4..d5b189391 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -63,12 +63,11 @@ opengauss-jdbc true - com.taosdata.jdbc taos-jdbcdriver + true - com.alibaba druid-spring-boot-3-starter diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index d398aa7d8..72e5f67b2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -107,6 +107,12 @@ 24.1.2 + + + com.taosdata.jdbc + taos-jdbcdriver + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java index 08dfec333..3b7f99bf4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotKafkaMQDataBridgeExecute.java @@ -10,6 +10,7 @@ import org.apache.kafka.common.serialization.StringSerializer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; import java.time.Duration; import java.time.LocalDateTime; @@ -23,7 +24,7 @@ import java.util.concurrent.TimeUnit; * @author HUIHUI */ @ConditionalOnClass(name = "org.springframework.kafka.core.KafkaTemplate") -//@Component +@Component @Slf4j public class IotKafkaMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute> { From 0bdd000226e83ee7b01794030248522b84375616 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 16 Mar 2025 20:43:11 +0800 Subject: [PATCH 221/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9Amqtt=20=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/yudao-module-iot-biz/pom.xml | 11 +++--- .../IotDeviceConfigSetVertxHandler.java | 7 +--- .../IotDeviceOtaUpgradeVertxHandler.java | 7 +--- .../IotDevicePropertyGetVertxHandler.java | 7 +--- .../IotDevicePropertySetVertxHandler.java | 7 +--- .../IotDeviceServiceInvokeVertxHandler.java | 7 +--- .../common/pojo/IotStandardResponse.java | 1 + .../iot/plugin/emqx/config/IotEmqxPlugin.java | 7 ++-- .../IotDeviceDownstreamHandlerImpl.java | 16 ++------ .../router/IotDeviceAuthVertxHandler.java | 9 ++--- .../router/IotDeviceMqttMessageHandler.java | 39 +++++++------------ .../router/IotDeviceWebhookVertxHandler.java | 9 ++--- .../router/IotDeviceUpstreamVertxHandler.java | 34 ++++++++-------- 13 files changed, 61 insertions(+), 100 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 72e5f67b2..b9b97cd81 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -42,6 +42,11 @@ + + com.taosdata.jdbc + taos-jdbcdriver + + cn.iocoder.boot yudao-spring-boot-starter-mybatis @@ -107,12 +112,6 @@ 24.1.2 - - - com.taosdata.jdbc - taos-jdbcdriver - - diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java index 6d2b3b5ba..b9bd4a52f 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java @@ -46,7 +46,6 @@ public class IotDeviceConfigSetVertxHandler implements Handler { .setConfig(config); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - // 使用IotStandardResponse实体类返回错误 IotStandardResponse errorResponse = IotStandardResponse.error( null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); @@ -57,18 +56,16 @@ public class IotDeviceConfigSetVertxHandler implements Handler { try { CommonResult result = deviceDownstreamHandler.setDeviceConfig(reqDTO); - // 使用IotStandardResponse实体类返回结果 + // 3. 响应结果 IotStandardResponse response; if (result.isSuccess()) { response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); } else { - response = IotStandardResponse.error( - reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); + response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); } IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 配置设置异常]", reqDTO, e); - // 使用IotStandardResponse实体类返回错误 IotStandardResponse errorResponse = IotStandardResponse.error( reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java index 888677d8b..a49b84acc 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java @@ -51,7 +51,6 @@ public class IotDeviceOtaUpgradeVertxHandler implements Handler .setInformation(information); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - // 使用IotStandardResponse实体类返回错误 IotStandardResponse errorResponse = IotStandardResponse.error( null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); @@ -62,18 +61,16 @@ public class IotDeviceOtaUpgradeVertxHandler implements Handler try { CommonResult result = deviceDownstreamHandler.upgradeDeviceOta(reqDTO); - // 使用IotStandardResponse实体类返回结果 + // 3. 响应结果 IotStandardResponse response; if (result.isSuccess()) { response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); } else { - response = IotStandardResponse.error( - reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); + response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); } IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) OTA 升级异常]", reqDTO, e); - // 使用IotStandardResponse实体类返回错误 IotStandardResponse errorResponse = IotStandardResponse.error( reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java index dc2a8acfe..3cb4bc941 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java @@ -46,7 +46,6 @@ public class IotDevicePropertyGetVertxHandler implements Handler .setIdentifiers(identifiers); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - // 使用IotStandardResponse实体类返回错误 IotStandardResponse errorResponse = IotStandardResponse.error( null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); @@ -57,18 +56,16 @@ public class IotDevicePropertyGetVertxHandler implements Handler try { CommonResult result = deviceDownstreamHandler.getDeviceProperty(reqDTO); - // 使用IotStandardResponse实体类返回结果 + // 3. 响应结果 IotStandardResponse response; if (result.isSuccess()) { response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); } else { - response = IotStandardResponse.error( - reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); + response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); } IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 属性获取异常]", reqDTO, e); - // 使用IotStandardResponse实体类返回错误 IotStandardResponse errorResponse = IotStandardResponse.error( reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java index 4f0afdccf..251be1eb9 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java @@ -46,7 +46,6 @@ public class IotDevicePropertySetVertxHandler implements Handler .setProperties(properties); } catch (Exception e) { log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); - // 使用IotStandardResponse实体类返回错误 IotStandardResponse errorResponse = IotStandardResponse.error( null, METHOD, BAD_REQUEST.getCode(), BAD_REQUEST.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); @@ -57,18 +56,16 @@ public class IotDevicePropertySetVertxHandler implements Handler try { CommonResult result = deviceDownstreamHandler.setDeviceProperty(reqDTO); - // 使用IotStandardResponse实体类返回结果 + // 3. 响应结果 IotStandardResponse response; if (result.isSuccess()) { response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); } else { - response = IotStandardResponse.error( - reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); + response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); } IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 属性设置异常]", reqDTO, e); - // 使用IotStandardResponse实体类返回错误 IotStandardResponse errorResponse = IotStandardResponse.error( reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java index 3a52f212c..534823f75 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java @@ -48,7 +48,6 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler result = deviceDownstreamHandler.invokeDeviceService(reqDTO); - // 使用IotStandardResponse实体类返回结果 + // 3. 响应结果 String method = METHOD_PREFIX + reqDTO.getIdentifier() + METHOD_SUFFIX; IotStandardResponse response; if (result.isSuccess()) { response = IotStandardResponse.success(reqDTO.getRequestId(), method, result.getData()); } else { - response = IotStandardResponse.error( - reqDTO.getRequestId(), method, result.getCode(), result.getMsg()); + response = IotStandardResponse.error(reqDTO.getRequestId(), method, result.getCode(), result.getMsg()); } IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 服务调用异常]", reqDTO, e); - // 使用IotStandardResponse实体类返回错误 String method = METHOD_PREFIX + reqDTO.getIdentifier() + METHOD_SUFFIX; IotStandardResponse errorResponse = IotStandardResponse.error( reqDTO.getRequestId(), method, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java index a006f3a6a..08b6149c3 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.pojo; import lombok.Data; import lombok.experimental.Accessors; +// TODO @芋艿:1)后续考虑,要不要叫 Iot 网关之类的 Response;2)包名 pojo /** * IoT 标准协议响应实体类 *

diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java index 74a49c4f1..275c20eb1 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotEmqxPlugin.java @@ -10,10 +10,9 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext /** * EMQX 插件实现类 * - * 基于 PF4J 插件框架,实现 EMQX 消息中间件的集成 - * 负责插件的生命周期管理,包括启动、停止和应用上下文的创建 + * 基于 PF4J 插件框架,实现 EMQX 消息中间件的集成:负责插件的生命周期管理,包括启动、停止和应用上下文的创建 * - * @author 芋道源码 + * @author haohao */ @Slf4j public class IotEmqxPlugin extends SpringPlugin { @@ -26,7 +25,6 @@ public class IotEmqxPlugin extends SpringPlugin { public void start() { log.info("[EmqxPlugin][EmqxPlugin 插件启动开始...]"); try { - log.info("[EmqxPlugin][EmqxPlugin 插件启动成功...]"); } catch (Exception e) { log.error("[EmqxPlugin][EmqxPlugin 插件开启动异常...]", e); @@ -52,6 +50,7 @@ public class IotEmqxPlugin extends SpringPlugin { // 继续使用插件自己的 ClassLoader 以加载插件内部的类 pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); // 扫描当前插件的自动配置包 + // TODO @芋艿:是不是要配置下包 pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.emqx.config"); pluginContext.refresh(); return pluginContext; diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java index 977f0869c..c1e64afb9 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java @@ -17,7 +17,6 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.MQTT_TOPIC_IL /** * EMQX 插件的 {@link IotDeviceDownstreamHandler} 实现类 - *

* * @author 芋道源码 */ @@ -26,8 +25,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle private static final String SYS_TOPIC_PREFIX = "/sys/"; - // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。 - // 回复 都使用 Alink 格式,方便后续扩展。 + // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。;回复 都使用 Alink 格式,方便后续扩展。 // 设备服务调用 标准 JSON // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} // 响应Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}_reply @@ -62,11 +60,8 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle try { // 构建请求主题 String topic = buildServiceTopic(reqDTO.getProductKey(), reqDTO.getDeviceName(), reqDTO.getIdentifier()); - - // 生成请求ID(如果没有提供) - String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); - // 构建请求消息 + String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); JSONObject request = buildServiceRequest(requestId, reqDTO.getIdentifier(), reqDTO.getParams()); // 发送消息 @@ -98,11 +93,8 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle try { // 构建请求主题 String topic = buildPropertySetTopic(reqDTO.getProductKey(), reqDTO.getDeviceName()); - - // 生成请求ID(如果没有提供) - String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); - // 构建请求消息 + String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); JSONObject request = buildPropertySetRequest(requestId, reqDTO.getProperties()); // 发送消息 @@ -163,7 +155,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle } /** - * 发布MQTT消息 + * 发布 MQTT 消息 */ private void publishMessage(String topic, JSONObject payload) { mqttClient.publish( diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java index 472eb83f7..fcb228615 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java @@ -13,13 +13,12 @@ import lombok.extern.slf4j.Slf4j; import java.util.Collections; /** - * IoT Emqx 连接认证的 Vert.x Handler - * MQTT - * HTTP + * IoT EMQX 连接认证的 Vert.x Handler + * + * EMQX HTTP * * 注意:该处理器需要返回特定格式:{"result": "allow"} 或 {"result": "deny"}, - * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类。 + * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类 * * @author haohao */ diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java index b92868582..6cf8d84c5 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin.emqx.upstream.router; +import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -21,26 +22,20 @@ import java.util.Map; /** * IoT 设备 MQTT 消息处理器 - *

- * 参考: - *

- * "..."> + * + * 参考:"设备属性、事件、服务"> */ @Slf4j public class IotDeviceMqttMessageHandler { - // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。 - // 回复 都使用 Alink 格式,方便后续扩展。 + // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈;回复 都使用 Alink 格式,方便后续扩展。 // 设备上报属性 标准 JSON // 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply // 设备上报事件 标准 JSON - // 请求 - // Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post - // 响应 - // Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply + // 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post + // 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply private static final String SYS_TOPIC_PREFIX = "/sys/"; private static final String PROPERTY_POST_TOPIC = "/thing/event/property/post"; @@ -70,7 +65,7 @@ public class IotDeviceMqttMessageHandler { log.info("[messageHandler][接收到消息][topic: {}][payload: {}]", topic, payload); try { - if (payload == null || payload.isEmpty()) { + if (StrUtil.isEmpty(payload)) { log.warn("[messageHandler][消息内容为空][topic: {}]", topic); return; } @@ -214,27 +209,20 @@ public class IotDeviceMqttMessageHandler { * @param topic 原始主题 * @param jsonObject 原始消息JSON对象 * @param method 响应方法 - * @param customData 自定义数据,可为null + * @param customData 自定义数据,可为 null */ private void sendResponse(String topic, JSONObject jsonObject, String method, Object customData) { String replyTopic = topic + REPLY_SUFFIX; - // 使用IotStandardResponse实体类构建响应 + // 响应结果 IotStandardResponse response = IotStandardResponse.success( - jsonObject.getStr("id"), - method, - customData); - + jsonObject.getStr("id"), method, customData); try { - mqttClient.publish(replyTopic, - Buffer.buffer(JsonUtils.toJsonString(response)), - MqttQoS.AT_LEAST_ONCE, - false, - false); + mqttClient.publish(replyTopic, Buffer.buffer(JsonUtils.toJsonString(response)), + MqttQoS.AT_LEAST_ONCE, false, false); log.info("[sendResponse][发送响应消息成功][topic: {}]", replyTopic); } catch (Exception e) { - log.error("[sendResponse][发送响应消息失败][topic: {}][response: {}]", - replyTopic, response, e); + log.error("[sendResponse][发送响应消息失败][topic: {}][response: {}]", replyTopic, response, e); } } @@ -304,4 +292,5 @@ public class IotDeviceMqttMessageHandler { return reportReqDTO; } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java index 6f1e8a11b..93fb01bc0 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java @@ -16,13 +16,12 @@ import java.time.LocalDateTime; import java.util.Collections; /** - * IoT Emqx Webhook 事件处理的 Vert.x Handler + * IoT EMQX Webhook 事件处理的 Vert.x Handler * - * EMQXWebhook + * EMQX Webhook * * 注意:该处理器需要返回特定格式:{"result": "success"} 或 {"result": "error"}, - * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。 + * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。 * * @author haohao */ @@ -137,7 +136,7 @@ public class IotDeviceWebhookVertxHandler implements Handler { * 解析用户名,格式为 deviceName&productKey * * @param username 用户名 - * @return 解析结果,[0] 为 deviceName,[1] 为productKey,解析失败返回 null + * @return 解析结果,[0] 为 deviceName,[1] 为 productKey,解析失败返回 null */ private String[] parseUsername(String username) { if (StrUtil.isEmpty(username)) { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java index ce250f41e..f6c7cc3a2 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java @@ -34,9 +34,13 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC @Slf4j public class IotDeviceUpstreamVertxHandler implements Handler { - // 属性上报路径 + /** + * 属性上报路径 + */ public static final String PROPERTY_PATH = "/sys/:productKey/:deviceName/thing/event/property/post"; - // 事件上报路径 + /** + * 事件上报路径 + */ public static final String EVENT_PATH = "/sys/:productKey/:deviceName/thing/event/:identifier/post"; private static final String PROPERTY_METHOD = "thing.event.property.post"; @@ -60,7 +64,6 @@ public class IotDeviceUpstreamVertxHandler implements Handler { // 2. 根据路径模式处理不同类型的请求 CommonResult result; String method; - if (path.matches(".*/thing/event/property/post")) { // 处理属性上报 IotDevicePropertyReportReqDTO reportReqDTO = parsePropertyReportRequest(productKey, deviceName, requestId, body); @@ -97,13 +100,13 @@ public class IotDeviceUpstreamVertxHandler implements Handler { response = IotStandardResponse.error(requestId, method, result.getCode(), result.getMsg()); } IotPluginCommonUtils.writeJsonResponse(routingContext, response); - } catch (Exception e) { log.error("[handle][处理上行请求异常] path={}", path, e); - // 构建错误响应 - String method = path.contains("/property/") ? PROPERTY_METHOD : EVENT_METHOD_PREFIX + (routingContext.pathParams().containsKey("identifier") ? routingContext.pathParam("identifier") : "unknown") + EVENT_METHOD_SUFFIX; - + String method = path.contains("/property/") ? PROPERTY_METHOD + : EVENT_METHOD_PREFIX + (routingContext.pathParams().containsKey("identifier") + ? routingContext.pathParam("identifier") + : "unknown") + EVENT_METHOD_SUFFIX; IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); } @@ -130,20 +133,16 @@ public class IotDeviceUpstreamVertxHandler implements Handler { */ @SuppressWarnings("unchecked") private IotDevicePropertyReportReqDTO parsePropertyReportRequest(String productKey, String deviceName, String requestId, JsonObject body) { - - // 按照标准JSON格式处理属性数据 + // 按照标准 JSON 格式处理属性数据 Map properties = new HashMap<>(); - - // 优先使用params字段,符合标准 + // 优先使用 params 字段,符合标准 Map params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() : null; - if (params != null) { - // 将标准格式的params转换为平台需要的properties格式 + // 将标准格式的 params 转换为平台需要的 properties 格式 for (Map.Entry entry : params.entrySet()) { String key = entry.getKey(); Object valueObj = entry.getValue(); - - // 如果是复杂结构(包含value和time) + // 如果是复杂结构(包含 value 和 time) if (valueObj instanceof Map) { Map valueMap = (Map) valueObj; properties.put(key, valueMap.getOrDefault("value", valueObj)); @@ -153,6 +152,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler { } } + // 构建属性上报请求 DTO return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setProperties(properties); } @@ -166,12 +166,9 @@ public class IotDeviceUpstreamVertxHandler implements Handler { * @param body 请求体 * @return 事件上报请求DTO */ - @SuppressWarnings("unchecked") private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, String requestId, JsonObject body) { - // 按照标准JSON格式处理事件参数 Map params; - // 优先使用params字段,符合标准 if (body.getJsonObject("params") != null) { params = body.getJsonObject("params").getMap(); @@ -180,6 +177,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler { params = new HashMap<>(); } + // 构建事件上报请求 DTO return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); } } \ No newline at end of file From 3b85adc754d5817d138daf2fc00f99e4938a124a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 16 Mar 2025 20:51:00 +0800 Subject: [PATCH 222/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=95=B0=E6=8D=AE=E6=A1=A5?= =?UTF-8?q?=E6=A2=81=E7=9A=84=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/yudao-module-iot-biz/pom.xml | 15 +++++++++++++ .../config/IotDataBridgeAbstractConfig.java | 5 ++++- .../databridge/IotDataBridgeExecuteTest.java | 21 +++++++------------ yudao-server/pom.xml | 13 ------------ 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index b9b97cd81..8721e4de9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -112,6 +112,21 @@ 24.1.2 + + + + + + + + + + + + + + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java index 550550d19..16481193f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Data; @@ -7,7 +8,7 @@ import lombok.Data; /** * 抽象类 IotDataBridgeConfig * - * 用于表示数据桥梁配置数据的通用类型,根据具体的 "type" 字段动态映射到对应的子类。 + * 用于表示数据桥梁配置数据的通用类型,根据具体的 "type" 字段动态映射到对应的子类 * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 * * @author HUIHUI @@ -26,6 +27,8 @@ public abstract class IotDataBridgeAbstractConfig { /** * 配置类型 + * + * 枚举 {@link IotDataBridgeTypeEnum#getType()} */ private String type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java index 03ea33d68..38586afdd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java @@ -10,7 +10,6 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -20,6 +19,7 @@ import java.time.LocalDateTime; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; /** * {@link IotDataBridgeExecute} 实现类的测试 @@ -41,20 +41,14 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { @BeforeEach public void setUp() { // 创建共享的测试消息 - message = IotDeviceMessage.builder() - .requestId("TEST-001") - .productKey("testProduct") - .deviceName("testDevice") - .deviceKey("testDeviceKey") - .type("property") - .identifier("temperature") - .data("{\"value\": 60}") - .reportTime(LocalDateTime.now()) - .tenantId(1L) + message = IotDeviceMessage.builder().requestId("TEST-001").reportTime(LocalDateTime.now()).tenantId(1L) + .productKey("testProduct").deviceName("testDevice").deviceKey("testDeviceKey") + .type("property").identifier("temperature").data("{\"value\": 60}") .build(); // 配置 RestTemplate mock 返回成功响应 - Mockito.when(restTemplate.exchange(anyString(), any(HttpMethod.class), any(), any(Class.class))) + // TODO @puhui999:这个应该放到 testHttpDataBridge 里 + when(restTemplate.exchange(anyString(), any(HttpMethod.class), any(), any(Class.class))) .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); } @@ -64,6 +58,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { IotKafkaMQDataBridgeExecute action = new IotKafkaMQDataBridgeExecute(); // 2. 创建配置 + // TODO @puhui999:可以改成链式哈。 IotDataBridgeKafkaMQConfig config = new IotDataBridgeKafkaMQConfig(); config.setBootstrapServers("127.0.0.1:9092"); config.setTopic("test-topic"); @@ -156,4 +151,4 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { httpDataBridgeExecute.execute(message, new IotDataBridgeDO().setType(httpDataBridgeExecute.getType()).setConfig(config)); } -} +} diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 0251e7b64..17403fef8 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -114,19 +114,6 @@ yudao-module-iot-biz ${revision} - - - - - - - - - - - - - From 44d7d623b33514d7391ce1a3bc8a99cc3bf18425 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 16 Mar 2025 21:26:51 +0800 Subject: [PATCH 223/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9AOTA=20=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../firmware/IotOtaFirmwareCreateReqVO.java | 1 + .../firmware/IotOtaFirmwareUpdateReqVO.java | 3 +- .../record/IotOtaUpgradeRecordPageReqVO.java | 5 ++-- .../task/IotOtaUpgradeTaskSaveReqVO.java | 5 +++- .../ota/IotOtaUpgradeRecordConvert.java | 11 ------- .../dal/dataobject/ota/IotOtaFirmwareDO.java | 1 + .../dal/mysql/ota/IotOtaFirmwareMapper.java | 6 +--- .../mysql/ota/IotOtaUpgradeRecordMapper.java | 15 ++++++---- .../mysql/plugin/IotPluginInstanceMapper.java | 1 + .../service/ota/IotOtaFirmwareService.java | 11 +++---- .../ota/IotOtaFirmwareServiceImpl.java | 4 ++- .../ota/IotOtaUpgradeRecordService.java | 14 +++++---- .../ota/IotOtaUpgradeRecordServiceImpl.java | 30 ++++++++++++------- .../ota/IotOtaUpgradeTaskServiceImpl.java | 18 +++++++---- .../mapper/ota/IotOtaUpgradeRecordMapper.xml | 7 ----- 15 files changed, 73 insertions(+), 59 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java index 98b99351d..20cd19536 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java @@ -27,6 +27,7 @@ public class IotOtaFirmwareCreateReqVO { private String productId; @Schema(description = "签名方式", example = "MD5") + // TODO @li:是不是必传哈 private String signMethod; @Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn/yudao-firmware.zip") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java index 88b7cde5c..4a304338d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java @@ -7,7 +7,7 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; -@Schema(description = "管理后台 - OTA固件更新 Request VO") +@Schema(description = "管理后台 - OTA 固件更新 Request VO") @Data public class IotOtaFirmwareUpdateReqVO { @@ -15,6 +15,7 @@ public class IotOtaFirmwareUpdateReqVO { @NotNull(message = "固件编号不能为空") private Long id; + // TODO @li:name 是不是可以飞必传哈 @Schema(description = "固件名称", requiredMode = REQUIRED, example = "智能开关固件") @NotEmpty(message = "固件名称不能为空") private String name; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java index e28024085..57335ddcb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java @@ -8,16 +8,17 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Data -@Schema(description = "管理后台 - OTA升级记录分页 Request VO") +@Schema(description = "管理后台 - OTA 升级记录分页 Request VO") public class IotOtaUpgradeRecordPageReqVO extends PageParam { + // TODO @li:已经有注解,不用重复注释 /** * 升级任务编号字段。 *

* 该字段用于标识升级任务的唯一编号,不能为空。 */ - @NotNull(message = "升级任务编号不能为空") @Schema(description = "升级任务编号", requiredMode = REQUIRED, example = "1024") + @NotNull(message = "升级任务编号不能为空") private Long taskId; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java index e2fbd8efe..687cf2b25 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java @@ -14,9 +14,12 @@ import java.util.List; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Data -@Schema(description = "管理后台 - OTA升级任务创建/修改 Request VO") +@Schema(description = "管理后台 - OTA 升级任务创建/修改 Request VO") public class IotOtaUpgradeTaskSaveReqVO { + // TODO @li:已经有注解,不用重复注释 + // TODO @li: @Schema 写在参数校验前面。先有定义;其他的,也检查下; + /** * 任务名称 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java deleted file mode 100644 index fe5279b3c..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/ota/IotOtaUpgradeRecordConvert.java +++ /dev/null @@ -1,11 +0,0 @@ -package cn.iocoder.yudao.module.iot.convert.ota; - -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -@Mapper -public interface IotOtaUpgradeRecordConvert { - - IotOtaUpgradeRecordConvert INSTANCE = Mappers.getMapper(IotOtaUpgradeRecordConvert.class); - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java index 12e5147ed..af5d8ac35 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java @@ -46,6 +46,7 @@ public class IotOtaFirmwareDO extends BaseDO { * * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} */ + // TODO @li:帮我改成 Long 哈,写错了 private String productId; /** * 产品标识 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java index 9652942b2..7adf79349 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java @@ -9,11 +9,7 @@ import org.apache.ibatis.annotations.Mapper; import java.util.List; -/** - * OTA固件 Mapper - * - * @author Shelly - */ +// TODO @li:参考 IotOtaUpgradeRecordMapper 的写法 @Mapper public interface IotOtaFirmwareMapper extends BaseMapperX { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java index 46ac87084..8591e1539 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -13,14 +13,10 @@ import org.apache.ibatis.annotations.Select; import java.util.List; import java.util.Map; -/** - * OTA 升级记录 Mapper - * - * @author Shelly - */ @Mapper public interface IotOtaUpgradeRecordMapper extends BaseMapperX { + // TODO @li:selectByFirmwareIdAndTaskIdAndDeviceId;让方法自解释 /** * 根据条件查询单个OTA升级记录 * @@ -37,6 +33,7 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX> selectOtaUpgradeRecordStatistics(Long firmwareId); + // TODO @li:这里的注释,可以去掉哈 /** * 根据分页查询条件获取IOT OTA升级记录的分页结果 * * @param pageReqVO 分页查询请求参数,包含设备名称、任务ID等查询条件 * @return 返回分页查询结果,包含符合条件的IOT OTA升级记录列表 */ + // TODO @li:selectPage 就 ok 拉。 default PageResult selectUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { + // TODO @li:这里的注释,可以去掉哈;然后下面的“如果”。。。也没必要注释 // 使用LambdaQueryWrapperX构建查询条件,并根据请求参数动态添加查询条件 return selectPage(pageReqVO, new LambdaQueryWrapperX() .likeIfPresent(IotOtaUpgradeRecordDO::getDeviceName, pageReqVO.getDeviceName()) // 如果设备名称存在,则添加模糊查询条件 .eqIfPresent(IotOtaUpgradeRecordDO::getTaskId, pageReqVO.getTaskId())); // 如果任务ID存在,则添加等值查询条件 } + // TODO @li:这里的注释,可以去掉哈 /** * 根据任务ID和状态更新升级记录的状态 *

@@ -97,6 +98,7 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX() @@ -106,6 +108,7 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX @@ -120,6 +123,7 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX @@ -137,6 +141,7 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInstanceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInstanceMapper.java index 9bd697dde..93ffe8728 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInstanceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInstanceMapper.java @@ -8,6 +8,7 @@ import org.apache.ibatis.annotations.Mapper; import java.time.LocalDateTime; import java.util.List; +// TODO @li:参考 IotOtaUpgradeRecordMapper 的写法 @Mapper public interface IotPluginInstanceMapper extends BaseMapperX { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java index 124c803b3..99e3b382a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import jakarta.validation.Valid; +// TODO @li:注释写的有点冗余,可以看看别的模块哈。= = AI 生成的注释,有的时候太啰嗦了,需要处理下的哈 /** * OTA 固件管理 Service * @@ -15,7 +16,7 @@ import jakarta.validation.Valid; public interface IotOtaFirmwareService { /** - * 创建OTA固件 + * 创建 OTA 固件 * * @param saveReqVO OTA固件保存请求对象,包含固件的相关信息 * @return 返回新创建的固件的ID @@ -23,14 +24,14 @@ public interface IotOtaFirmwareService { Long createOtaFirmware(@Valid IotOtaFirmwareCreateReqVO saveReqVO); /** - * 更新OTA固件信息 + * 更新 OTA 固件信息 * * @param updateReqVO OTA固件保存请求对象,包含需要更新的固件信息 */ void updateOtaFirmware(@Valid IotOtaFirmwareUpdateReqVO updateReqVO); /** - * 根据ID获取OTA固件信息 + * 根据 ID 获取 OTA 固件信息 * * @param id OTA固件的唯一标识符 * @return 返回OTA固件的详细信息对象 @@ -38,7 +39,7 @@ public interface IotOtaFirmwareService { IotOtaFirmwareDO getOtaFirmware(Long id); /** - * 分页查询OTA固件信息 + * 分页查询 OTA 固件信息 * * @param pageReqVO 包含分页查询条件的请求对象 * @return 返回分页查询结果,包含固件信息列表和分页信息 @@ -46,7 +47,7 @@ public interface IotOtaFirmwareService { PageResult getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO); /** - * 验证物联网OTA固件是否存在 + * 验证物联网 OTA 固件是否存在 * * @param id 固件的唯一标识符 * 该方法用于检查系统中是否存在与给定ID关联的物联网OTA固件信息 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java index d66ce0e4f..7c0ddba7c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java @@ -39,13 +39,14 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) { // 1. 校验固件产品 + 版本号不能重复 validateProductAndVersionDuplicate(saveReqVO.getProductId(), saveReqVO.getVersion()); + // 2.1.转化数据格式,准备存储到数据库中 IotOtaFirmwareDO firmware = BeanUtils.toBean(saveReqVO, IotOtaFirmwareDO.class); // 2.2.查询ProductKey + // TODO @li:productService.getProduct(Convert.toLong(firmware.getProductId())) 放到 1. 后面,先做参考校验。逻辑两段:1)先参数校验;2)构建对象 + 存储 IotProductDO product = productService.getProduct(Convert.toLong(firmware.getProductId())); firmware.setProductKey(Objects.requireNonNull(product).getProductKey()); // TODO @芋艿: 附件、附件签名等属性的计算 - otaFirmwareMapper.insert(firmware); return firmware.getId(); } @@ -79,6 +80,7 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { return firmware; } + // TODO @li:注释有点冗余 /** * 验证产品和版本号是否重复 *

diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java index 86bc18b84..cbf900ac0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java @@ -8,6 +8,7 @@ import jakarta.validation.Valid; import java.util.List; import java.util.Map; +// TODO @li:注释写的有点冗余,可以看看别的模块哈。= = AI 生成的注释,有的时候太啰嗦了,需要处理下的哈 /** * IotOtaUpgradeRecordService 接口定义了与物联网设备OTA升级记录相关的操作。 * 该接口提供了创建、更新、查询、统计和重试升级记录的功能。 @@ -15,7 +16,7 @@ import java.util.Map; public interface IotOtaUpgradeRecordService { /** - * 批量创建OTA升级记录。 + * 批量创建 OTA 升级记录 * 该函数用于为指定的设备列表、固件ID和升级任务ID创建OTA升级记录。 * * @param deviceIds 设备ID列表,表示需要升级的设备集合。 @@ -25,7 +26,7 @@ public interface IotOtaUpgradeRecordService { void createOtaUpgradeRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId); /** - * 获取OTA升级记录的数量统计。 + * 获取 OTA 升级记录的数量统计 * * @return 返回一个 Map,其中键为状态码,值为对应状态的升级记录数量 */ @@ -39,14 +40,14 @@ public interface IotOtaUpgradeRecordService { Map getOtaUpgradeRecordStatistics(Long firmwareId); /** - * 重试指定的OTA升级记录。 + * 重试指定的 OTA 升级记录 * * @param id 需要重试的升级记录的ID。 */ void retryUpgradeRecord(Long id); /** - * 获取指定ID的OTA升级记录的详细信息。 + * 获取指定 ID 的 OTA 升级记录的详细信息。 * * @param id 需要查询的升级记录的ID。 * @return 返回包含升级记录详细信息的响应对象。 @@ -54,7 +55,7 @@ public interface IotOtaUpgradeRecordService { IotOtaUpgradeRecordDO getUpgradeRecord(Long id); /** - * 分页查询OTA升级记录。 + * 分页查询 OTA 升级记录。 * * @param pageReqVO 包含分页查询条件的请求对象,必须经过验证。 * @return 返回包含分页查询结果的响应对象。 @@ -62,7 +63,7 @@ public interface IotOtaUpgradeRecordService { PageResult getUpgradeRecordPage(@Valid IotOtaUpgradeRecordPageReqVO pageReqVO); /** - * 根据任务ID取消升级记录。 + * 根据任务 ID 取消升级记录 *

* 该函数用于根据给定的任务ID,取消与该任务相关的升级记录。通常用于在任务执行失败或用户手动取消时, * 清理或标记相关的升级记录为取消状态。 @@ -71,6 +72,7 @@ public interface IotOtaUpgradeRecordService { */ void cancelUpgradeRecordByTaskId(Long taskId); + // TODO @li:不要的方法,可以删除下哈。 /** * 根据升级状态获取升级记录列表 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java index c04750e00..02ef39cdf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java @@ -25,8 +25,8 @@ import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum.CANCELED; +// TODO @li:@Service、@Validated、@Slf4j,先用关键注解;2)类注释,简单写 @Slf4j @Service @Validated @@ -34,6 +34,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Resource private IotOtaUpgradeRecordMapper upgradeRecordMapper; + // TODO @li:1)@Resource 写在 @Lazy 之前,先用关键注解;2)有必要的情况下,在写 @Lazy 注解。 @Lazy @Resource private IotDeviceService deviceService; @@ -46,8 +47,10 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Override public void createOtaUpgradeRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId) { - // 1.校验升级记录信息是否存在,并且已经取消的任务可以重新开始 + // 1. 校验升级记录信息是否存在,并且已经取消的任务可以重新开始 + // TODO @li:批量查询。。 deviceIds.forEach(deviceId -> validateUpgradeRecordDuplicate(firmwareId, upgradeTaskId, String.valueOf(deviceId))); + // 2.初始化OTA升级记录列表信息 IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(upgradeTaskId); IotOtaFirmwareDO firmware = firmwareService.getOtaFirmware(firmwareId); @@ -70,6 +73,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic } + // TODO @li:1)方法注释,简单写;2)父类写了注释,子类就不用写了。。。 /** * 获取OTA升级记录的数量统计。 * 该方法根据传入的查询条件,统计不同状态的OTA升级记录数量,并返回一个包含各状态数量的映射。 @@ -87,10 +91,10 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic Objects.requireNonNull(upgradeRecordCountMap); return upgradeRecordCountMap.entrySet().stream().collect(Collectors.toMap( entry -> Convert.toInt(entry.getKey()), - entry -> Convert.toLong(entry.getValue()) - )); + entry -> Convert.toLong(entry.getValue()))); } + // TODO @li:1)方法注释,简单写;2)父类写了注释,子类就不用写了。。。 /** * 获取指定固件ID的OTA升级记录统计信息。 * 该方法通过查询数据库,统计不同状态的OTA升级记录数量,并返回一个包含各状态数量的映射。 @@ -107,8 +111,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic Objects.requireNonNull(upgradeRecordStatisticsMap); return upgradeRecordStatisticsMap.entrySet().stream().collect(Collectors.toMap( entry -> Convert.toInt(entry.getKey()), - entry -> Convert.toLong(entry.getValue()) - )); + entry -> Convert.toLong(entry.getValue()))); } @Override @@ -118,7 +121,8 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic // 1.2.校验升级记录是否可以重新升级 validateUpgradeRecordCanRetry(upgradeRecord); - // 2.将一些数据重置,这样定时任务轮询就可以重启任务 + // 2. 将一些数据重置,这样定时任务轮询就可以重启任务 + // TODO @li:更新的时候,wherestatus; upgradeRecordMapper.updateById(new IotOtaUpgradeRecordDO() .setId(upgradeRecord.getId()).setProgress(0) .setStatus(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus())); @@ -136,9 +140,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Override public void cancelUpgradeRecordByTaskId(Long taskId) { - // 暂定只有待推送的升级记录可以取消 + // 暂定只有待推送的升级记录可以取消 TODO @芋艿:可以看看阿里云,哪些可以取消 upgradeRecordMapper.updateUpgradeRecordStatusByTaskIdAndStatus( - CANCELED.getStatus(), taskId, + IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus(), taskId, IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); } @@ -175,6 +179,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic return upgradeRecord; } + // TODO @li:注释有点冗余 /** * 校验固件升级记录是否重复。 *

@@ -189,13 +194,17 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic // 根据条件查询升级记录 IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); // 如果查询到升级记录且状态不是已取消,则抛出异常 + // TODO @li:if return,减少括号层级; + // TODO @li:ObjUtil.notEquals,尽量不用 !取否逻辑; if (upgradeRecord != null) { - if (!CANCELED.getStatus().equals(upgradeRecord.getStatus())) { + if (!IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus().equals(upgradeRecord.getStatus())) { + // TODO @li:提示的时候,需要把 deviceName 给提示出来,不然用户不知道哪个重复啦。 throw exception(OTA_UPGRADE_RECORD_DUPLICATE); } } } + // TODO @li:注释有点冗余 /** * 验证升级记录是否可以重试。 *

@@ -205,6 +214,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic * @param upgradeRecord 需要验证的升级记录对象,类型为 IotOtaUpgradeRecordDO * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出 OTA_UPGRADE_RECORD_CANNOT_RETRY 异常 */ + // TODO @li:这种一次性的方法(不复用的),其实一步一定要抽成小方法; private void validateUpgradeRecordCanRetry(IotOtaUpgradeRecordDO upgradeRecord) { // 检查升级记录的状态是否为 PENDING、PUSHED 或 UPGRADING if (ObjectUtils.equalsAny(upgradeRecord.getStatus(), diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java index ca74481ff..cee3ba516 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java @@ -27,6 +27,7 @@ import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +// TODO @li:完善注释、注解顺序 @Slf4j @Service @Validated @@ -54,9 +55,11 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { IotOtaFirmwareDO firmware = firmwareService.validateFirmwareExists(createReqVO.getFirmwareId()); // 1.3 补全设备范围信息,并且校验是否又设备可以升级,如果没有设备可以升级,则报错 validateScopeAndDevice(createReqVO.getScope(), createReqVO.getDeviceIds(), firmware.getProductId()); + // 2. 保存 OTA 升级任务信息到数据库 IotOtaUpgradeTaskDO upgradeTask = initOtaUpgradeTask(createReqVO, firmware.getProductId()); upgradeTaskMapper.insert(upgradeTask); + // 3. 生成设备升级记录信息并存储,等待定时任务轮询 upgradeRecordService.createOtaUpgradeRecordBatch(upgradeTask.getDeviceIds(), firmware.getId(), upgradeTask.getId()); return upgradeTask.getId(); @@ -68,15 +71,16 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { // 1.1 校验升级任务是否存在 IotOtaUpgradeTaskDO upgradeTask = validateUpgradeTaskExists(id); // 1.2 校验升级任务是否可以取消 - // 检查升级任务的状态是否为进行中,只有此状态下的任务才允许取消 + // TODO @li:ObjUtil notequals if (!Objects.equals(upgradeTask.getStatus(), IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus())) { - // 只有进行中的任务才可以取消 throw exception(OTA_UPGRADE_TASK_CANNOT_CANCEL); } + // 2. 更新 OTA 升级任务状态为已取消 upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder() .id(id).status(IotOtaUpgradeTaskStatusEnum.CANCELED.getStatus()) .build()); + // 3. 更新 OTA 升级记录状态为已取消 upgradeRecordService.cancelUpgradeRecordByTaskId(id); } @@ -98,11 +102,10 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { @Override public void updateUpgradeTaskStatus(Long id, Integer status) { - upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder() - .id(id).status(status) - .build()); + upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder().id(id).status(status).build()); } + // TODO @li:注释有点冗余 /** * 校验固件升级任务是否重复 *

@@ -123,6 +126,7 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { } } + // TODO @li:注释有点冗余 /** * 验证升级任务的范围和设备列表的有效性。 *

@@ -135,6 +139,7 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,抛出相应的异常 */ private void validateScopeAndDevice(Integer scope, List deviceIds, String productId) { + // TODO @li:if return // 验证范围为“选择设备”时,设备列表不能为空 if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { if (CollUtil.isEmpty(deviceIds)) { @@ -149,6 +154,7 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { } } + // TODO @li:注释有点冗余 /** * 验证升级任务是否存在 *

@@ -167,6 +173,7 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { return upgradeTask; } + // TODO @li:注释有点冗余 /** * 初始化升级任务 *

@@ -177,6 +184,7 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { * @param createReqVO 升级任务保存请求对象,包含创建升级任务所需的信息 * @return 返回初始化后的升级任务对象 */ + // TODO @li:一次性的方法,不用特别抽小方法 private IotOtaUpgradeTaskDO initOtaUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, String productId) { // 将请求参数转换为升级任务对象 IotOtaUpgradeTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaUpgradeTaskDO.class); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml deleted file mode 100644 index 74fa85eac..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/ota/IotOtaUpgradeRecordMapper.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file From 9dfe2f6fdfdadd398890fe9a1bfde2036f2288e7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 16 Mar 2025 21:33:47 +0800 Subject: [PATCH 224/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9AOTA=20=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-local.yaml | 30 +++++++++---------- .../src/main/resources/application.yaml | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index aea19a5e9..b4447b07f 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -45,16 +45,16 @@ spring: primary: master datasource: master: - url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 - # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 连接的示例 # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 - username: ruoyi-vue-pro - password: ruoyi-@h2ju02hebp + username: root + password: 123456 # username: sa # SQL Server 连接的示例 # password: Yudao@2024 # SQL Server 连接的示例 # username: SYSDBA # DM 连接的示例 @@ -63,11 +63,11 @@ spring: # password: Yudao@2024 # OpenGauss 连接的示例 slave: # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true - username: ruoyi-vue-pro - password: ruoyi-@h2ju02hebp + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true + username: root + password: 123456 tdengine: # IOT 数据库 - # lazy: true # 开启懒加载,保证启动速度 + lazy: true # 开启懒加载,保证启动速度 url: jdbc:TAOS-RS://chaojiniu.top:6041/ruoyi_vue_pro driver-class-name: com.taosdata.jdbc.rs.RestfulDriver username: root @@ -76,12 +76,11 @@ spring: validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 - data: - redis: - host: chaojiniu.top # 地址 - port: 6379 # 端口 - database: 15 # 数据库索引 - password: fsknKD7UvQYZsyf2hXXn # 密码,建议生产环境开启 + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 +# password: dev # 密码,建议生产环境开启 --- #################### 定时任务相关配置 #################### @@ -186,7 +185,6 @@ logging: cn.iocoder.yudao.module.iot.dal.tdengine: DEBUG cn.iocoder.yudao.module.ai.dal.mysql: debug org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 - com.taosdata: DEBUG # TDengine 的日志级别 debug: false @@ -266,7 +264,7 @@ justauth: prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 ---- #################### iot相关配置 TODO 芋艿:再瞅瞅 #################### +--- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 #################### pf4j: # pluginsDir: /tmp/ pluginsDir: ../plugins \ No newline at end of file diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 28b1eb60a..3232bc2a9 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -334,6 +334,6 @@ yudao: customer: E77DF18BE109F454A5CD319E44BF5177 debug: false -# 插件配置 +# 插件配置 TODO 芋艿:【IOT】需要处理下 pf4j: pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录 \ No newline at end of file From 8203e074ac6e3e4520dcb07395140ae9979a5dd0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 16 Mar 2025 22:28:10 +0800 Subject: [PATCH 225/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9AOTA=20=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao-module-iot-plugin-http-1.0.0.jar | Bin 13508 -> 0 bytes yudao-dependencies/pom.xml | 12 ----- .../yudao-spring-boot-starter-mybatis/pom.xml | 1 + .../banner/core/BannerApplicationRunner.java | 4 +- .../core/handler/GlobalExceptionHandler.java | 6 +-- .../IotDevicePropertyGetReqDTO.java | 1 + .../upstream/IotDeviceEmqxAuthReqDTO.java | 1 + .../upstream/IotDeviceTopologyAddReqDTO.java | 1 + .../yudao/module/iot/enums/IotConstants.java | 45 ------------------ .../IotDeviceMessageIdentifierEnum.java | 1 + .../enums/plugin/IotPluginDeployTypeEnum.java | 15 +----- .../iot/enums/plugin/IotPluginStatusEnum.java | 23 +-------- .../iot/enums/plugin/IotPluginTypeEnum.java | 12 ----- .../iot/enums/product/IotNetTypeEnum.java | 2 +- .../product/IotProductDeviceTypeEnum.java | 2 +- .../enums/product/IotProductStatusEnum.java | 2 +- .../enums/product/IotProtocolTypeEnum.java | 2 +- .../enums/product/IotValidateTypeEnum.java | 2 +- .../rule/IotAlertConfigReceiveTypeEnum.java | 2 +- .../rule/IotDataBridgeDirectionEnum.java | 2 +- .../iot/enums/rule/IotDataBridgeTypeEnum.java | 2 +- .../rule/IotRuleSceneActionTypeEnum.java | 2 +- ...TriggerConditionParameterOperatorEnum.java | 2 +- .../rule/IotRuleSceneTriggerTypeEnum.java | 2 +- .../IotThingModelAccessModeEnum.java | 2 +- .../IotThingModelParamDirectionEnum.java | 2 +- .../IotThingModelServiceCallTypeEnum.java | 2 +- .../IotThingModelServiceEventTypeEnum.java | 2 +- .../thingmodel/IotThingModelTypeEnum.java | 11 +---- .../admin/device/IotDeviceController.java | 4 +- .../vo/group/IotDeviceGroupPageReqVO.java | 2 - .../admin/ota/IotOtaFirmwareController.java | 4 +- .../ota/IotOtaUpgradeRecordController.java | 7 ++- .../ota/IotOtaUpgradeTaskController.java | 4 +- .../firmware/IotOtaFirmwareCreateReqVO.java | 2 +- .../vo/firmware/IotOtaFirmwarePageReqVO.java | 2 +- .../ota/vo/firmware/IotOtaFirmwareRespVO.java | 2 +- .../firmware/IotOtaFirmwareUpdateReqVO.java | 2 +- .../record/IotOtaUpgradeRecordPageReqVO.java | 2 +- .../record/IotOtaUpgradeRecordRespVO.java | 2 +- .../task/IotOtaUpgradeTaskPageReqVO.java | 2 +- .../upgrade/task/IotOtaUpgradeTaskRespVO.java | 2 +- .../task/IotOtaUpgradeTaskSaveReqVO.java | 2 +- .../vo/instance/PluginInstancePageReqVO.java | 3 +- .../vo/instance/PluginInstanceRespVO.java | 13 +---- .../category/IotProductCategoryPageReqVO.java | 4 -- .../vo/product/IotProductPageReqVO.java | 2 - .../vo/databridge/IotDataBridgePageReqVO.java | 4 -- .../vo/databridge/IotDataBridgeRespVO.java | 1 - .../vo/IotStatisticsSummaryRespVO.java | 4 +- .../thingmodel/model/ThingModelParam.java | 2 +- .../thingmodel/vo/IotThingModelPageReqVO.java | 4 -- .../dal/dataobject/device/IotDeviceDO.java | 2 - .../dataobject/device/IotDeviceGroupDO.java | 2 - .../dal/dataobject/ota/IotOtaFirmwareDO.java | 2 - .../dataobject/ota/IotOtaUpgradeRecordDO.java | 2 - .../dataobject/ota/IotOtaUpgradeTaskDO.java | 2 - .../dataobject/plugin/IotPluginConfigDO.java | 2 - .../plugin/IotPluginInstanceDO.java | 2 - .../product/IotProductCategoryDO.java | 2 - .../dal/dataobject/product/IotProductDO.java | 2 - .../dal/dataobject/rule/IotAlertConfig.java | 2 - .../dal/dataobject/rule/IotAlertRecordDO.java | 2 - .../dal/dataobject/rule/IotDataBridgeDO.java | 2 - .../dal/dataobject/rule/IotRuleSceneDO.java | 2 - .../mysql/ota/IotOtaUpgradeRecordMapper.java | 4 +- .../iot/dal/redis/RedisKeyConstants.java | 2 +- .../mq/producer/device/IotDeviceProducer.java | 2 +- .../rule/action/IotRuleSceneAction.java | 2 +- .../common/pojo/IotStandardResponse.java | 2 +- yudao-server/pom.xml | 20 ++++---- .../server/controller/DefaultController.java | 2 +- .../src/main/resources/application-local.yaml | 2 +- 73 files changed, 73 insertions(+), 228 deletions(-) delete mode 100644 plugins/yudao-module-iot-plugin-http-1.0.0.jar delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java diff --git a/plugins/yudao-module-iot-plugin-http-1.0.0.jar b/plugins/yudao-module-iot-plugin-http-1.0.0.jar deleted file mode 100644 index 2d1f7be1b0b03aaec502df04dd6137a907975dd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13508 zcmb_@1z1(v^ET3Pl%HRj_V52~ zo_!AIVa+?U=FFa1v(}5O1Oy~J*wlNMo+{dE{D*v8$k z)G#i?5DqQ~Z@u2H(azEl*ClZhWa zy`<}(iM6q^DOI7`4bZa_NVEsrT?{C-IlhohckF!ks(x5aViOVC0Xmhuc$Cm?EJh&B zDw)zQuTMONMK}^o%^fSn<%T=?b~mgdq9xz0W4vWM{W`MYH80q2-T(tLc=>y$LEL!* zX!YG)e;k1DZGfpY(AvPz?r#Pn|9+sWqk*3F-wen4v*DK3296eneJ8vhL#%YOhfuy(excd#?m zv-}%CrvCuwX!8fSpM#6@e}S{Jc69h5&|rUg&KKC5(SpIjz%Ze}z{LIo>aQ*ovvv@@ z`(Bg{?HpWWfBB+GndpHQdiM4uic$)w{79Zaa5z1<2k5f05BNX((Aq@EqeCDUfy;~3 z%dp28*i==qar4(-B=VfQmh*hcrgcY=EqcaKuEEVaKYo4bC^LL@b+XI-VoQ~a9@vEVF%W+Bfc(j4zDd%YcZ(dY>jRRr$kVgg{HmMQaNVFs1PUL^DUu{&k;li7Vb zhGHf_a&0(lp9U)37f{Wi|R6XSUW7FL(KZB@06p?nVdbP$qmz=%P~3g9~F6# z@+e5I@^y-)can3w&UyrdMnrMhUPd;;uC*>A007miMHw6-+C22oMl~BntBfp?Rt=M# z=3|qb4`xn9xF(3#)tfP-=(5-a$=o3xCUF}CC&KyYRZ~M$Oz%zvcmb<)`#!;sD@S-* zNj$?A0u&~HFq2Wt(MoRy)azG0E-q<1QWA1KAwp3#qSQ($^+T@*C=i^4BC9xFUp{ra zxI)r8rD7&M6Edh(61o|ZMuJ`Zh=;6~5GfVAhmz1gL*s8$w~gBa-Y=Xy7+0OF*m8hO zdy5@{IE5o)f=3Exp&QckAkgOwyK7fEcCOKiScHKw?$$r%!}$#6!i`VGV#oR0jk2Uj zpSH~#UnyCa49PX}v6-xFxpr1<6#d%g)ImJ`obWE8lWBP`*d)TQ==j~dAb!ix-@+aB z^xB)`F5Cqn!N3&$r*Quk##857RI@ZjQUBik(R>1mem6_^(;RA$C9%z4%(PK4-PmJUH`EcJH1=S0R0J8gLdpA_sp`0x>Ijt3 z0=JXn4&_7 zYpyzrK?nOwtaI)N+f)eY(^i^Y7Jey4$sj>5h|Z?D(Q|^N>!+yvv~NC+S-!FnbkTcVoilAv ze=8dJMvyJ1-{y187lpSlq%<$-E~u7hq{PXk&qoXVW5ttG(_Q#%$@AV?#?3wBlh>{c z@arw!GY(qW)SJJcY4CA9$Ax9Abb#wi&nUC~tZ*z%!727&lYwGZ0WFzqxG#!+-`BH` zStgFoU>S0jC5fMY-VOVr*lB|$lp*1%{-*(Y@}+%=ClZKCK+fkw=~`sxJR5`L^)DJA zF->`8&SB{dZPRPPJYaqwlf=M`xYWCNbh}$;J^!C#@~0I1YaA+RDBuaB-QZvtsgV;A zEeN2H!TAS7aFa*-!)Db7LaNb2Ln6xs%^G22<<%LvLAaI=fWpv0%o|lo$`>e}<*e$$ zu*lvoS|LVs^jzJX66doF-|@VA_2ld*l`r4>*8G|SjG;3!12Pv!fNMZ@$VT18l!Rrv zLH8Vc*lD~+^_fVj#herNfV;(X!dpOoRzLpWYnw3^7VJI8Iw{4+;qVWU@n4Q$U(!yO z2aw4xutw5 zr5ZC0#psa>EZu>CW`V($n%D8FxiE12coU^@)-r#2l3fCm-n(}AN*u4#_TeO#bVlIH z4F4H`Xg(DcP&2yj>)OkTr@&8)PO50)4_`7a7X>{gYCoIU&sl3Iu2B!SBHlubP5*q} zP7Q{0$aND%2V*IVTA2!~n_W?XL=gDs6;GL|{chOPr;9V18nHa8iw#n|dglT9BMC&Gi@IDBoCzK=={NTyl0nX<)#KEp_`pU~3$;7}p2!9)|j znZMV4YJ66==b7!6xdPr9qLt5~Oq(WG?vHG^eKTxT*l|L_Gj=7ad1hFAsq(!LXjRB=)c#fl5-ZebO7>KnDQOUpdM8 zRkgs!tnr}za>%6#TU=l@1`pqst#{g~rJ~ppcrI(r;W;IV57oc*!)PqM`8nt4xQKk4bR3GR!wm5>c`HRl&&Eg||7>V_{391F%n zi>E#ne8cw{ONq=xN7#~C*|X9CB7e%pNM39RCKd)V@6tSiS44w~AT|m%c{CK`GZQK) zN}e-`?QlluUZO}Wb;DTjD!63;rR3O%Z0yvCyx1cnXZe*2#bl*mOy3tDKr@(^V@o4! z4lgkTI8bofgjcnRyfDQ|vmQ*_5KJQwQTRm@sgm{u;1QW9_DxZ2Cz*Ns)AVC0y{`#P zQ)a4CyB4!yn2nw1|@@DN=AXAcWof5?D8EWPg* zqC$pFra(iX@5^yfJu3qXLpw1`8;frlaq#7!G#WqBi#KYzGmhvs!tGDJHuiO&wh@O2 zOh_rWYjwPxr3wmsRa%h`QyHb_0kbB@YqHu7bC4O%M$%*gSqW#xDXHQtH94&`$ujxA z#rpyt3{kfM(o^;zqZI(bNU3WegHMS~joKHH%4_lDfgjDBNgZ`Yd408(KM|#yEOjRt z<*m_@1;rzh+N}80o(~teQg-8JYso`dp+#i%;GG2F@p`QD#df|CU<^abnTHv~%fg^? z{xFZ~%GAqH10gRQVw%+OPSz2TJuXa%^hZ*$s0I-WTm;(~rOu8rFAoK)YbYP_Vxg9g zLevV&3FUE=zqnxwgu^N|_ZuEJf!R%%gHux&-F$I+m=8p?B!_HPD^5rE4Xru0N8I6F zl?|^#OTz*oS0?O_wW)m6z@5x}y24NrdJz4|i=r&)RJ3&C2%6k{Rj^h*vuGwW==d*|F@|LSN5l!6Ersap(zT#Xf+Y$A-?S!v4GNf-4c(lL*d z&SG$cef_eOz{o@_4<33Bdrba`a!r=z`&Ww1w51Y`gVf@MB_4w=&GLtuDdsAd&|Fwt z-qA+9+9f!Q*wQmC8{!%X{*^|4D2d8y3E(o(avJCiHk$8~#~Srhb2cn2TiXb@)Ymg1 zpc4W=aAP;ds@OejVJ;K^fMOWSJG#Ujn2xWNugT;zg*^0XiLtU!jmdkkoHlP(l*lKl z=elr;$)uDrQ;-o!Z$p@sV8z@ei#y$@1K>RZ?VkpuOcN=PPsUFrv|w;lzkGR<^AR!> zleeNz*lC3ms0-2A-&!ImTWCh+GRsAFQjlb8X4nf&aWflKWD0>g7|1naPNw zI>N!H&DR(0*A33jTYJ2(noe~04pWCY_PZ-kn*gfh(B&z7GT9JjgwyHqdO&t6G$jWH z=!c(JDhOe)lsWhaw`vp25{N|Fy@3`uHw-aM$FC7Rb`!d(yn9L-^^`qzKBzyNWW-LR z#oS=~=zkEfsvf^B#wx*1WXQsV-3R+?q@ z@yF8yWq9_Tept&UVSq3Uv*j>YxD0x|4}Z;ATmmC!g3@uYe~XC7da^Gd7;-6#b1};w z=*A*lg{ZszXx{(e@$MWfB62NK?UYlHXN=%P+qoLbu3j9|n`MD!KF&hf=po7U)%gVQ&)N;UU37|xwiZJ?GEONnn zK>fao@IoonLf<`j5&$qT>HqNXecx~SUPF|A-GNasv~x1F`*k_3tY(joS2Z%x-id&zJ2Hv<=oGk6CQxnI#8?^7AynnK_q;qq5^Bj!(pn(vIGG3Mx_$U+` zBfQX7X;g_M3l9r>jVLIyUX6t{KOmD)mPHkuP@MGKFkZlD8-N{Z6!?y@F5Z@-I9YrG z(8QIW7>P2z7;HqD9f_*2khH6+89}X;R~6J-gY-1sZG5_X1bI+VwEIb+zhoGV-)e%MG*1Kl!wJYESXQ|8jgAiez;0JE@d`Bb zyMDf)%Z@odVTA&J1CmhgQgRwuHmqb~Fz=bR;5gWo!lb<%8IVjFS$7y-&`_7$6{V~P z2M)1cHOvuUZr>%ML{hA<=bW-~IJC~&jv%KUuZZa@E!pf;Q&*krlpDiz2=6uFiHl)E_9zm;}xR<9Gtq?4dXfZNb(k~W^p;FB;#1lD3WV?2}; zP1eliC>>CIBs>^-xs%Uqo@ic<&e+A|^UZ8OZX!k5;_K$)4I3)o?Sv7MH83|S;A~@8 zfe{{?7%ySApVx7wPREOIK`aB+Bo;3$kK`3VQ6uOr_6*tBm-=uL7vHQ2w)qw4&dO&h zPEK5!y){CpPeb(JWcpojh8g3xP>EY3XN^RFT+XcH+s+fBMc%xerP({AR{okGl$sPW zF?tcCSfqq@+xX2ci+GdBJgp)Uu5@tuFAUNwm5L|XBc$Q|oY1Ly*PkYWqnH%3<6p|S zCf6<^jUF3HC7VR8_FI=;Ijzj4pOszROb+(H(SejsEyTtk?J~f_e0?z)y;kJL@DQ>+ zkFL{4Vw{?ullvK*8gXBLT^XdUK>R~XT-?uS&*>YJ`3cj=*8PXWb3Yzj?LIB_-X-Fq zTLYwJ&k~GDr4X0&?Mynzz3Vh3)J`%2RmB2c4r~aoQmnOH8wB@4I`X|9mTT~~veWM{ z_fs*@Y!kK{rUO+&CL#jNbSIc)VD%~K;Sx=020T96KYSkcxf=MCenp9CMH^LaP`4|} z+(oMcmwBm6quS4?P9Fx@P<;(RhP)@~xYf8bHRmu{YdW+J01Mop64esXtYWj9F~iEs zhPSCr!fwRIXNsb7Z)m5(d8H@6gSf7D?JaFg{hocyFo|#iu(T%fyq@jxYX0c>V5%I; z!W;GK*^yG=a*V(#DI{)f+c^Ao;!aJo-jNC`wuH)6^G7>{sEMub9ZHb)N4mbCv*4w& zha&A{EN92z$qEHw;^gYOq@;zKdIn7~+wL7ICl4-(_j1T2FE4YMwn)fe?lc5X`PH1Y znSI=QR+QSdz^$tI1s_97S4>6_oCb@$oXh6~igQ7>mdQs7>iogU^AG!a5}z$gqNR0l zAwoFNmmjHH$H)bqZ8s8-Ih2rcfObmZ5z67wRi(C~%q%)_xME6$8Kzb|W2vbg$G5?x zeGby51HN&5kf-&l2{wsb_wKa zK%cHUTu7-SQi=;14(zCiK<48YQYP(2v6qy)S1NY&W5saUYo=RIvzd36(Li?eu`yTT zPh9!FyeYSvsm@GsbSMV+pw6!zk_;3j(r8ZH zHwdXlS{m?ppM2SJMw)j288@%vNLk#mpFt)9#LV-i5wGO=#dFmhEMcFb41fC#MZWZ$ z?BY`t$#jqhYP}oo?kfXy_w<47OR5s6^H0{luQ(-nW&#>_XJ!?cU|@RxOU3zhOa6P| zk+rk7x!X#2l{d7pwsZJpSN+#6=35b}QHAqBo5a3t9b`%|Tvsil&!7#i7ZVjxABK#N zwkfs{AWaNbq-bJDA!=d)y|WN?bE{FJ6|gid$(<@f+s(vlB-N)oEypOS$+z6q3aPHC zmNpwQ7ckCI^tLEg z_N2Zt&z>Y|4v-thrd7oNq=bK2m)IW049AD9@R+4I>O-iJPy`mo%Nqwtw)h-m2?|cS zIdSTkNb|-q%XuoY)JluEH)7qaW9-O551V|>%;c6VaHy>2uFYKs7o8p8$-kX$@Jk}|cL1qEk0!5gj7!Wn~-{2q6H3JJzGm~8A| zK3)N(a3{M@Fg8@iEK!q?*6_XSe1ftG;>1M28X`q?&bRCoHK5X%Vy&4~_iay+mkJxF zhc>J}RpZ-;0q3sTC-ujY#-FWhW*AVYHQEN3MrWq3h+cllxC*!l*6Ts18Fg$IA=B?# zTOcJ-W>GBF5$42+h`c z^Bq#^+9_nY?!^z(^ee*29$Rxc%QyAG(OT8b6s6XFfIAadKQNFv)~9;V(OzbyQgfPL zj|qa^F{6Gtl2ud>wpC>2H)>^DcN$weg|3tc%a3b7+Y9e=QT;ab4U=AVPe{beBj0|w ztxi`}GLmqbKEc%mtM!E39v-1-9RK*y{;Dq<5R?^1qIuGqnVWd$2R0d`~% z&iF(S{}w>VW%JVCk+~G(6b>&jw%i1lUeMNZx^L!1U0kwe6uQXS`A4;w+VQ*>1C9U! zI`T(*@yJk?3=s(Huhx9Eh8B-hCARfV(hY(mXQAOT=E-;BB_1`@(}Bsfb8l)6<^@i% z@!6nVWawr46JW#Xy?jNYY^#`Qk}BK5#Gx*=D^J%XERl!OTtc_-`1B()Ag7N6c4syT zo1BdUy?RVcjwI2G%TzJD_6-7dO1L^LUMCE$DcoCTc7%R%$^6@`!qTNdY3aOATY^uQ zh*naWmjayQWS)?h*O2C8VJo4=+q=?S6I1T=7zL_zO23kkr-^qd3;$^Ahg-6sxVN{5 zfbTq?Vh$vlkYcvNFhUn#+xpz%a^!_gh~+gN4H`16N7o=-AYb#F8Ia|U@z9i^C~0=< zY~QtW6JDyyqe8J#_sS~Tfb+x zpXT{%0D1FR@$0c!(I~Bg*D~QCXvmaEj|5kz7Rw=3P%=hkUyGTyw1fzCE9J)PcZ0M z@}{eaXDznsp-RW@YHjm5Tc>d7q%{>AiBy?9%UC$IbYU@PZY8rOHBFYHkt&yIFXfDR zVqIK;RVy=H)=o23>Zf(1Hzv6Sgys(P!#g<*Qi;#A6lfz)WuMuIl3qEzON3Ps6i}Yn zLoF-=i`?efUo|2AlABd59QLt@(gK_KVj{-(tm52Xv>`nFlR49vQGD5mKY6B@M^6Dp zZyXm0(20RAJ}|kItQ@N1d5(KSze1Q*aY5nZC?qen&*tW$Y+pCspLsAe3f+g&D7i>d za)I2rEtXHdC(vVo_Ezt~=Mz+zE7~wOwiuI9i&3Ggl;p@!tqTbVji5b`^S)D!z|(z~ zi_#Roj<f>5MJ->9jNOS&cUPPl+F(l;CITptHJ}94q00y(#cO z8`Hk*W)!;3M=@^CPdZQ3!_dZP!mdDuM2peHNGl-?PE3%0d7}W$H0akOe!DZ2Q)q`| z%shbx6AHr=rUzzkF78C4snCeHaZ~hc=W#qS(r5r$=IklI<_Di!JMYEEAHrn$X~Lnz zSyV5ulp$`&z3rjRSxgAK+z`1=p~bJJjWVX{PGP?|S z0IZ4!mOX>o&Q=ltR>RAY{2uYAO-)W?rA?_?>D2Y+#>&Tly+dy!Bt#d=GM=P%LBE;j zJe65%JBN3--}d9FSI-J>+g$pcfrb&Jw2WBMJ*vx-JP6HP9hK_75|~$a`Z=(I~CHQXs$)!BtfFO4FZD(?2En z1G}d0ye*ZJEUFiS*&$fTQ-2U+FzAppVHJB~1&X$lrur01kSry4M&Hfp@GvpkwZT6!Da7*b{ZnnjCWik z)3$te9M?4-X zsom#(z~HB=GDGLaz5%)&2P$qi!eE)Af>qOp(3Y@QnD;AN;2o36&G-wF^WBOz6?{zD@j%7_dP~F^e7rN=Ptwu_d?fY3<3UY(+6#958CK z0deXlC$P~b#{S+2@w;h)VHRX>=qfB@KgrZ!*<<2A@)#Ikj~<(;#X;us9cN`oPi$ga zo9EsS$412W2sXB{;ca+?C~Kz#x!(f%zTfjlirQBjzf;sK^_&cUBpm(BXCwUMV4xNK zuS6{RuY0dQFnN9!=J{vgUl>|+-zZmfrq&L0-zZRYCO)`7Bx!z*5iz5E&D1$4f9rYM48l}E-0Vs3Nd_Cyv6krHqu%{ZYlTm zJ~*Ffr`5KHH(;1utv(UyKD(q+Q)8v*S#@ViXKAer@2ha}hdw)ng zQ?0FKA6#?;j~RI)&xi}VXhbC$$1O7A;MR|YNGHzoLYVBHiAv|UF}<8fsE`HPc{zzc zvPC=t4;u0Id*`4|76YS?8{}iyb%FuxeA{-zg9v9?5xUcQf>W~U+@D~9_C3=WN4U%u&Un|J=#^ce@Du&6P4%g+?CorF<=ovtzR zKA)0^A-eqenQ3~$NqXss@iRWYX?0&Hdz9`pw80wW9_Sj}nU{guonueZ;`!y|EG4S$ z=@JabKHt^V&F&^>ODDY)Vx70Z9(l*99xh;DwI_#(B~ITTH6|_*D*sb#fxtWLWQ-S| zaH0+6X+n~7wN(msnpkK~QC!RtBYh&@=31I*lhq!#L)0B~h=ZVXoI0I3Fg^jBkW9`$ zjb0q|&vxUR^GH(&2w1>~CGZOsl@rS(%v#3+6Vc2IKUp@(PYuZzOrL!$!inxAY8n}M zAwU++4$oEYdwDAZgE|w*UKP>IyQ-ZRbpBxP7Ijiub6+v%8T??l>~1WbdT; zTdX9SsgNpYNT;@FW{F24!*LKfa>YAeZ z5cQKtw;5&%wQ%NyPw&L+sZWHk77Z*OapD_B_o%RrPvw$ZsP~CSDJU~ISVc^V*o?fn z3?x8#?ey3@m#gTcq%sOhEqqZe!xvBxsC7(N=dezfQ>MgWfjl2-9%wZ(6>@$0Jm-cZ z>g?u+gOaatPaI(Q(Dg3fU)DUptRszv z!H~XCAq>Qq!B04;Gn~yf{NF5Kr z(IEbsL3=mLy9)_ym;dYg_hfZ1_UDY+uY|cX_Wx?KqfBp~PKOD^e=;WWR|H_KJS0H#7tpCEvzxd?) znaz*zKgaS{mh3%z?EeD)oiqEJm;RhJ`AQ2Uf9tz@ zwg1Rv{Mmq?scQEInBS4t{<{HR&%J-(4u9L^{8{PG?2vn|bz2em3Ig zll^-m*zYpmzn%Hl`TpZM|Iey_KG(cgU3K>_7ynlE_b2B2?EmbP^Jm>Z?{MGiCd2(7 zbpO}=?jOzhv$o{koLjO#G%5GOf8H;A6Gj5Nz0D^7p|bwgJ^c2>|55mB|8Orn@<-u6 zb`yUM_O+k52YYx|Mr*@qxt&j{{iGQ^WOjf diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index fa54eef60..4d2aef341 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -35,8 +35,6 @@ 3.3.3 2.3.2 - 3.3.3 - 3.4.3 2.2.7 @@ -292,16 +290,6 @@ rocketmq-spring-boot-starter ${rocketmq-spring.version} - - org.springframework.kafka - spring-kafka - ${kafka-spring.version} - - - org.springframework.boot - spring-boot-starter-amqp - ${rabbitmq-spring.version} - diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml index d5b189391..5a619c511 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -68,6 +68,7 @@ taos-jdbcdriver true + com.alibaba druid-spring-boot-3-starter diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java index c8b0dbd66..d07c4aaed 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java @@ -62,9 +62,9 @@ public class BannerApplicationRunner implements ApplicationRunner { if (isNotPresent("cn.iocoder.yudao.module.ai.framework.web.config.AiWebConfiguration")) { System.out.println("[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]"); } - // IOT 物联网 + // IoT 物联网 if (isNotPresent("cn.iocoder.yudao.module.iot.framework.web.config.IotWebConfiguration")) { - System.out.println("[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + System.out.println("[IoT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]"); } }); } diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java index 41c5cead6..b0ca9c778 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java @@ -378,11 +378,11 @@ public class GlobalExceptionHandler { return CommonResult.error(NOT_IMPLEMENTED.getCode(), "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]"); } - // 9. IOT 物联网 + // 9. IoT 物联网 if (message.contains("iot_")) { - log.error("[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + log.error("[IoT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); return CommonResult.error(NOT_IMPLEMENTED.getCode(), - "[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + "[IoT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); } return null; } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java index b72d88d97..d9ae96321 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java @@ -6,6 +6,7 @@ import lombok.Data; import java.util.List; // TODO @芋艿:从 server => plugin => device 是否有必要?从阿里云 iot 来看,没有这个功能?! +// TODO @芋艿:是不是改成 read 更好?在看看阿里云的 topic 设计 /** * IoT 设备【属性】获取 Request DTO * diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java index 2fb10a076..8762aae5b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java @@ -4,6 +4,7 @@ import jakarta.validation.constraints.NotEmpty; import lombok.Data; // TODO @芋艿:要不要继承 IotDeviceUpstreamAbstractReqDTO +// TODO @芋艿:@haohao:后续其它认证的设计 /** * IoT 认证 Emqx 连接 Request DTO * diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java index 38b2b69ef..18efe7d48 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java @@ -5,6 +5,7 @@ import lombok.Data; import java.util.List; +// TODO @芋艿:要写清楚,是来自设备网关,还是设备。 /** * IoT 设备【拓扑】添加 Request DTO */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java deleted file mode 100644 index 631ca24a3..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/IotConstants.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.iot.enums; - -/** - * Iot 常量 - * - * @author 芋道源码 - */ -public interface IotConstants { - - /** - * 获取设备表名 - *

- * 格式为 device_{productKey}_{deviceName} - */ - String DEVICE_TABLE_NAME_FORMAT = "device_%s_%s"; - - /** - * 获取产品属性超级表名 - 网关子设备 - *

- * 格式为 gateway_sub_{productKey} - */ - String GATEWAY_SUB_STABLE_NAME_FORMAT = "gateway_sub_%s"; - - /** - * 获取产品属性超级表名 - 网关 - *

- * 格式为 gateway_{productKey} - */ - String GATEWAY_STABLE_NAME_FORMAT = "gateway_%s"; - - /** - * 获取产品属性超级表名 - 设备 - *

- * 格式为 device_{productKey} - */ - String DEVICE_STABLE_NAME_FORMAT = "device_%s"; - - /** - * 获取物模型消息记录设备名 - *

- * 格式为 thing_model_message_{productKey}_{deviceName} - */ - String THING_MODEL_MESSAGE_TABLE_NAME_FORMAT = "thing_model_message_%s_%s"; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java index 5bd169aba..6de9359ba 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.enums.device; import lombok.Getter; import lombok.RequiredArgsConstructor; +// TODO @芋艿:需要添加对应的 DTO,以及上下行的链路,网关、网关服务、设备等 /** * IoT 设备消息标识符枚举 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java index 3f7e75310..b6ef4f0cc 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.enums.plugin; import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.Getter; +import lombok.RequiredArgsConstructor; import java.util.Arrays; @@ -10,6 +11,7 @@ import java.util.Arrays; * * @author haohao */ +@RequiredArgsConstructor @Getter public enum IotPluginDeployTypeEnum implements ArrayValuable { @@ -22,24 +24,11 @@ public enum IotPluginDeployTypeEnum implements ArrayValuable { * 部署方式 */ private final Integer deployType; - /** * 部署方式名 */ private final String name; - IotPluginDeployTypeEnum(Integer deployType, String name) { - this.deployType = deployType; - this.name = name; - } - - public static IotPluginDeployTypeEnum valueOf(Integer deployType) { - return Arrays.stream(values()) - .filter(value -> value.getDeployType().equals(deployType)) - .findFirst() - .orElse(null); - } - @Override public Integer[] array() { return ARRAYS; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java index 9b187c5b6..7e3fa657e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.enums.plugin; import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.Getter; +import lombok.RequiredArgsConstructor; import java.util.Arrays; @@ -10,6 +11,7 @@ import java.util.Arrays; * * @author haohao */ +@RequiredArgsConstructor @Getter public enum IotPluginStatusEnum implements ArrayValuable { @@ -22,35 +24,14 @@ public enum IotPluginStatusEnum implements ArrayValuable { * 状态 */ private final Integer status; - /** * 状态名 */ private final String name; - IotPluginStatusEnum(Integer status, String name) { - this.status = status; - this.name = name; - } - - public static IotPluginStatusEnum fromState(Integer state) { - return Arrays.stream(values()) - .filter(value -> value.getStatus().equals(state)) - .findFirst() - .orElse(null); - } - @Override public Integer[] array() { return ARRAYS; } - public static boolean isValidState(Integer state) { - return fromState(state) != null; - } - - public static boolean contains(Integer status) { - return Arrays.stream(values()).anyMatch(e -> e.getStatus().equals(status)); - } - } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java index 0f81d5a8f..ec0b72f9f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java @@ -24,7 +24,6 @@ public enum IotPluginTypeEnum implements ArrayValuable { * 类型 */ private final Integer type; - /** * 类型名 */ @@ -35,15 +34,4 @@ public enum IotPluginTypeEnum implements ArrayValuable { return ARRAYS; } - public static IotPluginTypeEnum fromType(Integer type) { - return Arrays.stream(values()) - .filter(value -> value.getType().equals(type)) - .findFirst() - .orElse(null); - } - - public static boolean isValidType(Integer type) { - return fromType(type) != null; - } - } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java index 561bc66f9..2a54e489f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 联网方式枚举类 + * IoT 联网方式枚举类 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java index 238e3e25f..7910f1b2d 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 产品的设备类型 + * IoT 产品的设备类型 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java index ee8be5c81..b9bbbeec7 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 产品的状态枚举类 + * IoT 产品的状态枚举类 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java index 9eb57044f..d24dea92e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 接入网关协议枚举类 + * IoT 接入网关协议枚举类 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java index 11604b4dd..2a15d16a4 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 数据校验级别枚举类 + * IoT 数据校验级别枚举类 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java index 87df89f76..3fdd53234 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java @@ -7,7 +7,7 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * Iot 告警配置的接收方式枚举 + * IoT 告警配置的接收方式枚举 * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java index eb4b99916..a9d445fd2 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java @@ -7,7 +7,7 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * Iot 数据桥接的方向枚举 + * IoT 数据桥接的方向枚举 * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java index 25c7e8c1f..78fc8452e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java @@ -7,7 +7,7 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * Iot 数据桥接的类型枚举 + * IoT 数据桥接的类型枚举 * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java index 2dfb92f63..2bdf7d0ed 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java @@ -7,7 +7,7 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * Iot 规则场景的触发类型枚举 + * IoT 规则场景的触发类型枚举 * * 设备触发,定时触发 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java index 1aac8c237..5ed90ccae 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java @@ -8,7 +8,7 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * Iot 场景触发条件参数的操作符枚举 + * IoT 场景触发条件参数的操作符枚举 * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java index 509b9a603..a420a21d5 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java @@ -7,7 +7,7 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * Iot 场景流转的触发类型枚举 + * IoT 场景流转的触发类型枚举 * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java index a78614853..c0a2b329b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 产品物模型属性读取类型枚举 + * IoT 产品物模型属性读取类型枚举 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java index 00158a0f9..4f06cefce 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java @@ -8,7 +8,7 @@ import java.util.Arrays; /** - * IOT 产品物模型参数是输入参数还是输出参数枚举 + * IoT 产品物模型参数是输入参数还是输出参数枚举 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java index d6ed70e50..376db6b4a 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 产品物模型服务调用方式枚举 + * IoT 产品物模型服务调用方式枚举 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java index 584c0743f..c7c74092a 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 产品物模型事件类型枚举 + * IoT 产品物模型事件类型枚举 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java index 8f0345529..e0097cfe9 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 产品功能(物模型)类型枚举类 + * IoT 产品功能(物模型)类型枚举类 * * @author ahh */ @@ -30,15 +30,6 @@ public enum IotThingModelTypeEnum implements ArrayValuable { */ private final String description; - public static IotThingModelTypeEnum valueOfType(Integer type) { - for (IotThingModelTypeEnum value : values()) { - if (value.getType().equals(type)) { - return value; - } - } - return null; - } - @Override public Integer[] array() { return ARRAYS; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 2add4ee13..08fc244b1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -133,8 +133,8 @@ public class IotDeviceController { public CommonResult> getSimpleDeviceList( @RequestParam(value = "deviceType", required = false) Integer deviceType) { List list = deviceService.getDeviceListByDeviceType(deviceType); - return success(convertList(list, device -> // 只返回 id、name 字段 - new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName()))); + return success(convertList(list, device -> // 只返回 id、name 字段 + new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName()))); } @PostMapping("/import") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java index 1490f2894..93b1a1ead 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java @@ -13,8 +13,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Schema(description = "管理后台 - IoT 设备分组分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class IotDeviceGroupPageReqVO extends PageParam { @Schema(description = "分组名字", example = "李四") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java index 344a1e3fc..6cc3918e8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java @@ -19,10 +19,10 @@ import org.springframework.web.bind.annotation.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -@Validated -@RestController @Tag(name = "管理后台 - IoT OTA 固件") +@RestController @RequestMapping("/iot/ota-firmware") +@Validated public class IotOtaFirmwareController { @Resource diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java index 519d6b9ab..f6bc526ac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java @@ -20,10 +20,10 @@ import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -@Validated +@Tag(name = "管理后台 - IoT OTA 升级记录") @RestController -@Tag(name = "管理后台 - OTA 升级记录") @RequestMapping("/iot/ota-upgrade-record") +@Validated public class IotOtaUpgradeRecordController { @Resource @@ -33,8 +33,7 @@ public class IotOtaUpgradeRecordController { @Operation(summary = "固件升级设备统计") @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") @Parameter(name = "firmwareId", description = "固件编号", required = true, example = "1024") - public CommonResult> getOtaUpgradeRecordStatistics( - @RequestParam(value = "firmwareId") Long firmwareId) { + public CommonResult> getOtaUpgradeRecordStatistics(@RequestParam(value = "firmwareId") Long firmwareId) { return success(upgradeRecordService.getOtaUpgradeRecordStatistics(firmwareId)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java index 5486102e6..e248e8027 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java @@ -19,10 +19,10 @@ import org.springframework.web.bind.annotation.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -@Validated +@Tag(name = "管理后台 - IoT OTA 升级任务") @RestController -@Tag(name = "管理后台 - OTA升级任务") @RequestMapping("/iot/ota-upgrade-task") +@Validated public class IotOtaUpgradeTaskController { @Resource diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java index 20cd19536..50c2ece15 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java @@ -7,7 +7,7 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; -@Schema(description = "管理后台 - OTA 固件创建 Request VO") +@Schema(description = "管理后台 - IoT OTA 固件创建 Request VO") @Data public class IotOtaFirmwareCreateReqVO { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java index 24304202c..baa741029 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java @@ -5,7 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data -@Schema(description = "管理后台 - OTA 固件分页 Request VO") +@Schema(description = "管理后台 - IoT OTA 固件分页 Request VO") public class IotOtaFirmwarePageReqVO extends PageParam { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java index f9aa25cca..735618781 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java @@ -10,7 +10,7 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Data -@Schema(description = "管理后台 - OTA 固件 Response VO") +@Schema(description = "管理后台 - IoT OTA 固件 Response VO") public class IotOtaFirmwareRespVO implements VO { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java index 4a304338d..aa134bcee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java @@ -7,7 +7,7 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; -@Schema(description = "管理后台 - OTA 固件更新 Request VO") +@Schema(description = "管理后台 - IoT OTA 固件更新 Request VO") @Data public class IotOtaFirmwareUpdateReqVO { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java index 57335ddcb..2b21b3079 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java @@ -8,7 +8,7 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Data -@Schema(description = "管理后台 - OTA 升级记录分页 Request VO") +@Schema(description = "管理后台 - IoT OTA 升级记录分页 Request VO") public class IotOtaUpgradeRecordPageReqVO extends PageParam { // TODO @li:已经有注解,不用重复注释 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java index d717cfd31..db6737feb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java @@ -13,7 +13,7 @@ import java.time.LocalDateTime; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Data -@Schema(description = "管理后台 - OTA升级记录 Response VO") +@Schema(description = "管理后台 - IoT OTA 升级记录 Response VO") public class IotOtaUpgradeRecordRespVO { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java index c1f2816c0..d2b1926aa 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java @@ -8,7 +8,7 @@ import lombok.Data; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Data -@Schema(description = "管理后台 - OTA升级任务分页 Request VO") +@Schema(description = "管理后台 - IoT OTA 升级任务分页 Request VO") public class IotOtaUpgradeTaskPageReqVO extends PageParam { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java index f8f5320c9..dbc29618f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java @@ -12,7 +12,7 @@ import java.util.List; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Data -@Schema(description = "管理后台 - OTA升级任务 Response VO") +@Schema(description = "管理后台 - IoT OTA 升级任务 Response VO") public class IotOtaUpgradeTaskRespVO implements VO { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java index 687cf2b25..0ace17a04 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java @@ -14,7 +14,7 @@ import java.util.List; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; @Data -@Schema(description = "管理后台 - OTA 升级任务创建/修改 Request VO") +@Schema(description = "管理后台 - IoT OTA 升级任务创建/修改 Request VO") public class IotOtaUpgradeTaskSaveReqVO { // TODO @li:已经有注解,不用重复注释 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/instance/PluginInstancePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/instance/PluginInstancePageReqVO.java index dad6926bd..e58b88856 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/instance/PluginInstancePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/instance/PluginInstancePageReqVO.java @@ -8,11 +8,12 @@ import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +// TODO @haohao:后续需要使用下 @Schema(description = "管理后台 - IoT 插件实例分页 Request VO") @Data public class PluginInstancePageReqVO extends PageParam { - @Schema(description = "插件主程序id", example = "23738") + @Schema(description = "插件主程序编号", example = "23738") private String mainId; @Schema(description = "插件id", example = "26498") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/instance/PluginInstanceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/instance/PluginInstanceRespVO.java index 96a89299d..cba59fdaf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/instance/PluginInstanceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/instance/PluginInstanceRespVO.java @@ -1,43 +1,34 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.instance; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; +// TODO @haohao:后续需要使用下 @Schema(description = "管理后台 - IoT 插件实例 Response VO") @Data -@ExcelIgnoreUnannotated public class PluginInstanceRespVO { - @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "23864") - @ExcelProperty("主键ID") + @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23864") private Long id; @Schema(description = "插件主程序id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23738") - @ExcelProperty("插件主程序id") private String mainId; @Schema(description = "插件id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26498") - @ExcelProperty("插件id") private Long pluginId; @Schema(description = "插件主程序所在ip", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("插件主程序所在ip") private String ip; @Schema(description = "插件主程序端口", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("插件主程序端口") private Integer port; @Schema(description = "心跳时间,心路时间超过30秒需要剔除", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("心跳时间,心路时间超过30秒需要剔除") private Long heartbeatAt; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") private LocalDateTime createTime; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryPageReqVO.java index 90d338a89..f1c12bf7c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/category/IotProductCategoryPageReqVO.java @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.product.vo.category; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; @@ -13,8 +11,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Schema(description = "管理后台 - IoT 产品分类分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class IotProductCategoryPageReqVO extends PageParam { @Schema(description = "分类名字", example = "王五") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductPageReqVO.java index d54adec48..18c69c4ce 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductPageReqVO.java @@ -8,8 +8,6 @@ import lombok.ToString; @Schema(description = "管理后台 - IoT 产品分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class IotProductPageReqVO extends PageParam { @Schema(description = "产品名称", example = "李四") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java index 401f796f6..7228b23bb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; @@ -13,8 +11,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Schema(description = "管理后台 - IoT 数据桥梁分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class IotDataBridgePageReqVO extends PageParam { @Schema(description = "桥梁名称", example = "赵六") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java index 1db10a762..79c2c5cbe 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java @@ -9,7 +9,6 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - IoT 数据桥梁 Response VO") @Data -@ExcelIgnoreUnannotated public class IotDataBridgeRespVO { @Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java index 1b750f380..21745c4ab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/vo/IotStatisticsSummaryRespVO.java @@ -6,9 +6,9 @@ import lombok.Data; import java.util.Map; /** - * 管理后台 - Iot 统计 Response VO + * 管理后台 - IoT 统计 Response VO */ -@Schema(description = "管理后台 - Iot 统计 Response VO") +@Schema(description = "管理后台 - IoT 统计 Response VO") @Data public class IotStatisticsSummaryRespVO { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java index 89b162db9..2afad898b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java @@ -11,7 +11,7 @@ import lombok.Data; import java.util.List; /** - * IOT 产品物模型中的参数 + * IoT 产品物模型中的参数 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java index 447eb6e9a..8064b10e5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java @@ -6,13 +6,9 @@ import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; @Schema(description = "管理后台 - IoT 产品物模型分页 Request VO") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) public class IotThingModelPageReqVO extends PageParam { @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index 4c52031fe..9633d2feb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -23,8 +23,6 @@ import java.util.Set; @TableName(value = "iot_device", autoResultMap = true) @KeySequence("iot_device_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceGroupDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceGroupDO.java index 44c471216..7865a4424 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceGroupDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceGroupDO.java @@ -14,8 +14,6 @@ import lombok.*; @TableName("iot_device_group") @KeySequence("iot_device_group_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java index af5d8ac35..fa56f6938 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java @@ -16,8 +16,6 @@ import lombok.*; @TableName(value = "iot_ota_firmware", autoResultMap = true) @KeySequence("iot_ota_firmware_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java index 52f6d8375..ff4f0e7a0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java @@ -17,8 +17,6 @@ import java.time.LocalDateTime; @TableName(value = "iot_ota_upgrade_record", autoResultMap = true) @KeySequence("iot_ota_upgrade_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java index 6cc80e2b7..221bdc56c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java @@ -18,8 +18,6 @@ import java.util.List; @TableName(value = "iot_ota_upgrade_task", autoResultMap = true) @KeySequence("iot_ota_upgrade_task_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java index 69b738391..cb247fc30 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginConfigDO.java @@ -17,8 +17,6 @@ import lombok.*; @TableName("iot_plugin_config") @KeySequence("iot_plugin_config_seq") @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java index c64fe86c6..34abe893e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java @@ -16,8 +16,6 @@ import java.time.LocalDateTime; @TableName("iot_plugin_instance") @KeySequence("iot_plugin_instance_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductCategoryDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductCategoryDO.java index a6510488c..174342afb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductCategoryDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductCategoryDO.java @@ -14,8 +14,6 @@ import lombok.*; @TableName("iot_product_category") @KeySequence("iot_product_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java index 37c7be44b..3caebbccb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java @@ -14,8 +14,6 @@ import lombok.*; @TableName("iot_product") @KeySequence("iot_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java index 94734a2d3..c6a2390ac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java @@ -20,8 +20,6 @@ import java.util.List; @TableName("iot_alert_config") @KeySequence("iot_alert_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java index fbcf1fe79..840111078 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java @@ -18,8 +18,6 @@ import lombok.*; @TableName("iot_alert_record") @KeySequence("iot_alert_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java index 5697007b3..fed429872 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java @@ -20,8 +20,6 @@ import lombok.*; @TableName(value = "iot_data_bridge", autoResultMap = true) @KeySequence("iot_data_bridge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index 3c6ae6288..f50101a4e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -27,8 +27,6 @@ import java.util.Map; @TableName("iot_rule_scene") @KeySequence("iot_rule_scene_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java index 8591e1539..5e5d8200f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -74,10 +74,10 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX selectUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java index bd4d258f7..d09dac72d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; /** - * Iot Redis Key 枚举类 + * IoT Redis Key 枚举类 * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java index c3855fbfe..11d5d96be 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/device/IotDeviceProducer.java @@ -7,7 +7,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; /** - * Iot 设备相关消息的 Producer + * IoT 设备相关消息的 Producer * * @author alwayssuper * @since 2024/12/17 16:35 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java index a673b538e..c7b921c04 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneAction.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; import javax.annotation.Nullable; /** - * IOT 规则场景的场景执行器接口 + * IoT 规则场景的场景执行器接口 * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java index 08b6149c3..e31f40dd8 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.plugin.common.pojo; import lombok.Data; import lombok.experimental.Accessors; -// TODO @芋艿:1)后续考虑,要不要叫 Iot 网关之类的 Response;2)包名 pojo +// TODO @芋艿:1)后续考虑,要不要叫 IoT 网关之类的 Response;2)包名 pojo /** * IoT 标准协议响应实体类 *

diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 17403fef8..efd53c84a 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -46,11 +46,11 @@ - - cn.iocoder.boot - yudao-module-bpm-biz - ${revision} - + + + + + @@ -109,11 +109,11 @@ - - cn.iocoder.boot - yudao-module-iot-biz - ${revision} - + + + + + diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java index f0e387833..a9ed8fbf4 100644 --- a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java +++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java @@ -73,7 +73,7 @@ public class DefaultController { @RequestMapping(value = { "/admin-api/iot/**"}) public CommonResult iot404() { return CommonResult.error(NOT_IMPLEMENTED.getCode(), - "[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + "[IoT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]"); } /** diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index b4447b07f..c98a3277b 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -66,7 +66,7 @@ spring: url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true username: root password: 123456 - tdengine: # IOT 数据库 + tdengine: # IoT 数据库 lazy: true # 开启懒加载,保证启动速度 url: jdbc:TAOS-RS://chaojiniu.top:6041/ruoyi_vue_pro driver-class-name: com.taosdata.jdbc.rs.RestfulDriver From b6c7937aebe7d0d7b216e7735eea543e97e1c683 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 16 Mar 2025 22:40:41 +0800 Subject: [PATCH 226/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9AOTA=20=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rule/vo/databridge/IotDataBridgePageReqVO.java | 5 ++++- .../admin/rule/vo/databridge/IotDataBridgeRespVO.java | 3 +-- .../databridge/config/IotDataBridgeAbstractConfig.java | 2 +- .../vo/databridge/config/IotDataBridgeHttpConfig.java | 2 +- .../databridge/config/IotDataBridgeKafkaMQConfig.java | 2 +- .../vo/databridge/config/IotDataBridgeMqttConfig.java | 2 +- .../databridge/config/IotDataBridgeRabbitMQConfig.java | 2 +- .../config/IotDataBridgeRedisStreamMQConfig.java | 3 ++- .../databridge/config/IotDataBridgeRocketMQConfig.java | 2 +- .../iot/controller/admin/rule/vo/package-info.java | 1 + .../admin/statistics/IotStatisticsController.java | 6 ++++-- .../admin/thingmodel/model/ThingModelEvent.java | 2 +- .../admin/thingmodel/model/ThingModelProperty.java | 2 +- .../admin/thingmodel/model/ThingModelService.java | 2 +- .../model/dataType/ThingModelArrayDataSpecs.java | 10 +++++----- .../model/dataType/ThingModelBoolOrEnumDataSpecs.java | 9 +++++---- .../thingmodel/model/dataType/ThingModelDataSpecs.java | 2 +- .../model/dataType/ThingModelDateOrTextDataSpecs.java | 4 ++-- .../model/dataType/ThingModelNumericDataSpec.java | 4 ++-- .../model/dataType/ThingModelStructDataSpecs.java | 4 ++-- .../iot/service/device/data/IotDeviceLogService.java | 1 + 21 files changed, 39 insertions(+), 31 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java index 7228b23bb..e4dc36ef9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; @@ -16,7 +18,8 @@ public class IotDataBridgePageReqVO extends PageParam { @Schema(description = "桥梁名称", example = "赵六") private String name; - @Schema(description = "桥梁状态", example = "2") + @Schema(description = "桥梁状态", example = "1") + @InEnum(CommonStatusEnum.class) private Integer status; @Schema(description = "创建时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java index 79c2c5cbe..38e04b2eb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -20,7 +19,7 @@ public class IotDataBridgeRespVO { @Schema(description = "桥梁描述", example = "随便") private String description; - @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer status; @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java index 16481193f..527e79b35 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Data; /** - * 抽象类 IotDataBridgeConfig + * IoT IotDataBridgeConfig 抽象类 * * 用于表示数据桥梁配置数据的通用类型,根据具体的 "type" 字段动态映射到对应的子类 * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java index 9711cb6ec..eca35c76e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java @@ -5,7 +5,7 @@ import lombok.Data; import java.util.Map; /** - * HTTP 配置 + * IoT HTTP 配置 {@link IotDataBridgeAbstractConfig} 实现类 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java index cbc37cd69..1201214d1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; import lombok.Data; /** - * Kafka 配置 + * IoT Kafka 配置 {@link IotDataBridgeAbstractConfig} 实现类 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java index c437898c2..448b21501 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; import lombok.Data; /** - * MQTT 配置 + * IoT MQTT 配置 {@link IotDataBridgeAbstractConfig} 实现类 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java index 40e72f14c..2c247d1d5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; import lombok.Data; /** - * RabbitMQ 配置 + * IoT RabbitMQ 配置 {@link IotDataBridgeAbstractConfig} 实现类 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java index 288b772a0..3c9bb330f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamMQConfig.java @@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; import lombok.Data; +// TODO @puhui999:MQ 可以去掉哈。stream 更精准 /** - * Redis Stream MQ 配置 + * IoT Redis Stream 配置 {@link IotDataBridgeAbstractConfig} 实现类 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java index 791d36250..e23e3061a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; import lombok.Data; /** - * RocketMQ 配置 + * IoT RocketMQ 配置 {@link IotDataBridgeAbstractConfig} 实现类 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/package-info.java index a977d86e9..f397e0acd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/package-info.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/package-info.java @@ -1 +1,2 @@ +// TODO @芋艿:占位 package cn.iocoder.yudao.module.iot.controller.admin.rule.vo; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java index 31cc5121a..a9c195656 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java @@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; import java.util.Map; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.*; + @Tag(name = "管理后台 - IoT 数据统计") @RestController @RequestMapping("/iot/statistics") @@ -61,7 +63,7 @@ public class IotStatisticsController { respVO.setDeviceOnlineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.ONLINE.getState(), 0L)); respVO.setDeviceOfflineCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.OFFLINE.getState(), 0L)); respVO.setDeviceInactiveCount(deviceCountMap.getOrDefault(IotDeviceStateEnum.INACTIVE.getState(), 0L)); - return CommonResult.success(respVO); + return success(respVO); } // TODO @super:要不干掉 IotStatisticsReqVO 参数,直接使用 @RequestParam 接收,简单一些。 @@ -69,7 +71,7 @@ public class IotStatisticsController { @Operation(summary = "获取 IoT 设备上下行消息数据统计") public CommonResult getIotStatisticsDeviceMessageSummary( @Valid IotStatisticsReqVO reqVO) { - return CommonResult.success(new IotStatisticsDeviceMessageSummaryRespVO() + return success(new IotStatisticsDeviceMessageSummaryRespVO() .setDownstreamCounts(deviceLogService.getDeviceLogUpCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())) .setDownstreamCounts((deviceLogService.getDeviceLogDownCountByHour(null, reqVO.getStartTime(), reqVO.getEndTime())))); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index d3f0d33c5..06cc43809 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -10,7 +10,7 @@ import lombok.Data; import java.util.List; /** - * 物模型中的事件 + * IoT 物模型中的事件 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java index 395c8611e..4b9a05a0e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java @@ -11,7 +11,7 @@ import lombok.Data; import java.util.List; /** - * 物模型中的属性 + * IoT 物模型中的属性 * * dataSpecs 和 dataSpecsList 之中必须传入且只能传入一个 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java index 7f97b9402..c98acd824 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java @@ -10,7 +10,7 @@ import lombok.Data; import java.util.List; /** - * 物模型中的服务 + * IoT 物模型中的服务 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java index b8b1a2975..50011aabf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java @@ -7,25 +7,25 @@ import lombok.EqualsAndHashCode; import java.util.List; /** - * 物模型数据类型为数组的 DataSpec 定义 + * IoT 物模型数据类型为数组的 DataSpec 定义 * * @author HUIHUI */ @Data @EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 public class ThingModelArrayDataSpecs extends ThingModelDataSpecs { /** - * 数组中的元素个数。 + * 数组中的元素个数 */ private Integer size; /** - * 数组中的元素的数据类型。可选值:struct、int、float、double 或 text。 + * 数组中的元素的数据类型。可选值:struct、int、float、double 或 text */ private String childDataType; /** - * 数据类型(childDataType)为列表型 struct 的数据规范存储在 dataSpecsList 中。 + * 数据类型(childDataType)为列表型 struct 的数据规范存储在 dataSpecsList 中 * 此时 struct 取值范围为:int、float、double、text、date、enum、bool */ private List dataSpecsList; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java index 3ab624cab..925bc6719 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java @@ -5,7 +5,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; /** - * 物模型数据类型为布尔型或枚举型的 DataSpec 定义 + * IoT 物模型数据类型为布尔型或枚举型的 DataSpec 定义 * * 数据类型,取值为 bool 或 enum。 * @@ -13,13 +13,14 @@ import lombok.EqualsAndHashCode; */ @Data @EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 public class ThingModelBoolOrEnumDataSpecs extends ThingModelDataSpecs { + // TODO @puhui999:要不写下参数校验?这样,注释可以简洁一点 /** * 枚举项的名称。 - * 可包含中文、大小写英文字母、数字、下划线(_)和短划线(-)。 - * 必须以中文、英文字母或数字开头,长度不超过 20 个字符。 + * 可包含中文、大小写英文字母、数字、下划线(_)和短划线(-) + * 必须以中文、英文字母或数字开头,长度不超过 20 个字符 */ private String name; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java index 78bfd02dd..d9fc12dd9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Data; /** - * 抽象类 ThingModelDataSpecs + * IoT ThingModelDataSpecs 抽象类 * * 用于表示物模型数据的通用类型,根据具体的 "dataType" 字段动态映射到对应的子类。 * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java index 9d2c88ae1..62500bc56 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java @@ -5,7 +5,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; /** - * 物模型数据类型为时间型或文本型的 DataSpec 定义 + * IoT 物模型数据类型为时间型或文本型的 DataSpec 定义 * * 数据类型,取值为 date 或 text。 * @@ -13,7 +13,7 @@ import lombok.EqualsAndHashCode; */ @Data @EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java index b65d606ac..8d0827c01 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java @@ -5,7 +5,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; /** - * 物模型数据类型为数值的 DataSpec 定义 + * IoT 物模型数据类型为数值的 DataSpec 定义 * * 数据类型,取值为 int、float 或 double。 * @@ -13,7 +13,7 @@ import lombok.EqualsAndHashCode; */ @Data @EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 public class ThingModelNumericDataSpec extends ThingModelDataSpecs { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java index 8fcaefdc5..6d483eeaa 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java @@ -8,13 +8,13 @@ import lombok.EqualsAndHashCode; import java.util.List; /** - * 物模型数据类型为 struct 的 DataSpec 定义 + * IoT 物模型数据类型为 struct 的 DataSpec 定义 * * @author HUIHUI */ @Data @EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复。 +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 public class ThingModelStructDataSpecs extends ThingModelDataSpecs { /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java index 468599e1c..b79732911 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDeviceLogService.java @@ -47,6 +47,7 @@ public interface IotDeviceLogService { */ Long getDeviceLogCount(@Nullable LocalDateTime createTime); + // TODO @super:deviceKey 是不是用不上哈? /** * 获得每个小时设备上行消息数量统计 * From a9733b4d2af6caf65445ce2ce4aac3295c106618 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 16 Mar 2025 23:11:04 +0800 Subject: [PATCH 227/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=95=B4=E4=BD=93=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotPluginCommonAutoConfiguration.java | 5 +- .../IotDeviceConfigSetVertxHandler.java | 10 ++- .../IotDeviceOtaUpgradeVertxHandler.java | 11 ++-- .../common/pojo/IotStandardResponse.java | 3 +- .../common/util/IotPluginCommonUtils.java | 1 + .../yudao-module-iot-plugin-emqx/pom.xml | 1 + .../IotPluginEmqxAutoConfiguration.java | 4 +- .../emqx/config/IotPluginEmqxProperties.java | 9 +-- .../IotDeviceDownstreamHandlerImpl.java | 9 ++- .../upstream/IotDeviceUpstreamServer.java | 62 +++++++++---------- .../router/IotDeviceAuthVertxHandler.java | 3 +- .../router/IotDeviceMqttMessageHandler.java | 2 +- .../router/IotDeviceWebhookVertxHandler.java | 5 +- .../http/config/IotHttpVertxPlugin.java | 4 +- .../router/IotDeviceUpstreamVertxHandler.java | 35 ++++++----- .../yudao-module-iot-plugin-mqtt/pom.xml | 1 + .../yudao/module/iot/plugin/MqttPlugin.java | 1 + .../iot/plugin/MqttServerExtension.java | 1 + 18 files changed, 83 insertions(+), 84 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java index 111189875..ba7d56fe6 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java @@ -43,8 +43,9 @@ public class IotPluginCommonAutoConfiguration { } @Bean(initMethod = "init", destroyMethod = "stop") - public IotPluginInstanceHeartbeatJob pluginInstanceHeartbeatJob( - IotDeviceUpstreamApi deviceDataApi, IotDeviceDownstreamServer deviceDownstreamServer, IotPluginCommonProperties commonProperties) { + public IotPluginInstanceHeartbeatJob pluginInstanceHeartbeatJob(IotDeviceUpstreamApi deviceDataApi, + IotDeviceDownstreamServer deviceDownstreamServer, + IotPluginCommonProperties commonProperties) { return new IotPluginInstanceHeartbeatJob(deviceDataApi, deviceDownstreamServer, commonProperties); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java index b9bd4a52f..1693f128d 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.java @@ -25,6 +25,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC @RequiredArgsConstructor public class IotDeviceConfigSetVertxHandler implements Handler { + // TODO @haohao:是不是可以把 PATH、Method 所有的,抽到一个枚举类里?因为 topic、path、method 相当于不同的几个表达? public static final String PATH = "/sys/:productKey/:deviceName/thing/service/config/set"; public static final String METHOD = "thing.service.config.set"; @@ -57,12 +58,9 @@ public class IotDeviceConfigSetVertxHandler implements Handler { CommonResult result = deviceDownstreamHandler.setDeviceConfig(reqDTO); // 3. 响应结果 - IotStandardResponse response; - if (result.isSuccess()) { - response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); - } else { - response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); - } + IotStandardResponse response = result.isSuccess() ? + IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()) + : IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) 配置设置异常]", reqDTO, e); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java index a49b84acc..b417229aa 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceOtaUpgradeVertxHandler.java @@ -62,15 +62,14 @@ public class IotDeviceOtaUpgradeVertxHandler implements Handler CommonResult result = deviceDownstreamHandler.upgradeDeviceOta(reqDTO); // 3. 响应结果 - IotStandardResponse response; - if (result.isSuccess()) { - response = IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()); - } else { - response = IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); - } + // TODO @haohao:可以考虑 IotStandardResponse.of(requestId, method, CommonResult) + IotStandardResponse response = result.isSuccess() ? + IotStandardResponse.success(reqDTO.getRequestId(), METHOD, result.getData()) + :IotStandardResponse.error(reqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][请求参数({}) OTA 升级异常]", reqDTO, e); + // TODO @haohao:可以考虑 IotStandardResponse.of(requestId, method, ErrorCode) IotStandardResponse errorResponse = IotStandardResponse.error( reqDTO.getRequestId(), METHOD, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java index e31f40dd8..131eb1b9c 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/pojo/IotStandardResponse.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin.common.pojo; import lombok.Data; -import lombok.experimental.Accessors; // TODO @芋艿:1)后续考虑,要不要叫 IoT 网关之类的 Response;2)包名 pojo /** @@ -12,7 +11,6 @@ import lombok.experimental.Accessors; * @author haohao */ @Data -@Accessors(chain = true) public class IotStandardResponse { /** @@ -92,4 +90,5 @@ public class IotStandardResponse { .setMethod(method) .setVersion("1.0"); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java index 2e09c3c5c..34c6c0fe2 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java @@ -72,4 +72,5 @@ public class IotPluginCommonUtils { .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) .end(JsonUtils.toJsonString(response)); } + } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml index 818c08b33..8620ecaa6 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml @@ -15,6 +15,7 @@ 1.0.0 ${project.artifactId} + 物联网 插件模块 - emqx 插件 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java index 382bb9ecf..e1d11504c 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxAutoConfiguration.java @@ -14,7 +14,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** - * IoT 插件 Emqx 的专用自动配置类 + * IoT 插件 EMQX 的专用自动配置类 * * @author haohao */ @@ -34,7 +34,7 @@ public class IotPluginEmqxAutoConfiguration { .setClientId("yudao-iot-downstream-" + IdUtil.fastSimpleUUID()) .setUsername(emqxProperties.getMqttUsername()) .setPassword(emqxProperties.getMqttPassword()) - .setSsl(emqxProperties.isMqttSsl()); + .setSsl(emqxProperties.getMqttSsl()); return MqttClient.create(vertx, options); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java index 4117e7182..219fe0360 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/config/IotPluginEmqxProperties.java @@ -14,6 +14,8 @@ import org.springframework.validation.annotation.Validated; @Data public class IotPluginEmqxProperties { + // TODO @haohao:参数校验,加下,啊哈 + /** * 服务主机 */ @@ -21,12 +23,11 @@ public class IotPluginEmqxProperties { /** * 服务端口 */ - private int mqttPort; + private Integer mqttPort; /** * 服务用户名 */ private String mqttUsername; - /** * 服务密码 */ @@ -34,7 +35,7 @@ public class IotPluginEmqxProperties { /** * 是否启用 SSL */ - private boolean mqttSsl; + private Boolean mqttSsl; /** * 订阅的主题列表 @@ -44,6 +45,6 @@ public class IotPluginEmqxProperties { /** * 认证端口 */ - private int authPort; + private Integer authPort; } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java index c1e64afb9..f5c19224a 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/downstream/IotDeviceDownstreamHandlerImpl.java @@ -25,6 +25,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle private static final String SYS_TOPIC_PREFIX = "/sys/"; + // TODO @haohao:是不是可以类似 IotDeviceConfigSetVertxHandler 的建议,抽到统一的枚举类 // TODO @haohao:讨论,感觉 mqtt 和 http,可以做个相对统一的格式哈。;回复 都使用 Alink 格式,方便后续扩展。 // 设备服务调用 标准 JSON // 请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier} @@ -63,7 +64,6 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle // 构建请求消息 String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); JSONObject request = buildServiceRequest(requestId, reqDTO.getIdentifier(), reqDTO.getParams()); - // 发送消息 publishMessage(topic, request); @@ -82,9 +82,8 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle @Override public CommonResult setDeviceProperty(IotDevicePropertySetReqDTO reqDTO) { - log.info("[setProperty][开始设置设备属性][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); - // 验证参数 + log.info("[setProperty][开始设置设备属性][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); if (reqDTO.getProductKey() == null || reqDTO.getDeviceName() == null) { log.error("[setProperty][参数不完整][reqDTO: {}]", JSONUtil.toJsonStr(reqDTO)); return CommonResult.error(MQTT_TOPIC_ILLEGAL.getCode(), MQTT_TOPIC_ILLEGAL.getMsg()); @@ -96,7 +95,6 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle // 构建请求消息 String requestId = reqDTO.getRequestId() != null ? reqDTO.getRequestId() : generateRequestId(); JSONObject request = buildPropertySetRequest(requestId, reqDTO.getProperties()); - // 发送消息 publishMessage(topic, request); @@ -132,6 +130,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + PROPERTY_SET_TOPIC; } + // TODO @haohao:这个,后面搞个对象,会不会好点哈? /** * 构建服务调用请求 */ @@ -168,7 +167,7 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle } /** - * 生成请求ID + * 生成请求 ID */ private String generateRequestId() { return IdUtil.fastSimpleUUID(); diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java index 040985ba9..8911a76a8 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/IotDeviceUpstreamServer.java @@ -36,10 +36,6 @@ public class IotDeviceUpstreamServer { * 连接超时时间(毫秒) */ private static final int CONNECTION_TIMEOUT_MS = 10000; - /** - * 主题分隔符 - */ - private static final String TOPIC_SEPARATOR = ","; /** * 默认 QoS 级别 */ @@ -84,42 +80,40 @@ public class IotDeviceUpstreamServer { */ public void start() { if (isRunning) { - log.warn("服务已经在运行中,请勿重复启动"); + log.warn("[start][服务已经在运行中,请勿重复启动]"); return; } - - log.info("[start] 开始启动服务"); + log.info("[start][开始启动服务]"); // 1. 启动 HTTP 服务器 CompletableFuture httpFuture = server.listen(emqxProperties.getAuthPort()) .toCompletionStage() .toCompletableFuture() - .thenAccept(v -> log.info("[start] HTTP服务器启动完成,端口: {}", server.actualPort())); + .thenAccept(v -> log.info("[start][HTTP服务器启动完成,端口: {}]", server.actualPort())); // 2. 连接 MQTT Broker CompletableFuture mqttFuture = connectMqtt() .toCompletionStage() .toCompletableFuture() .thenAccept(v -> { - // 3. 添加 MQTT 断开重连监听器 + // 2.1 添加 MQTT 断开重连监听器 client.closeHandler(closeEvent -> { - log.warn("[closeHandler] MQTT连接已断开,准备重连"); + log.warn("[closeHandler][MQTT连接已断开,准备重连]"); reconnectWithDelay(); }); - - // 4. 设置 MQTT 消息处理器 + // 2. 设置 MQTT 消息处理器 setupMessageHandler(); }); - // 等待所有服务启动完成 + // 3. 等待所有服务启动完成 CompletableFuture.allOf(httpFuture, mqttFuture) .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) .whenComplete((result, error) -> { if (error != null) { - log.error("[start] 服务启动失败", error); + log.error("[start][服务启动失败]", error); } else { isRunning = true; - log.info("[start] 所有服务启动完成"); + log.info("[start][所有服务启动完成]"); } }); } @@ -129,7 +123,7 @@ public class IotDeviceUpstreamServer { */ private void setupMessageHandler() { client.publishHandler(mqttMessageHandler::handle); - log.debug("[setupMessageHandler] MQTT消息处理器设置完成"); + log.debug("[setupMessageHandler][MQTT消息处理器设置完成]"); } /** @@ -137,12 +131,12 @@ public class IotDeviceUpstreamServer { */ private void reconnectWithDelay() { if (!isRunning) { - log.info("[reconnectWithDelay] 服务已停止,不再尝试重连"); + log.info("[reconnectWithDelay][服务已停止,不再尝试重连]"); return; } vertx.setTimer(RECONNECT_DELAY_MS, id -> { - log.info("[reconnectWithDelay] 开始重新连接MQTT"); + log.info("[reconnectWithDelay][开始重新连接 MQTT]"); connectMqtt(); }); } @@ -155,28 +149,28 @@ public class IotDeviceUpstreamServer { private Future connectMqtt() { return client.connect(emqxProperties.getMqttPort(), emqxProperties.getMqttHost()) .compose(connAck -> { - log.info("[connectMqtt] MQTT客户端连接成功"); + log.info("[connectMqtt][MQTT客户端连接成功]"); return subscribeToTopics(); }) - .recover(err -> { - log.error("[connectMqtt] 连接MQTT Broker失败: {}", err.getMessage()); + .recover(error -> { + log.error("[connectMqtt][连接MQTT Broker失败:]", error); reconnectWithDelay(); - return Future.failedFuture(err); + return Future.failedFuture(error); }); } /** * 订阅设备上行消息主题 * - * @return 订阅结果的Future + * @return 订阅结果的 Future */ private Future subscribeToTopics() { String[] topics = emqxProperties.getMqttTopics(); if (ArrayUtil.isEmpty(topics)) { - log.warn("[subscribeToTopics] 未配置MQTT主题,跳过订阅"); + log.warn("[subscribeToTopics][未配置MQTT主题,跳过订阅]"); return Future.succeededFuture(); } - log.info("[subscribeToTopics] 开始订阅设备上行消息主题"); + log.info("[subscribeToTopics][开始订阅设备上行消息主题]"); Future compositeFuture = Future.succeededFuture(); for (String topic : topics) { @@ -186,11 +180,11 @@ public class IotDeviceUpstreamServer { } compositeFuture = compositeFuture.compose(v -> client.subscribe(trimmedTopic, DEFAULT_QOS.value()) .map(ack -> { - log.info("[subscribeToTopics] 成功订阅主题: {}", trimmedTopic); + log.info("[subscribeToTopics][成功订阅主题: {}]", trimmedTopic); return null; }) - .recover(err -> { - log.error("[subscribeToTopics] 订阅主题失败: {}, 原因: {}", trimmedTopic, err.getMessage()); + .recover(error -> { + log.error("[subscribeToTopics][订阅主题失败: {}]", trimmedTopic, error); return Future.succeededFuture(); // 继续订阅其他主题 })); } @@ -202,10 +196,10 @@ public class IotDeviceUpstreamServer { */ public void stop() { if (!isRunning) { - log.warn("[stop] 服务未运行,无需停止"); + log.warn("[stop][服务未运行,无需停止]"); return; } - log.info("[stop] 开始关闭服务"); + log.info("[stop][开始关闭服务]"); isRunning = false; try { @@ -224,14 +218,14 @@ public class IotDeviceUpstreamServer { .orTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) .whenComplete((result, error) -> { if (error != null) { - log.error("[stop] 服务关闭过程中发生异常", error); + log.error("[stop][服务关闭过程中发生异常]", error); } else { - log.info("[stop] 所有服务关闭完成"); + log.info("[stop][所有服务关闭完成]"); } }); } catch (Exception e) { - log.error("[stop] 关闭服务异常", e); - throw new RuntimeException("关闭IoT设备上行服务失败", e); + log.error("[stop][关闭服务异常]", e); + throw new RuntimeException("关闭 IoT 设备上行服务失败", e); } } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java index fcb228615..e9206d5b6 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceAuthVertxHandler.java @@ -15,7 +15,7 @@ import java.util.Collections; /** * IoT EMQX 连接认证的 Vert.x Handler * - * EMQX HTTP + * 参考:EMQX HTTP * * 注意:该处理器需要返回特定格式:{"result": "allow"} 或 {"result": "deny"}, * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类 @@ -31,7 +31,6 @@ public class IotDeviceAuthVertxHandler implements Handler { private final IotDeviceUpstreamApi deviceUpstreamApi; @Override - @SuppressWarnings("unchecked") public void handle(RoutingContext routingContext) { try { // 构建认证请求 DTO diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java index 6cf8d84c5..00fa1b96d 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceMqttMessageHandler.java @@ -23,7 +23,7 @@ import java.util.Map; /** * IoT 设备 MQTT 消息处理器 * - * 参考:"设备属性、事件、服务"> + * 参考:设备属性、事件、服务 */ @Slf4j public class IotDeviceMqttMessageHandler { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java index 93fb01bc0..21b49e097 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/emqx/upstream/router/IotDeviceWebhookVertxHandler.java @@ -18,7 +18,7 @@ import java.util.Collections; /** * IoT EMQX Webhook 事件处理的 Vert.x Handler * - * EMQX Webhook + * 参考:EMQX Webhook * * 注意:该处理器需要返回特定格式:{"result": "success"} 或 {"result": "error"}, * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。 @@ -51,8 +51,7 @@ public class IotDeviceWebhookVertxHandler implements Handler { handleClientDisconnected(clientId, username); break; default: - log.info("[handle][未处理的 Webhook 事件] event={}, clientId={}, username={}", event, clientId, - username); + log.info("[handle][未处理的 Webhook 事件] event={}, clientId={}, username={}", event, clientId, username); break; } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java index 674980d00..f704c1844 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java @@ -23,10 +23,8 @@ public class IotHttpVertxPlugin extends SpringPlugin { public void start() { log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动开始...]"); try { - // 1. 获取插件上下文 ApplicationContext pluginContext = getApplicationContext(); Assert.notNull(pluginContext, "pluginContext 不能为空"); - log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动成功...]"); } catch (Exception e) { log.error("[HttpVertxPlugin][HttpVertxPlugin 插件开启动异常...]", e); @@ -43,6 +41,7 @@ public class IotHttpVertxPlugin extends SpringPlugin { } } + // TODO @芋艿:思考下,未来要不要。。。 @Override protected ApplicationContext createApplicationContext() { // 创建插件自己的 ApplicationContext @@ -52,6 +51,7 @@ public class IotHttpVertxPlugin extends SpringPlugin { // 继续使用插件自己的 ClassLoader 以加载插件内部的类 pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); // 扫描当前插件的自动配置包 + // TODO @芋艿:后续看看,怎么配置类包 pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.http.config"); pluginContext.refresh(); return pluginContext; diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java index f6c7cc3a2..79d465ea0 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java @@ -34,6 +34,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC @Slf4j public class IotDeviceUpstreamVertxHandler implements Handler { + // TODO @haohao:要不要类似 IotDeviceConfigSetVertxHandler 写的,把这些 PATH、METHOD 之类的抽走 /** * 属性上报路径 */ @@ -49,6 +50,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler { private final IotDeviceUpstreamApi deviceUpstreamApi; + // TODO @haohao:要不要分成多个 Handler?每个只解决一个问题哈。 @Override public void handle(RoutingContext routingContext) { String path = routingContext.request().path(); @@ -102,7 +104,6 @@ public class IotDeviceUpstreamVertxHandler implements Handler { IotPluginCommonUtils.writeJsonResponse(routingContext, response); } catch (Exception e) { log.error("[handle][处理上行请求异常] path={}", path, e); - // 构建错误响应 String method = path.contains("/property/") ? PROPERTY_METHOD : EVENT_METHOD_PREFIX + (routingContext.pathParams().containsKey("identifier") ? routingContext.pathParam("identifier") @@ -115,27 +116,28 @@ public class IotDeviceUpstreamVertxHandler implements Handler { /** * 更新设备状态 * - * @param productKey 产品Key + * @param productKey 产品 Key * @param deviceName 设备名称 */ private void updateDeviceState(String productKey, String deviceName) { - deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setState(IotDeviceStateEnum.ONLINE.getState())); + deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO() + .setRequestId(IdUtil.fastSimpleUUID()).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) + .setProductKey(productKey).setDeviceName(deviceName)).setState(IotDeviceStateEnum.ONLINE.getState())); } /** * 解析属性上报请求 * - * @param productKey 产品Key + * @param productKey 产品 Key * @param deviceName 设备名称 - * @param requestId 请求ID + * @param requestId 请求 ID * @param body 请求体 - * @return 属性上报请求DTO + * @return 属性上报请求 DTO */ @SuppressWarnings("unchecked") private IotDevicePropertyReportReqDTO parsePropertyReportRequest(String productKey, String deviceName, String requestId, JsonObject body) { // 按照标准 JSON 格式处理属性数据 Map properties = new HashMap<>(); - // 优先使用 params 字段,符合标准 Map params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() : null; if (params != null) { // 将标准格式的 params 转换为平台需要的 properties 格式 @@ -153,24 +155,25 @@ public class IotDeviceUpstreamVertxHandler implements Handler { } // 构建属性上报请求 DTO - return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setProperties(properties); + return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId) + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) + .setProductKey(productKey).setDeviceName(deviceName)).setProperties(properties); } /** * 解析事件上报请求 * - * @param productKey 产品Key + * @param productKey 产品K ey * @param deviceName 设备名称 * @param identifier 事件标识符 - * @param requestId 请求ID + * @param requestId 请求 ID * @param body 请求体 - * @return 事件上报请求DTO + * @return 事件上报请求 DTO */ private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, String requestId, JsonObject body) { - // 按照标准JSON格式处理事件参数 + // 按照标准 JSON 格式处理事件参数 Map params; - // 优先使用params字段,符合标准 - if (body.getJsonObject("params") != null) { + if (body.containsKey("params")) { params = body.getJsonObject("params").getMap(); } else { // 兼容旧格式 @@ -178,6 +181,8 @@ public class IotDeviceUpstreamVertxHandler implements Handler { } // 构建事件上报请求 DTO - return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); + return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId) + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) + .setProductKey(productKey).setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml index e007596dc..f1fba5059 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml @@ -14,6 +14,7 @@ yudao-module-iot-plugin-mqtt ${project.artifactId} + 物联网 插件模块 - mqtt 插件 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java index 54ff31f36..7883fa8b1 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.pf4j.Plugin; import org.pf4j.PluginWrapper; +// TODO @芋艿:暂未实现 @Slf4j public class MqttPlugin extends Plugin { diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java index 868d238ee..dd0c5da37 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java @@ -21,6 +21,7 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; +// TODO @芋艿:暂未实现 /** * 根据官方示例,整合常见 MQTT 功能到 PF4J 的 Extension 类中 */ From 638976dac81a7098b0e8d563379a05e7fd4d6c8b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 16 Mar 2025 23:15:32 +0800 Subject: [PATCH 228/228] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E6=95=B4=E4=BD=93=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../control/IotDeviceUpstreamServiceImpl.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java index 29e8096a9..6c80e75ac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java @@ -280,11 +280,11 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { sendDeviceMessage(message, device); } + // TODO @芋艿:后续需要考虑,http 的认证 @Override public boolean authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) { log.info("[authenticateEmqxConnection][认证 Emqx 连接: {}]", authReqDTO); - // 1. 校验设备是否存在 - // username 格式:${DeviceName}&${ProductKey} + // 1.1 校验设备是否存在。username 格式:${DeviceName}&${ProductKey} String[] usernameParts = authReqDTO.getUsername().split("&"); if (usernameParts.length != 2) { log.error("[authenticateEmqxConnection][认证失败,username 格式不正确]"); @@ -292,17 +292,19 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { } String deviceName = usernameParts[0]; String productKey = usernameParts[1]; - IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( - productKey, deviceName); + // 1.2 获得设备 + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(productKey, deviceName); if (device == null) { - log.error("[authenticateEmqxConnection][设备({}/{}) 不存在]", - productKey, deviceName); + log.error("[authenticateEmqxConnection][设备({}/{}) 不存在]", productKey, deviceName); return false; } + // TODO @haohao:需要记录,记录设备的最后时间 + // 2. 校验密码 String deviceSecret = device.getDeviceSecret(); String clientId = authReqDTO.getClientId(); MqttSignResult sign = MqttSignUtils.calculate(productKey, deviceName, deviceSecret, clientId); + // TODO 建议,先失败,return false; if (StrUtil.equals(sign.getPassword(), authReqDTO.getPassword())) { log.info("[authenticateEmqxConnection][认证成功]"); return true;