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/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 e1268b0035..7d9ac6a0d0 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 8e1ed3c236..c4f9d1f55d 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
@@ -4,24 +4,26 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
-
-import java.time.LocalDateTime;
-
+// 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;
@@ -34,7 +36,8 @@ public class IotDeviceDataSimulatorSaveReqVO {
@NotEmpty(message = "数据内容不能为空")
private String content;
+ // TODO @芋艿:需要讨论下,reportTime 到底以那个为准!
@Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
- private LocalDateTime reportTime;
+ 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
new file mode 100644
index 0000000000..a882a6d86a
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogPageReqVO.java
@@ -0,0 +1,33 @@
+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.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
+public class IotDeviceLogPageReqVO extends PageParam {
+
+ @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
+ @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
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
new file mode 100644
index 0000000000..48ea9b6989
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/deviceData/IotDeviceLogRespVO.java
@@ -0,0 +1,36 @@
+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 设备日志 Response VO")
+@Data
+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;
+
+ @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
+ private String type;
+
+ @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
+ private String subType;
+
+ @Schema(description = "日志内容", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String content;
+
+ @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime reportTime;
+
+ @Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime ts;
+
+}
\ 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 e71e4c484d..bc8d6c8fae 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/PluginInfoPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoPageReqVO.java
index 7d4677dd49..76f30ac99f 100644
--- 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
@@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
+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;
@@ -11,7 +13,8 @@ public class PluginInfoPageReqVO extends PageParam {
@Schema(description = "插件名称", example = "http")
private String name;
- @Schema(description = "状态")
+ @Schema(description = "状态", example = "1")
+ @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/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 514ba4f1f1..4291024699 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 9a98481306..25c0f6bcb7 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,12 +1,18 @@
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
public class PluginInfoSaveReqVO {
+ // TODO @haohao:新增的字段有点多,每个都需要哇?
+
+ // TODO @haohao:一些枚举字段,需要加枚举校验。例如说,deployType、status、type 等
+
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
private Long id;
@@ -35,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/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 d213329e29..e4913486d3 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 3652b36b94..dd77cfc5ee 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 4a30ed7915..dd811ee323 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,45 +17,52 @@ 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;
/**
* 上报时间戳
*/
- private DateTime reportTime;
+ private Long reportTime;
/**
* 时序时间
*/
- private DateTime ts;
-
+ private Long ts;
}
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 507b91f2a0..8b0ec95d14 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/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 b647c68730..ae70da37bb 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/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
index 228519fb65..9806ef17f3 100644
--- 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
@@ -4,6 +4,9 @@ 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 java.util.List;
+
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.*;
@@ -22,4 +25,10 @@ public interface PluginInfoMapper extends BaseMapperX {
.orderByDesc(PluginInfoDO::getId));
}
+ default List selectListByStatus(Integer status) {
+ return selectList(new LambdaQueryWrapperX()
+ .eq(PluginInfoDO::getStatus, status)
+ .orderByAsc(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/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 249082032d..4f773aa064 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/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 194218b7f8..9584262dff 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,15 +1,18 @@
package cn.iocoder.yudao.module.iot.dal.tdengine;
+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;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
/**
- * IoT 设备日志 Mapper
+ * IOT 设备日志数据 Mapper 接口
*
- * @author alwayssuper
+ * 基于 TDengine 实现设备日志的存储
*/
@Mapper
@TDengineDS
@@ -18,22 +21,58 @@ 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
+ /**
+ * 插入设备日志数据
+ *
+ * 如果子表不存在,会自动创建子表
+ *
+>>>>>>> deab8c1cc6bb7864d9c40e0c369f649f6f9bfa41
* @param log 设备日志数据
*/
void insert(@Param("log") IotDeviceLogDO log);
+ /**
+ * 获得设备日志分页
+ *
+ * @param reqVO 分页查询条件
+ * @return 设备日志列表
+ */
+ List selectPage(@Param("reqVO") IotDeviceLogPageReqVO reqVO);
+
+ /**
+ * 获得设备日志总数
+ *
+ * @param reqVO 查询条件
+ * @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 b04be11991..cbc6e88366 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/emq/callback/EmqxCallback.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java
index b466113f70..fbc6ffcdb3 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java
@@ -17,7 +17,7 @@ import org.springframework.stereotype.Component;
* @author ahh
*/
@Slf4j
-@Component
+//@Component
public class EmqxCallback implements MqttCallbackExtended {
@Lazy
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java
index de24585b09..577a808dc0 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java
@@ -19,7 +19,7 @@ import org.springframework.stereotype.Component;
*/
@Slf4j
@Data
-@Component
+//@Component
public class EmqxClient {
@Resource
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java
index 9d128903c4..8e32c185d4 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java
@@ -12,8 +12,8 @@ import org.springframework.stereotype.Component;
* @author ahh
*/
@Data
-@Component
-@ConfigurationProperties("iot.emq")
+//@Component
+//@ConfigurationProperties("iot.emq")
public class MqttConfig {
/**
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 46217a22bb..3c21a55ca8 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/emq/start/EmqxStart.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java
index 0c316b66c9..64265fdc3c 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java
@@ -13,7 +13,7 @@ import org.springframework.stereotype.Component;
*
* @author ahh
*/
-@Component
+//@Component
public class EmqxStart implements ApplicationRunner {
@Resource
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
new file mode 100644
index 0000000000..2cb688cfa5
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.iot.framework.plugin;
+
+import java.util.List;
+
+import javax.annotation.Resource;
+
+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;
+
+@Component
+@Slf4j
+public class PluginStart implements ApplicationRunner {
+
+ @Resource
+ private PluginInfoService 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/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 4f1d5e3e29..374e3856a1 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/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 e14fa2948c..e0057e1808 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/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 ca8398e51c..d32148b47c 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;
@@ -23,7 +22,8 @@ public class PluginInstancesJob {
@Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
public void updatePluginInstances() {
TenantUtils.executeIgnore(() -> {
- pluginInstanceService.updatePluginInstances();
+ pluginInstanceService.reportPluginInstances();
});
}
+
}
\ 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 0000000000..c7a0500030
--- /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 0000000000..90ce2a3875
--- /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,100 @@
+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-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 166727dec7..1a3b48503c 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
@@ -1,6 +1,9 @@
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.IotDeviceDataSimulatorSaveReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
/**
* IoT 设备日志数据 Service 接口
@@ -10,13 +13,27 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDevi
public interface IotDeviceLogDataService {
/**
- * 初始化 TDengine 表
+ * 初始化 TDengine 超级表
+ *
+ *系统启动时,会自动初始化一次
*/
void initTDengineSTable();
/**
- * 模拟设备创建设备日志
- * @param simulatorReqVO 模拟设备信息
+ * 插入设备日志
+ *
+ * 当该设备第一次插入日志时,自动创建该设备的设备日志子表
+ *
+ * @param simulatorReqVO 设备日志模拟数据
*/
void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO);
+
+ /**
+ * 获得设备日志分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 设备日志分页
+ */
+ PageResult getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO);
+
}
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 528477cf90..d0659e5073 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,8 +1,9 @@
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;
+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 jakarta.annotation.Resource;
@@ -10,7 +11,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
-import java.time.LocalDateTime;
+import java.util.List;
/**
* IoT 设备日志数据 Service 实现了
@@ -19,27 +20,43 @@ import java.time.LocalDateTime;
*/
@Service
@Slf4j
+@Validated
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) {
+ // 1. 转换请求对象为 DO
IotDeviceLogDO iotDeviceLogDO = BeanUtils.toBean(simulatorReqVO, IotDeviceLogDO.class);
- iotDeviceLogDO.setTs(DateTime.now());
+
+ // 2. 处理时间字段
+ // TODO @super:一次性的字段,不用单独给个变量
+ long currentTime = System.currentTimeMillis();
+ // 2.1 设置时序时间为当前时间
+ 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) {
+ // 查询数据
+ List list = iotDeviceLogDataMapper.selectPage(pageReqVO);
+ Long total = iotDeviceLogDataMapper.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/IotDevicePropertyDataService.java
index 08375cb092..a882b5d6cb 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 9d2f43ba7b..0f9523414e 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,10 +15,9 @@ 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.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;
@@ -57,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 芋艿:怎么映射!!!!
@@ -110,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;
}
@@ -131,20 +130,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/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 0000000000..22ebe8b4f2
--- /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/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java
index 56b7e95e1f..3a1529674f 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);
@@ -76,4 +77,12 @@ public interface PluginInfoService {
* @return 插件信息列表
*/
List getPluginInfoList();
-}
\ No newline at end of file
+
+ /**
+ * 根据状态获得插件信息列表
+ *
+ * @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 4e7f2e9961..37b6328450 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 实现类
@@ -41,18 +32,17 @@ public class PluginInfoServiceImpl implements PluginInfoService {
@Resource
private PluginInfoMapper pluginInfoMapper;
+
+ @Resource
+ private PluginInstanceService pluginInstanceService;
+
@Resource
private SpringPluginManager pluginManager;
- @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,41 +57,21 @@ 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);
}
- // 卸载插件
- PluginWrapper plugin = pluginManager.getPlugin(pluginInfoDO.getPluginKey());
- if (plugin != null) {
- // 查询插件是否是启动状态
- if (plugin.getPluginState().equals(PluginState.STARTED)) {
- // 停止插件
- pluginManager.stopPlugin(plugin.getPluginId());
- }
- // 卸载插件
- pluginManager.unloadPlugin(plugin.getPluginId());
- }
+ // 2. 卸载插件
+ pluginInstanceService.stopAndUnloadPlugin(pluginInfoDO.getPluginKey());
- // 删除
+ // 3. 删除插件文件
+ pluginInstanceService.deletePluginFile(pluginInfoDO);
+
+ // 4. 删除插件信息
pluginInfoMapper.deleteById(id);
- // 删除插件文件
- 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,99 +97,37 @@ public class PluginInfoServiceImpl implements PluginInfoService {
// 1. 校验插件信息是否存在
PluginInfoDO pluginInfoDo = validatePluginInfoExists(id);
- // 2. 获取插件标识
- String pluginKey = pluginInfoDo.getPluginKey();
+ // 2. 停止并卸载旧的插件
+ pluginInstanceService.stopAndUnloadPlugin(pluginInfoDo.getPluginKey());
- // 3. 停止并卸载旧的插件
- stopAndUnloadPlugin(pluginKey);
+ // 3 上传新的插件文件,更新插件启用状态文件
+ String pluginKeyNew = pluginInstanceService.uploadAndLoadNewPlugin(file);
- // 4. 上传新的插件文件
- String pluginKeyNew = uploadAndLoadNewPlugin(file);
-
- // 5. 更新插件启用状态文件
- updatePluginStatusFile(pluginKeyNew, false);
-
- // 6. 更新插件信息
+ // 4. 更新插件信息
updatePluginInfo(pluginInfoDo, pluginKeyNew, file);
}
- // 停止并卸载旧的插件
- 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); // 卸载插件
- }
- }
-
- // 上传并加载新的插件文件
- private String uploadAndLoadNewPlugin(MultipartFile file) {
- Path pluginsPath = Paths.get(pluginsDir);
- try {
- 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()); // 加载插件
- } else {
- throw exception(PLUGIN_INSTALL_FAILED);
- }
- } catch (Exception e) {
- throw exception(PLUGIN_INSTALL_FAILED);
- }
- }
-
- // 更新插件状态文件
- private void updatePluginStatusFile(String pluginKeyNew, 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(pluginKeyNew);
- if (pluginWrapper == null) {
- throw exception(PLUGIN_INSTALL_FAILED);
- }
- String pluginInfo = pluginKeyNew + "@" + 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);
- }
- }
-
- // 更新插件信息
+ /**
+ * 更新插件信息
+ *
+ * @param pluginInfoDo 插件信息
+ * @param pluginKeyNew 插件标识符
+ * @param file 文件
+ */
private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginKeyNew, MultipartFile file) {
- pluginInfoDo.setPluginKey(pluginKeyNew);
- pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus());
- pluginInfoDo.setFileName(file.getOriginalFilename());
- pluginInfoDo.setScript("");
+ // 创建新的插件信息对象并链式设置属性
+ 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());
- PluginDescriptor pluginDescriptor = pluginManager.getPlugin(pluginKeyNew).getDescriptor();
- pluginInfoDo.setConfigSchema(pluginDescriptor.getPluginDescription());
- pluginInfoDo.setVersion(pluginDescriptor.getVersion());
- pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription());
- pluginInfoMapper.updateById(pluginInfoDo);
+ // 执行更新
+ pluginInfoMapper.updateById(updatedPluginInfo);
}
@Override
@@ -227,44 +135,24 @@ public class PluginInfoServiceImpl implements PluginInfoService {
// 1. 校验插件信息是否存在
PluginInfoDO pluginInfoDo = validatePluginInfoExists(id);
- // 2. 校验插件状态是否有效
- 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. 更新数据库中的插件状态
- pluginInfoDo.setStatus(status);
- pluginInfoMapper.updateById(pluginInfoDo);
+ // 3. 更新数据库中的插件状态
+ PluginInfoDO updatedPluginInfo = new PluginInfoDO();
+ updatedPluginInfo.setId(id);
+ updatedPluginInfo.setStatus(status);
+ pluginInfoMapper.updateById(updatedPluginInfo);
}
@Override
public List getPluginInfoList() {
- return pluginInfoMapper.selectList(null);
+ return pluginInfoMapper.selectList();
+ }
+
+ @Override
+ 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 5655f1d3ad..4df9b10319 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,38 @@ 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 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 52d79207b8..65a6cf32ba 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,34 @@
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.nio.file.*;
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,76 +40,149 @@ import java.util.List;
@Slf4j
public class PluginInstanceServiceImpl implements PluginInstanceService {
- /**
- * 主程序id
- */
+ // TODO @haohao:这个可以后续确认下,有没更合适的标识。例如说 mac 地址之类的
+ // 简化的 UUID + mac 地址 会不会好一些,一台机子有可能会部署多个插件;
+ // 那就 mac@uuid ?
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;
+ @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 {
+ log.warn("插件不存在或已卸载: {}", pluginKey);
+ }
+ }
@Override
- public void updatePluginInstances() {
- // 1. 查询 pf4j 插件列表
+ 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);
+ }
+ }
+ }
+
+ @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 updatePluginStatus(PluginInfoDO pluginInfoDo, Integer status) {
+ 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 (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) {
+ throw exception(ErrorCodeConstants.PLUGIN_STATUS_INVALID);
+ }
+ }
+ }
+
+ @Override
+ public void reportPluginInstances() {
+ // 1.1 获取 pf4j 插件列表
List plugins = pluginManager.getPlugins();
- // 2. 查询插件信息列表
- List pluginInfos = pluginInfoService.getPluginInfoList();
+ // 1.2 获取插件信息列表并转换为 Map 以便快速查找
+ List pluginInfos = pluginInfoMapper.selectList();
+ Map pluginInfoMap = pluginInfos.stream()
+ .collect(Collectors.toMap(PluginInfoDO::getPluginKey, Function.identity()));
- // 动态获取主程序的 IP 和端口
- String mainIp = getLocalIpAddress();
+ // 1.3 获取本机 IP 和 MAC 地址
+ String ip = NetUtil.getLocalhostStr();
+ String mac = NetUtil.getLocalMacAddress();
+ String mainId = MAIN_ID + "-" + mac;
- // 3. 遍历插件列表,并保存为插件实例
+ // 2. 遍历插件列表,并保存为插件实例
for (PluginWrapper plugin : plugins) {
String pluginKey = plugin.getPluginId();
- PluginInfoDO pluginInfo = pluginInfos.stream()
- .filter(pluginInfoDO -> pluginInfoDO.getPluginKey().equals(pluginKey))
- .findFirst()
- .orElse(null);
- // 4. 如果插件信息不存在,则跳过
+ // 2.1 查找插件信息
+ PluginInfoDO pluginInfo = pluginInfoMap.get(pluginKey);
if (pluginInfo == null) {
+ log.error("插件信息不存在,pluginKey = {}", pluginKey);
continue;
}
- // 5. 查询插件实例
- PluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(MAIN_ID, pluginInfo.getId());
-
- // 6. 如果插件实例不存在,则创建
+ // 2.2 情况一:如果插件实例不存在,则创建
+ PluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(mainId,
+ pluginInfo.getId());
if (pluginInstance == null) {
- 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 {
- // 7. 如果插件实例存在,则更新
+ // 2.2 情况二:如果存在,则更新 heartbeatAt
+ // TODO @haohao:这里最好 new 去 update;避免并发更新(虽然目前没有)
pluginInstance.setHeartbeatAt(System.currentTimeMillis());
pluginInstanceMapper.updateById(pluginInstance);
}
}
}
- 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-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 41537664b0..ad3ff94e2b 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 52e90f30f7..e094b34cb6 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 db18b3022d..09e5dd4681 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,20 +6,20 @@
- 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)
- )
+ 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)
+ )
-
CREATE TABLE device_log_${deviceKey} USING device_log TAGS('${deviceKey}')
@@ -41,4 +41,38 @@
)
+
+
+
+
\ 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
index c8f0ff0fe8..4a46b61672 100644
--- a/yudao-module-iot/yudao-module-iot-plugin/pom.xml
+++ b/yudao-module-iot/yudao-module-iot-plugin/pom.xml
@@ -2,11 +2,6 @@
-
-
-
-
-
yudao-module-iot
cn.iocoder.boot
@@ -15,6 +10,7 @@
yudao-module-iot-demo-plugin
yudao-module-iot-http-plugin
+ yudao-module-iot-mqtt-plugin
4.0.0
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 0000000000..f4ec60d961
--- /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 4e1199acfc..44f221cb15 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 1ecf140a47..29c0200f1c 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,20 @@
${lombok.version}
provided