Commit 555310de66d18250116f14d2cf93f42155cc3862
1 parent
39ba4e72
【功能新增】IoT:增加插件管理功能,包含插件实例和类型的定义及相关配置
Showing
30 changed files
with
1726 additions
and
1 deletions
yudao-dependencies/pom.xml
| @@ -66,6 +66,7 @@ | @@ -66,6 +66,7 @@ | ||
| 66 | <ip2region.version>2.7.0</ip2region.version> | 66 | <ip2region.version>2.7.0</ip2region.version> |
| 67 | <bizlog-sdk.version>3.0.6</bizlog-sdk.version> | 67 | <bizlog-sdk.version>3.0.6</bizlog-sdk.version> |
| 68 | <mqtt.version>1.2.5</mqtt.version> | 68 | <mqtt.version>1.2.5</mqtt.version> |
| 69 | + <pf4j-spring.version>0.9.0</pf4j-spring.version> | ||
| 69 | <!-- 三方云服务相关 --> | 70 | <!-- 三方云服务相关 --> |
| 70 | <okio.version>3.5.0</okio.version> | 71 | <okio.version>3.5.0</okio.version> |
| 71 | <okhttp3.version>4.11.0</okhttp3.version> | 72 | <okhttp3.version>4.11.0</okhttp3.version> |
| @@ -605,6 +606,13 @@ | @@ -605,6 +606,13 @@ | ||
| 605 | <version>${mqtt.version}</version> | 606 | <version>${mqtt.version}</version> |
| 606 | </dependency> | 607 | </dependency> |
| 607 | 608 | ||
| 609 | + <!-- PF4J --> | ||
| 610 | + <dependency> | ||
| 611 | + <groupId>org.pf4j</groupId> | ||
| 612 | + <artifactId>pf4j-spring</artifactId> | ||
| 613 | + <version>${pf4j-spring.version}</version> | ||
| 614 | + </dependency> | ||
| 615 | + | ||
| 608 | </dependencies> | 616 | </dependencies> |
| 609 | </dependencyManagement> | 617 | </dependencyManagement> |
| 610 | 618 |
yudao-module-iot/pom.xml
| @@ -10,6 +10,7 @@ | @@ -10,6 +10,7 @@ | ||
| 10 | <modules> | 10 | <modules> |
| 11 | <module>yudao-module-iot-api</module> | 11 | <module>yudao-module-iot-api</module> |
| 12 | <module>yudao-module-iot-biz</module> | 12 | <module>yudao-module-iot-biz</module> |
| 13 | + <module>yudao-module-iot-plugin</module> | ||
| 13 | </modules> | 14 | </modules> |
| 14 | <modelVersion>4.0.0</modelVersion> | 15 | <modelVersion>4.0.0</modelVersion> |
| 15 | 16 |
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 { | @@ -36,4 +36,15 @@ public interface ErrorCodeConstants { | ||
| 36 | // ========== 设备分组 1-050-005-000 ========== | 36 | // ========== 设备分组 1-050-005-000 ========== |
| 37 | ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在"); | 37 | ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在"); |
| 38 | ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除"); | 38 | ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除"); |
| 39 | -} | 39 | + |
| 40 | + // ========== 插件信息 1-050-006-000 ========== | ||
| 41 | + ErrorCode PLUGIN_INFO_NOT_EXISTS = new ErrorCode(1_050_006_000, "插件信息不存在"); | ||
| 42 | + ErrorCode PLUGIN_INSTALL_FAILED = new ErrorCode(1_050_006_001, "插件安装失败"); | ||
| 43 | + ErrorCode PLUGIN_INSTALL_FAILED_FILE_NAME_NOT_MATCH = new ErrorCode(1_050_006_002, "插件安装失败,文件名与原插件id不匹配"); | ||
| 44 | + ErrorCode PLUGIN_INFO_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件"); | ||
| 45 | + ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效"); | ||
| 46 | + | ||
| 47 | + // ========== 插件实例 1-050-007-000 ========== | ||
| 48 | + ErrorCode PLUGIN_INSTANCE_NOT_EXISTS = new ErrorCode(1_050_007_000, "插件实例不存在"); | ||
| 49 | + | ||
| 50 | +} | ||
| 40 | \ No newline at end of file | 51 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.enums.plugin; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||
| 4 | +import lombok.Getter; | ||
| 5 | + | ||
| 6 | +import java.util.Arrays; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * IoT 部署方式枚举 | ||
| 10 | + * | ||
| 11 | + * @author haohao | ||
| 12 | + */ | ||
| 13 | +@Getter | ||
| 14 | +public enum IotPluginDeployTypeEnum implements IntArrayValuable { | ||
| 15 | + | ||
| 16 | + UPLOAD(0, "上传jar"), | ||
| 17 | + ALONE(1, "独立运行"); | ||
| 18 | + | ||
| 19 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginDeployTypeEnum::getDeployType).toArray(); | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 部署方式 | ||
| 23 | + */ | ||
| 24 | + private final Integer deployType; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 部署方式名 | ||
| 28 | + */ | ||
| 29 | + private final String name; | ||
| 30 | + | ||
| 31 | + IotPluginDeployTypeEnum(Integer deployType, String name) { | ||
| 32 | + this.deployType = deployType; | ||
| 33 | + this.name = name; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public static IotPluginDeployTypeEnum fromDeployType(Integer deployType) { | ||
| 37 | + for (IotPluginDeployTypeEnum value : values()) { | ||
| 38 | + if (value.getDeployType().equals(deployType)) { | ||
| 39 | + return value; | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + return null; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public static boolean isValidDeployType(Integer deployType) { | ||
| 46 | + return fromDeployType(deployType) != null; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + @Override | ||
| 50 | + public int[] array() { | ||
| 51 | + return ARRAYS; | ||
| 52 | + } | ||
| 53 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.enums.plugin; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||
| 4 | +import lombok.Getter; | ||
| 5 | + | ||
| 6 | +import java.util.Arrays; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * IoT 插件状态枚举 | ||
| 10 | + * | ||
| 11 | + * @author haohao | ||
| 12 | + */ | ||
| 13 | +@Getter | ||
| 14 | +public enum IotPluginStatusEnum implements IntArrayValuable { | ||
| 15 | + | ||
| 16 | + STOPPED(0, "停止"), | ||
| 17 | + RUNNING(1, "运行"); | ||
| 18 | + | ||
| 19 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginStatusEnum::getStatus).toArray(); | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 状态 | ||
| 23 | + */ | ||
| 24 | + private final Integer status; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 状态名 | ||
| 28 | + */ | ||
| 29 | + private final String name; | ||
| 30 | + | ||
| 31 | + IotPluginStatusEnum(Integer status, String name) { | ||
| 32 | + this.status = status; | ||
| 33 | + this.name = name; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public static IotPluginStatusEnum fromState(Integer state) { | ||
| 37 | + for (IotPluginStatusEnum value : values()) { | ||
| 38 | + if (value.getStatus().equals(state)) { | ||
| 39 | + return value; | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + return null; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public static boolean isValidState(Integer state) { | ||
| 46 | + return fromState(state) != null; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public static boolean contains(Integer status) { | ||
| 50 | + return Arrays.stream(values()).anyMatch(e -> e.getStatus().equals(status)); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public int[] array() { | ||
| 55 | + return new int[0]; | ||
| 56 | + } | ||
| 57 | +} |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.enums.plugin; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||
| 4 | +import lombok.Getter; | ||
| 5 | + | ||
| 6 | +import java.util.Arrays; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * IoT 插件类型枚举 | ||
| 10 | + * | ||
| 11 | + * @author haohao | ||
| 12 | + */ | ||
| 13 | +@Getter | ||
| 14 | +public enum IotPluginTypeEnum implements IntArrayValuable { | ||
| 15 | + | ||
| 16 | + NORMAL(0, "普通插件"), | ||
| 17 | + DEVICE(1, "设备插件"); | ||
| 18 | + | ||
| 19 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotPluginTypeEnum::getType).toArray(); | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 类型 | ||
| 23 | + */ | ||
| 24 | + private final Integer type; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 类型名 | ||
| 28 | + */ | ||
| 29 | + private final String name; | ||
| 30 | + | ||
| 31 | + IotPluginTypeEnum(Integer type, String name) { | ||
| 32 | + this.type = type; | ||
| 33 | + this.name = name; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public static IotPluginTypeEnum fromType(Integer type) { | ||
| 37 | + for (IotPluginTypeEnum value : values()) { | ||
| 38 | + if (value.getType().equals(type)) { | ||
| 39 | + return value; | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + return null; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public static boolean isValidType(Integer type) { | ||
| 46 | + return fromType(type) != null; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + @Override | ||
| 50 | + public int[] array() { | ||
| 51 | + return ARRAYS; | ||
| 52 | + } | ||
| 53 | +} |
yudao-module-iot/yudao-module-iot-biz/pom.xml
| @@ -69,6 +69,12 @@ | @@ -69,6 +69,12 @@ | ||
| 69 | <groupId>org.eclipse.paho</groupId> | 69 | <groupId>org.eclipse.paho</groupId> |
| 70 | <artifactId>org.eclipse.paho.client.mqttv3</artifactId> | 70 | <artifactId>org.eclipse.paho.client.mqttv3</artifactId> |
| 71 | </dependency> | 71 | </dependency> |
| 72 | + | ||
| 73 | + <!-- PF4J --> | ||
| 74 | + <dependency> | ||
| 75 | + <groupId>org.pf4j</groupId> | ||
| 76 | + <artifactId>pf4j-spring</artifactId> | ||
| 77 | + </dependency> | ||
| 72 | </dependencies> | 78 | </dependencies> |
| 73 | 79 | ||
| 74 | </project> | 80 | </project> |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 6 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoRespVO; | ||
| 8 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; | ||
| 9 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; | ||
| 10 | +import cn.iocoder.yudao.module.iot.service.plugininfo.PluginInfoService; | ||
| 11 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 12 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 13 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 14 | +import jakarta.annotation.Resource; | ||
| 15 | +import jakarta.validation.Valid; | ||
| 16 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 17 | +import org.springframework.validation.annotation.Validated; | ||
| 18 | +import org.springframework.web.bind.annotation.*; | ||
| 19 | +import org.springframework.web.multipart.MultipartFile; | ||
| 20 | + | ||
| 21 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 22 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 23 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | ||
| 24 | +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_IS_EMPTY; | ||
| 25 | + | ||
| 26 | +@Tag(name = "管理后台 - IoT 插件信息") | ||
| 27 | +@RestController | ||
| 28 | +@RequestMapping("/iot/plugin-info") | ||
| 29 | +@Validated | ||
| 30 | +public class PluginInfoController { | ||
| 31 | + | ||
| 32 | + @Resource | ||
| 33 | + private PluginInfoService pluginInfoService; | ||
| 34 | + | ||
| 35 | + @PostMapping("/create") | ||
| 36 | + @Operation(summary = "创建插件信息") | ||
| 37 | + @PreAuthorize("@ss.hasPermission('iot:plugin-info:create')") | ||
| 38 | + public CommonResult<Long> createPluginInfo(@Valid @RequestBody PluginInfoSaveReqVO createReqVO) { | ||
| 39 | + return success(pluginInfoService.createPluginInfo(createReqVO)); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + @PutMapping("/update") | ||
| 43 | + @Operation(summary = "更新插件信息") | ||
| 44 | + @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") | ||
| 45 | + public CommonResult<Boolean> updatePluginInfo(@Valid @RequestBody PluginInfoSaveReqVO updateReqVO) { | ||
| 46 | + pluginInfoService.updatePluginInfo(updateReqVO); | ||
| 47 | + return success(true); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + @DeleteMapping("/delete") | ||
| 51 | + @Operation(summary = "删除插件信息") | ||
| 52 | + @Parameter(name = "id", description = "编号", required = true) | ||
| 53 | + @PreAuthorize("@ss.hasPermission('iot:plugin-info:delete')") | ||
| 54 | + public CommonResult<Boolean> deletePluginInfo(@RequestParam("id") Long id) { | ||
| 55 | + pluginInfoService.deletePluginInfo(id); | ||
| 56 | + return success(true); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + @GetMapping("/get") | ||
| 60 | + @Operation(summary = "获得插件信息") | ||
| 61 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||
| 62 | + @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") | ||
| 63 | + public CommonResult<PluginInfoRespVO> getPluginInfo(@RequestParam("id") Long id) { | ||
| 64 | + PluginInfoDO pluginInfo = pluginInfoService.getPluginInfo(id); | ||
| 65 | + return success(BeanUtils.toBean(pluginInfo, PluginInfoRespVO.class)); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @GetMapping("/page") | ||
| 69 | + @Operation(summary = "获得插件信息分页") | ||
| 70 | + @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") | ||
| 71 | + public CommonResult<PageResult<PluginInfoRespVO>> getPluginInfoPage(@Valid PluginInfoPageReqVO pageReqVO) { | ||
| 72 | + PageResult<PluginInfoDO> pageResult = pluginInfoService.getPluginInfoPage(pageReqVO); | ||
| 73 | + return success(BeanUtils.toBean(pageResult, PluginInfoRespVO.class)); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + @RequestMapping(value = "/update-jar", | ||
| 77 | + method = {RequestMethod.POST, RequestMethod.PUT}) // 解决 uni-app 不支持 Put 上传文件的问题 | ||
| 78 | + @Operation(summary = "上传Jar包") | ||
| 79 | + public CommonResult<Boolean> uploadJar( | ||
| 80 | + @RequestParam("id") Long id, | ||
| 81 | + @RequestParam("jar") MultipartFile file) throws Exception { | ||
| 82 | + if (file.isEmpty()) { | ||
| 83 | + throw exception(FILE_IS_EMPTY); | ||
| 84 | + } | ||
| 85 | + pluginInfoService.uploadJar(id, file); | ||
| 86 | + return success(true); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + // 修改插件状态 | ||
| 90 | + @PutMapping("/update-status") | ||
| 91 | + @Operation(summary = "修改插件状态") | ||
| 92 | + @PreAuthorize("@ss.hasPermission('iot:plugin-info:update')") | ||
| 93 | + public CommonResult<Boolean> updateUserStatus(@Valid @RequestBody PluginInfoSaveReqVO reqVO) { | ||
| 94 | + pluginInfoService.updatePluginStatus(reqVO.getId(), reqVO.getStatus()); | ||
| 95 | + return success(true); | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | +} | ||
| 0 | \ No newline at end of file | 99 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; | ||
| 2 | + | ||
| 3 | +import lombok.*; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 6 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 7 | +import java.time.LocalDateTime; | ||
| 8 | + | ||
| 9 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 10 | + | ||
| 11 | +@Schema(description = "管理后台 - IoT 插件信息分页 Request VO") | ||
| 12 | +@Data | ||
| 13 | +@EqualsAndHashCode(callSuper = true) | ||
| 14 | +@ToString(callSuper = true) | ||
| 15 | +public class PluginInfoPageReqVO extends PageParam { | ||
| 16 | + | ||
| 17 | + @Schema(description = "插件包id", example = "24627") | ||
| 18 | + private String pluginId; | ||
| 19 | + | ||
| 20 | + @Schema(description = "插件名称", example = "赵六") | ||
| 21 | + private String name; | ||
| 22 | + | ||
| 23 | + @Schema(description = "描述", example = "你猜") | ||
| 24 | + private String description; | ||
| 25 | + | ||
| 26 | + @Schema(description = "部署方式", example = "2") | ||
| 27 | + private Integer deployType; | ||
| 28 | + | ||
| 29 | + @Schema(description = "插件包文件名") | ||
| 30 | + private String file; | ||
| 31 | + | ||
| 32 | + @Schema(description = "插件版本") | ||
| 33 | + private String version; | ||
| 34 | + | ||
| 35 | + @Schema(description = "插件类型", example = "2") | ||
| 36 | + private Integer type; | ||
| 37 | + | ||
| 38 | + @Schema(description = "设备插件协议类型") | ||
| 39 | + private String protocol; | ||
| 40 | + | ||
| 41 | + @Schema(description = "状态") | ||
| 42 | + private Integer status; | ||
| 43 | + | ||
| 44 | + @Schema(description = "插件配置项描述信息") | ||
| 45 | + private String configSchema; | ||
| 46 | + | ||
| 47 | + @Schema(description = "插件配置信息") | ||
| 48 | + private String config; | ||
| 49 | + | ||
| 50 | + @Schema(description = "插件脚本") | ||
| 51 | + private String script; | ||
| 52 | + | ||
| 53 | + @Schema(description = "创建时间") | ||
| 54 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 55 | + private LocalDateTime[] createTime; | ||
| 56 | + | ||
| 57 | +} | ||
| 0 | \ No newline at end of file | 58 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.*; | ||
| 5 | + | ||
| 6 | +import java.time.LocalDateTime; | ||
| 7 | +import com.alibaba.excel.annotation.*; | ||
| 8 | + | ||
| 9 | +@Schema(description = "管理后台 - IoT 插件信息 Response VO") | ||
| 10 | +@Data | ||
| 11 | +@ExcelIgnoreUnannotated | ||
| 12 | +public class PluginInfoRespVO { | ||
| 13 | + | ||
| 14 | + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") | ||
| 15 | + @ExcelProperty("主键ID") | ||
| 16 | + private Long id; | ||
| 17 | + | ||
| 18 | + @Schema(description = "插件包id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") | ||
| 19 | + @ExcelProperty("插件包id") | ||
| 20 | + private String pluginId; | ||
| 21 | + | ||
| 22 | + @Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") | ||
| 23 | + @ExcelProperty("插件名称") | ||
| 24 | + private String name; | ||
| 25 | + | ||
| 26 | + @Schema(description = "描述", example = "你猜") | ||
| 27 | + @ExcelProperty("描述") | ||
| 28 | + private String description; | ||
| 29 | + | ||
| 30 | + @Schema(description = "部署方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 31 | + @ExcelProperty("部署方式") | ||
| 32 | + private Integer deployType; | ||
| 33 | + | ||
| 34 | + @Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 35 | + @ExcelProperty("插件包文件名") | ||
| 36 | + private String file; | ||
| 37 | + | ||
| 38 | + @Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 39 | + @ExcelProperty("插件版本") | ||
| 40 | + private String version; | ||
| 41 | + | ||
| 42 | + @Schema(description = "插件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 43 | + @ExcelProperty("插件类型") | ||
| 44 | + private Integer type; | ||
| 45 | + | ||
| 46 | + @Schema(description = "设备插件协议类型") | ||
| 47 | + @ExcelProperty("设备插件协议类型") | ||
| 48 | + private String protocol; | ||
| 49 | + | ||
| 50 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 51 | + @ExcelProperty("状态") | ||
| 52 | + private Integer status; | ||
| 53 | + | ||
| 54 | + @Schema(description = "插件配置项描述信息") | ||
| 55 | + @ExcelProperty("插件配置项描述信息") | ||
| 56 | + private String configSchema; | ||
| 57 | + | ||
| 58 | + @Schema(description = "插件配置信息") | ||
| 59 | + @ExcelProperty("插件配置信息") | ||
| 60 | + private String config; | ||
| 61 | + | ||
| 62 | + @Schema(description = "插件脚本") | ||
| 63 | + @ExcelProperty("插件脚本") | ||
| 64 | + private String script; | ||
| 65 | + | ||
| 66 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 67 | + @ExcelProperty("创建时间") | ||
| 68 | + private LocalDateTime createTime; | ||
| 69 | + | ||
| 70 | +} | ||
| 0 | \ No newline at end of file | 71 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.*; | ||
| 5 | + | ||
| 6 | +@Schema(description = "管理后台 - IoT 插件信息新增/修改 Request VO") | ||
| 7 | +@Data | ||
| 8 | +public class PluginInfoSaveReqVO { | ||
| 9 | + | ||
| 10 | + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") | ||
| 11 | + private Long id; | ||
| 12 | + | ||
| 13 | + @Schema(description = "插件包id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") | ||
| 14 | + private String pluginId; | ||
| 15 | + | ||
| 16 | + @Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") | ||
| 17 | + private String name; | ||
| 18 | + | ||
| 19 | + @Schema(description = "描述", example = "你猜") | ||
| 20 | + private String description; | ||
| 21 | + | ||
| 22 | + @Schema(description = "部署方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 23 | + private Integer deployType; | ||
| 24 | + | ||
| 25 | + @Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 26 | + private String file; | ||
| 27 | + | ||
| 28 | + @Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 29 | + private String version; | ||
| 30 | + | ||
| 31 | + @Schema(description = "插件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||
| 32 | + private Integer type; | ||
| 33 | + | ||
| 34 | + @Schema(description = "设备插件协议类型") | ||
| 35 | + private String protocol; | ||
| 36 | + | ||
| 37 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 38 | + private Integer status; | ||
| 39 | + | ||
| 40 | + @Schema(description = "插件配置项描述信息") | ||
| 41 | + private String configSchema; | ||
| 42 | + | ||
| 43 | + @Schema(description = "插件配置信息") | ||
| 44 | + private String config; | ||
| 45 | + | ||
| 46 | + @Schema(description = "插件脚本") | ||
| 47 | + private String script; | ||
| 48 | + | ||
| 49 | +} | ||
| 0 | \ No newline at end of file | 50 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/PluginInstanceController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.plugininstance; | ||
| 2 | + | ||
| 3 | +import org.springframework.web.bind.annotation.*; | ||
| 4 | +import jakarta.annotation.Resource; | ||
| 5 | +import org.springframework.validation.annotation.Validated; | ||
| 6 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 7 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 8 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 9 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 10 | + | ||
| 11 | +import jakarta.validation.*; | ||
| 12 | +import jakarta.servlet.http.*; | ||
| 13 | +import java.util.*; | ||
| 14 | +import java.io.IOException; | ||
| 15 | + | ||
| 16 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 17 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 18 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 19 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 20 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 21 | + | ||
| 22 | +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | ||
| 23 | + | ||
| 24 | +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; | ||
| 25 | +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; | ||
| 26 | + | ||
| 27 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.*; | ||
| 28 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; | ||
| 29 | +import cn.iocoder.yudao.module.iot.service.plugininstance.PluginInstanceService; | ||
| 30 | + | ||
| 31 | +@Tag(name = "管理后台 - IoT 插件实例") | ||
| 32 | +@RestController | ||
| 33 | +@RequestMapping("/iot/plugin-instance") | ||
| 34 | +@Validated | ||
| 35 | +public class PluginInstanceController { | ||
| 36 | + | ||
| 37 | + @Resource | ||
| 38 | + private PluginInstanceService pluginInstanceService; | ||
| 39 | + | ||
| 40 | + @PostMapping("/create") | ||
| 41 | + @Operation(summary = "创建IoT 插件实例") | ||
| 42 | + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:create')") | ||
| 43 | + public CommonResult<Long> createPluginInstance(@Valid @RequestBody PluginInstanceSaveReqVO createReqVO) { | ||
| 44 | + return success(pluginInstanceService.createPluginInstance(createReqVO)); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + @PutMapping("/update") | ||
| 48 | + @Operation(summary = "更新IoT 插件实例") | ||
| 49 | + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:update')") | ||
| 50 | + public CommonResult<Boolean> updatePluginInstance(@Valid @RequestBody PluginInstanceSaveReqVO updateReqVO) { | ||
| 51 | + pluginInstanceService.updatePluginInstance(updateReqVO); | ||
| 52 | + return success(true); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + @DeleteMapping("/delete") | ||
| 56 | + @Operation(summary = "删除IoT 插件实例") | ||
| 57 | + @Parameter(name = "id", description = "编号", required = true) | ||
| 58 | + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:delete')") | ||
| 59 | + public CommonResult<Boolean> deletePluginInstance(@RequestParam("id") Long id) { | ||
| 60 | + pluginInstanceService.deletePluginInstance(id); | ||
| 61 | + return success(true); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + @GetMapping("/get") | ||
| 65 | + @Operation(summary = "获得IoT 插件实例") | ||
| 66 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||
| 67 | + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:query')") | ||
| 68 | + public CommonResult<PluginInstanceRespVO> getPluginInstance(@RequestParam("id") Long id) { | ||
| 69 | + PluginInstanceDO pluginInstance = pluginInstanceService.getPluginInstance(id); | ||
| 70 | + return success(BeanUtils.toBean(pluginInstance, PluginInstanceRespVO.class)); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @GetMapping("/page") | ||
| 74 | + @Operation(summary = "获得IoT 插件实例分页") | ||
| 75 | + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:query')") | ||
| 76 | + public CommonResult<PageResult<PluginInstanceRespVO>> getPluginInstancePage(@Valid PluginInstancePageReqVO pageReqVO) { | ||
| 77 | + PageResult<PluginInstanceDO> pageResult = pluginInstanceService.getPluginInstancePage(pageReqVO); | ||
| 78 | + return success(BeanUtils.toBean(pageResult, PluginInstanceRespVO.class)); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + @GetMapping("/export-excel") | ||
| 82 | + @Operation(summary = "导出IoT 插件实例 Excel") | ||
| 83 | + @PreAuthorize("@ss.hasPermission('iot:plugin-instance:export')") | ||
| 84 | + @ApiAccessLog(operateType = EXPORT) | ||
| 85 | + public void exportPluginInstanceExcel(@Valid PluginInstancePageReqVO pageReqVO, | ||
| 86 | + HttpServletResponse response) throws IOException { | ||
| 87 | + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); | ||
| 88 | + List<PluginInstanceDO> list = pluginInstanceService.getPluginInstancePage(pageReqVO).getList(); | ||
| 89 | + // 导出 Excel | ||
| 90 | + ExcelUtils.write(response, "IoT 插件实例.xls", "数据", PluginInstanceRespVO.class, | ||
| 91 | + BeanUtils.toBean(list, PluginInstanceRespVO.class)); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | +} | ||
| 0 | \ No newline at end of file | 95 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstancePageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; | ||
| 2 | + | ||
| 3 | +import lombok.*; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 6 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 7 | +import java.time.LocalDateTime; | ||
| 8 | + | ||
| 9 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||
| 10 | + | ||
| 11 | +@Schema(description = "管理后台 - IoT 插件实例分页 Request VO") | ||
| 12 | +@Data | ||
| 13 | +@EqualsAndHashCode(callSuper = true) | ||
| 14 | +@ToString(callSuper = true) | ||
| 15 | +public class PluginInstancePageReqVO extends PageParam { | ||
| 16 | + | ||
| 17 | + @Schema(description = "插件主程序id", example = "23738") | ||
| 18 | + private String mainId; | ||
| 19 | + | ||
| 20 | + @Schema(description = "插件id", example = "26498") | ||
| 21 | + private Long pluginId; | ||
| 22 | + | ||
| 23 | + @Schema(description = "插件主程序所在ip") | ||
| 24 | + private String ip; | ||
| 25 | + | ||
| 26 | + @Schema(description = "插件主程序端口") | ||
| 27 | + private Integer port; | ||
| 28 | + | ||
| 29 | + @Schema(description = "心跳时间,心路时间超过30秒需要剔除") | ||
| 30 | + private Long heartbeatAt; | ||
| 31 | + | ||
| 32 | + @Schema(description = "创建时间") | ||
| 33 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 34 | + private LocalDateTime[] createTime; | ||
| 35 | + | ||
| 36 | +} | ||
| 0 | \ No newline at end of file | 37 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.*; | ||
| 5 | +import java.util.*; | ||
| 6 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 7 | +import java.time.LocalDateTime; | ||
| 8 | +import com.alibaba.excel.annotation.*; | ||
| 9 | + | ||
| 10 | +@Schema(description = "管理后台 - IoT 插件实例 Response VO") | ||
| 11 | +@Data | ||
| 12 | +@ExcelIgnoreUnannotated | ||
| 13 | +public class PluginInstanceRespVO { | ||
| 14 | + | ||
| 15 | + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "23864") | ||
| 16 | + @ExcelProperty("主键ID") | ||
| 17 | + private Long id; | ||
| 18 | + | ||
| 19 | + @Schema(description = "插件主程序id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23738") | ||
| 20 | + @ExcelProperty("插件主程序id") | ||
| 21 | + private String mainId; | ||
| 22 | + | ||
| 23 | + @Schema(description = "插件id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26498") | ||
| 24 | + @ExcelProperty("插件id") | ||
| 25 | + private Long pluginId; | ||
| 26 | + | ||
| 27 | + @Schema(description = "插件主程序所在ip", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 28 | + @ExcelProperty("插件主程序所在ip") | ||
| 29 | + private String ip; | ||
| 30 | + | ||
| 31 | + @Schema(description = "插件主程序端口", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 32 | + @ExcelProperty("插件主程序端口") | ||
| 33 | + private Integer port; | ||
| 34 | + | ||
| 35 | + @Schema(description = "心跳时间,心路时间超过30秒需要剔除", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 36 | + @ExcelProperty("心跳时间,心路时间超过30秒需要剔除") | ||
| 37 | + private Long heartbeatAt; | ||
| 38 | + | ||
| 39 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 40 | + @ExcelProperty("创建时间") | ||
| 41 | + private LocalDateTime createTime; | ||
| 42 | + | ||
| 43 | +} | ||
| 0 | \ No newline at end of file | 44 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininstance/vo/PluginInstanceSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.*; | ||
| 5 | +import java.util.*; | ||
| 6 | +import jakarta.validation.constraints.*; | ||
| 7 | + | ||
| 8 | +@Schema(description = "管理后台 - IoT 插件实例新增/修改 Request VO") | ||
| 9 | +@Data | ||
| 10 | +public class PluginInstanceSaveReqVO { | ||
| 11 | + | ||
| 12 | + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "23864") | ||
| 13 | + private Long id; | ||
| 14 | + | ||
| 15 | + @Schema(description = "插件主程序id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23738") | ||
| 16 | + @NotEmpty(message = "插件主程序id不能为空") | ||
| 17 | + private String mainId; | ||
| 18 | + | ||
| 19 | + @Schema(description = "插件id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26498") | ||
| 20 | + @NotNull(message = "插件id不能为空") | ||
| 21 | + private Long pluginId; | ||
| 22 | + | ||
| 23 | + @Schema(description = "插件主程序所在ip", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 24 | + @NotEmpty(message = "插件主程序所在ip不能为空") | ||
| 25 | + private String ip; | ||
| 26 | + | ||
| 27 | + @Schema(description = "插件主程序端口", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 28 | + @NotNull(message = "插件主程序端口不能为空") | ||
| 29 | + private Integer port; | ||
| 30 | + | ||
| 31 | + @Schema(description = "心跳时间,心路时间超过30秒需要剔除", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 32 | + @NotNull(message = "心跳时间,心路时间超过30秒需要剔除不能为空") | ||
| 33 | + private Long heartbeatAt; | ||
| 34 | + | ||
| 35 | +} | ||
| 0 | \ No newline at end of file | 36 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 4 | +import com.baomidou.mybatisplus.annotation.KeySequence; | ||
| 5 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 6 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 7 | +import lombok.*; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * IoT 插件信息 DO | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@TableName("iot_plugin_info") | ||
| 15 | +@KeySequence("iot_plugin_info_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | ||
| 16 | +@Data | ||
| 17 | +@EqualsAndHashCode(callSuper = true) | ||
| 18 | +@ToString(callSuper = true) | ||
| 19 | +@Builder | ||
| 20 | +@NoArgsConstructor | ||
| 21 | +@AllArgsConstructor | ||
| 22 | +public class PluginInfoDO extends BaseDO { | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 主键ID | ||
| 26 | + */ | ||
| 27 | + @TableId | ||
| 28 | + private Long id; | ||
| 29 | + /** | ||
| 30 | + * 插件包id | ||
| 31 | + */ | ||
| 32 | + private String pluginId; | ||
| 33 | + /** | ||
| 34 | + * 插件名称 | ||
| 35 | + */ | ||
| 36 | + private String name; | ||
| 37 | + /** | ||
| 38 | + * 描述 | ||
| 39 | + */ | ||
| 40 | + private String description; | ||
| 41 | + /** | ||
| 42 | + * 部署方式 | ||
| 43 | + */ | ||
| 44 | + private Integer deployType; | ||
| 45 | + /** | ||
| 46 | + * 插件包文件名 | ||
| 47 | + */ | ||
| 48 | + private String file; | ||
| 49 | + /** | ||
| 50 | + * 插件版本 | ||
| 51 | + */ | ||
| 52 | + private String version; | ||
| 53 | + /** | ||
| 54 | + * 插件类型 | ||
| 55 | + */ | ||
| 56 | + private Integer type; | ||
| 57 | + /** | ||
| 58 | + * 设备插件协议类型 | ||
| 59 | + */ | ||
| 60 | + private String protocol; | ||
| 61 | + /** | ||
| 62 | + * 状态 | ||
| 63 | + */ | ||
| 64 | + private Integer status; | ||
| 65 | + /** | ||
| 66 | + * 插件配置项描述信息 | ||
| 67 | + */ | ||
| 68 | + private String configSchema; | ||
| 69 | + /** | ||
| 70 | + * 插件配置信息 | ||
| 71 | + */ | ||
| 72 | + private String config; | ||
| 73 | + /** | ||
| 74 | + * 插件脚本 | ||
| 75 | + */ | ||
| 76 | + private String script; | ||
| 77 | + | ||
| 78 | +} | ||
| 0 | \ No newline at end of file | 79 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance; | ||
| 2 | + | ||
| 3 | +import lombok.*; | ||
| 4 | +import java.util.*; | ||
| 5 | +import java.time.LocalDateTime; | ||
| 6 | +import java.time.LocalDateTime; | ||
| 7 | +import com.baomidou.mybatisplus.annotation.*; | ||
| 8 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * IoT 插件实例 DO | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@TableName("iot_plugin_instance") | ||
| 16 | +@KeySequence("iot_plugin_instance_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | ||
| 17 | +@Data | ||
| 18 | +@EqualsAndHashCode(callSuper = true) | ||
| 19 | +@ToString(callSuper = true) | ||
| 20 | +@Builder | ||
| 21 | +@NoArgsConstructor | ||
| 22 | +@AllArgsConstructor | ||
| 23 | +public class PluginInstanceDO extends BaseDO { | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 主键ID | ||
| 27 | + */ | ||
| 28 | + @TableId | ||
| 29 | + private Long id; | ||
| 30 | + /** | ||
| 31 | + * 插件主程序id | ||
| 32 | + */ | ||
| 33 | + private String mainId; | ||
| 34 | + /** | ||
| 35 | + * 插件id | ||
| 36 | + */ | ||
| 37 | + private Long pluginId; | ||
| 38 | + /** | ||
| 39 | + * 插件主程序所在ip | ||
| 40 | + */ | ||
| 41 | + private String ip; | ||
| 42 | + /** | ||
| 43 | + * 插件主程序端口 | ||
| 44 | + */ | ||
| 45 | + private Integer port; | ||
| 46 | + /** | ||
| 47 | + * 心跳时间,心路时间超过30秒需要剔除 | ||
| 48 | + */ | ||
| 49 | + private Long heartbeatAt; | ||
| 50 | + | ||
| 51 | +} | ||
| 0 | \ No newline at end of file | 52 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininfo/PluginInfoMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.mysql.plugininfo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 6 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; | ||
| 7 | +import org.apache.ibatis.annotations.Mapper; | ||
| 8 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.*; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * IoT 插件信息 Mapper | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Mapper | ||
| 16 | +public interface PluginInfoMapper extends BaseMapperX<PluginInfoDO> { | ||
| 17 | + | ||
| 18 | + default PageResult<PluginInfoDO> selectPage(PluginInfoPageReqVO reqVO) { | ||
| 19 | + return selectPage(reqVO, new LambdaQueryWrapperX<PluginInfoDO>() | ||
| 20 | + .eqIfPresent(PluginInfoDO::getPluginId, reqVO.getPluginId()) | ||
| 21 | + .likeIfPresent(PluginInfoDO::getName, reqVO.getName()) | ||
| 22 | + .eqIfPresent(PluginInfoDO::getDescription, reqVO.getDescription()) | ||
| 23 | + .eqIfPresent(PluginInfoDO::getDeployType, reqVO.getDeployType()) | ||
| 24 | + .eqIfPresent(PluginInfoDO::getFile, reqVO.getFile()) | ||
| 25 | + .eqIfPresent(PluginInfoDO::getVersion, reqVO.getVersion()) | ||
| 26 | + .eqIfPresent(PluginInfoDO::getType, reqVO.getType()) | ||
| 27 | + .eqIfPresent(PluginInfoDO::getProtocol, reqVO.getProtocol()) | ||
| 28 | + .eqIfPresent(PluginInfoDO::getStatus, reqVO.getStatus()) | ||
| 29 | + .eqIfPresent(PluginInfoDO::getConfigSchema, reqVO.getConfigSchema()) | ||
| 30 | + .eqIfPresent(PluginInfoDO::getConfig, reqVO.getConfig()) | ||
| 31 | + .eqIfPresent(PluginInfoDO::getScript, reqVO.getScript()) | ||
| 32 | + .betweenIfPresent(PluginInfoDO::getCreateTime, reqVO.getCreateTime()) | ||
| 33 | + .orderByDesc(PluginInfoDO::getId)); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | +} | ||
| 0 | \ No newline at end of file | 37 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugininstance/PluginInstanceMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.dal.mysql.plugininstance; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 6 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; | ||
| 7 | +import org.apache.ibatis.annotations.Mapper; | ||
| 8 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.*; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * IoT 插件实例 Mapper | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Mapper | ||
| 16 | +public interface PluginInstanceMapper extends BaseMapperX<PluginInstanceDO> { | ||
| 17 | + | ||
| 18 | + default PageResult<PluginInstanceDO> selectPage(PluginInstancePageReqVO reqVO) { | ||
| 19 | + return selectPage(reqVO, new LambdaQueryWrapperX<PluginInstanceDO>() | ||
| 20 | + .eqIfPresent(PluginInstanceDO::getMainId, reqVO.getMainId()) | ||
| 21 | + .eqIfPresent(PluginInstanceDO::getPluginId, reqVO.getPluginId()) | ||
| 22 | + .eqIfPresent(PluginInstanceDO::getIp, reqVO.getIp()) | ||
| 23 | + .eqIfPresent(PluginInstanceDO::getPort, reqVO.getPort()) | ||
| 24 | + .eqIfPresent(PluginInstanceDO::getHeartbeatAt, reqVO.getHeartbeatAt()) | ||
| 25 | + .betweenIfPresent(PluginInstanceDO::getCreateTime, reqVO.getCreateTime()) | ||
| 26 | + .orderByDesc(PluginInstanceDO::getId)); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | +} | ||
| 0 | \ No newline at end of file | 30 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.framework.plugin; | ||
| 2 | + | ||
| 3 | +import org.pf4j.spring.SpringPluginManager; | ||
| 4 | +import org.springframework.context.annotation.Bean; | ||
| 5 | +import org.springframework.context.annotation.Configuration; | ||
| 6 | + | ||
| 7 | +@Configuration | ||
| 8 | +public class SpringConfiguration { | ||
| 9 | + | ||
| 10 | + @Bean | ||
| 11 | + public SpringPluginManager pluginManager() { | ||
| 12 | + return new SpringPluginManager(); | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | +} | ||
| 0 | \ No newline at end of file | 16 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.plugininfo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; | ||
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; | ||
| 7 | +import jakarta.validation.Valid; | ||
| 8 | +import org.springframework.web.multipart.MultipartFile; | ||
| 9 | + | ||
| 10 | +import java.io.InputStream; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * IoT 插件信息 Service 接口 | ||
| 14 | + * | ||
| 15 | + * @author 芋道源码 | ||
| 16 | + */ | ||
| 17 | +public interface PluginInfoService { | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 创建IoT 插件信息 | ||
| 21 | + * | ||
| 22 | + * @param createReqVO 创建信息 | ||
| 23 | + * @return 编号 | ||
| 24 | + */ | ||
| 25 | + Long createPluginInfo(@Valid PluginInfoSaveReqVO createReqVO); | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 更新IoT 插件信息 | ||
| 29 | + * | ||
| 30 | + * @param updateReqVO 更新信息 | ||
| 31 | + */ | ||
| 32 | + void updatePluginInfo(@Valid PluginInfoSaveReqVO updateReqVO); | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 删除IoT 插件信息 | ||
| 36 | + * | ||
| 37 | + * @param id 编号 | ||
| 38 | + */ | ||
| 39 | + void deletePluginInfo(Long id); | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 获得IoT 插件信息 | ||
| 43 | + * | ||
| 44 | + * @param id 编号 | ||
| 45 | + * @return IoT 插件信息 | ||
| 46 | + */ | ||
| 47 | + PluginInfoDO getPluginInfo(Long id); | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * 获得IoT 插件信息分页 | ||
| 51 | + * | ||
| 52 | + * @param pageReqVO 分页查询 | ||
| 53 | + * @return IoT 插件信息分页 | ||
| 54 | + */ | ||
| 55 | + PageResult<PluginInfoDO> getPluginInfoPage(PluginInfoPageReqVO pageReqVO); | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * 上传插件的 JAR 包 | ||
| 59 | + * | ||
| 60 | + * @param id 插件id | ||
| 61 | + * @param file 文件 | ||
| 62 | + */ | ||
| 63 | + void uploadJar(Long id, MultipartFile file); | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * 更新插件的状态 | ||
| 67 | + * | ||
| 68 | + * @param id 插件id | ||
| 69 | + * @param status 状态 | ||
| 70 | + */ | ||
| 71 | + void updatePluginStatus(Long id, Integer status); | ||
| 72 | +} | ||
| 0 | \ No newline at end of file | 73 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.plugininfo; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.io.IoUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 6 | +import cn.iocoder.yudao.module.infra.api.file.FileApi; | ||
| 7 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; | ||
| 8 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; | ||
| 9 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; | ||
| 10 | +import cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper; | ||
| 11 | +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; | ||
| 12 | +import jakarta.annotation.PostConstruct; | ||
| 13 | +import jakarta.annotation.Resource; | ||
| 14 | +import lombok.SneakyThrows; | ||
| 15 | +import lombok.extern.slf4j.Slf4j; | ||
| 16 | +import org.pf4j.PluginDescriptor; | ||
| 17 | +import org.pf4j.PluginState; | ||
| 18 | +import org.pf4j.PluginWrapper; | ||
| 19 | +import org.pf4j.spring.SpringPluginManager; | ||
| 20 | +import org.springframework.stereotype.Service; | ||
| 21 | +import org.springframework.validation.annotation.Validated; | ||
| 22 | +import org.springframework.web.multipart.MultipartFile; | ||
| 23 | + | ||
| 24 | +import java.nio.file.Path; | ||
| 25 | +import java.util.concurrent.Executors; | ||
| 26 | +import java.util.concurrent.TimeUnit; | ||
| 27 | + | ||
| 28 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 29 | +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * IoT 插件信息 Service 实现类 | ||
| 33 | + * | ||
| 34 | + * @author 芋道源码 | ||
| 35 | + */ | ||
| 36 | +@Service | ||
| 37 | +@Validated | ||
| 38 | +@Slf4j | ||
| 39 | +public class PluginInfoServiceImpl implements PluginInfoService { | ||
| 40 | + | ||
| 41 | + @Resource | ||
| 42 | + private PluginInfoMapper pluginInfoMapper; | ||
| 43 | + | ||
| 44 | + @Resource | ||
| 45 | + private SpringPluginManager pluginManager; | ||
| 46 | + | ||
| 47 | + @Resource | ||
| 48 | + private FileApi fileApi; | ||
| 49 | + | ||
| 50 | + @Override | ||
| 51 | + public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) { | ||
| 52 | + // 插入 | ||
| 53 | + PluginInfoDO pluginInfo = BeanUtils.toBean(createReqVO, PluginInfoDO.class); | ||
| 54 | + pluginInfoMapper.insert(pluginInfo); | ||
| 55 | + // 返回 | ||
| 56 | + return pluginInfo.getId(); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + @Override | ||
| 60 | + public void updatePluginInfo(PluginInfoSaveReqVO updateReqVO) { | ||
| 61 | + // 校验存在 | ||
| 62 | + validatePluginInfoExists(updateReqVO.getId()); | ||
| 63 | + // 更新 | ||
| 64 | + PluginInfoDO updateObj = BeanUtils.toBean(updateReqVO, PluginInfoDO.class); | ||
| 65 | + pluginInfoMapper.updateById(updateObj); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @Override | ||
| 69 | + public void deletePluginInfo(Long id) { | ||
| 70 | + // 校验存在 | ||
| 71 | + PluginInfoDO pluginInfoDO = validatePluginInfoExists(id); | ||
| 72 | + | ||
| 73 | + // 停止插件 | ||
| 74 | + if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { | ||
| 75 | + throw exception(PLUGIN_INFO_DELETE_FAILED_RUNNING); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + // 卸载插件 | ||
| 79 | + PluginWrapper plugin = pluginManager.getPlugin(pluginInfoDO.getPluginId()); | ||
| 80 | + if (plugin != null) { | ||
| 81 | + // 查询插件是否是启动状态 | ||
| 82 | + if (plugin.getPluginState().equals(PluginState.STARTED)) { | ||
| 83 | + // 停止插件 | ||
| 84 | + pluginManager.stopPlugin(plugin.getPluginId()); | ||
| 85 | + } | ||
| 86 | + // 卸载插件 | ||
| 87 | + pluginManager.unloadPlugin(plugin.getPluginId()); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + // 删除 | ||
| 91 | + pluginInfoMapper.deleteById(id); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + private PluginInfoDO validatePluginInfoExists(Long id) { | ||
| 95 | + PluginInfoDO pluginInfo = pluginInfoMapper.selectById(id); | ||
| 96 | + if (pluginInfo == null) { | ||
| 97 | + throw exception(PLUGIN_INFO_NOT_EXISTS); | ||
| 98 | + } | ||
| 99 | + return pluginInfo; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + @Override | ||
| 103 | + public PluginInfoDO getPluginInfo(Long id) { | ||
| 104 | + return pluginInfoMapper.selectById(id); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Override | ||
| 108 | + public PageResult<PluginInfoDO> getPluginInfoPage(PluginInfoPageReqVO pageReqVO) { | ||
| 109 | + return pluginInfoMapper.selectPage(pageReqVO); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + @Override | ||
| 113 | + public void uploadJar(Long id, MultipartFile file) { | ||
| 114 | + // 1. 校验存在 | ||
| 115 | + PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); | ||
| 116 | + | ||
| 117 | + // 2. 判断文件名称与插件 ID 是否匹配 | ||
| 118 | + String pluginId = pluginInfoDo.getPluginId(); | ||
| 119 | + | ||
| 120 | + // 3. 停止卸载旧的插件 | ||
| 121 | + // 3.1. 获取插件信息 | ||
| 122 | + PluginWrapper plugin = pluginManager.getPlugin(pluginId); | ||
| 123 | + if (plugin != null) { | ||
| 124 | + // 3.2. 如果插件状态是启动的,停止插件 | ||
| 125 | + if (plugin.getPluginState().equals(PluginState.STARTED)) { | ||
| 126 | + pluginManager.stopPlugin(pluginId); | ||
| 127 | + } | ||
| 128 | + // 3.3. 卸载插件 | ||
| 129 | + pluginManager.unloadPlugin(pluginId); | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + // 4. 上传插件 | ||
| 133 | + String pluginIdNew; | ||
| 134 | + try { | ||
| 135 | + String path = fileApi.createFile(IoUtil.readBytes(file.getInputStream())); | ||
| 136 | + Path pluginPath = Path.of(path); | ||
| 137 | + pluginIdNew = pluginManager.loadPlugin(pluginPath); | ||
| 138 | + } catch (Exception e) { | ||
| 139 | + throw exception(PLUGIN_INSTALL_FAILED); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginIdNew); | ||
| 143 | + if (pluginWrapper == null) { | ||
| 144 | + throw exception(PLUGIN_INSTALL_FAILED); | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + | ||
| 148 | + // 5. 读取配置文件和脚本 | ||
| 149 | + String configJson = ""; | ||
| 150 | + String script = ""; | ||
| 151 | + | ||
| 152 | + pluginInfoDo.setPluginId(pluginIdNew); | ||
| 153 | + pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); | ||
| 154 | + pluginInfoDo.setFile(file.getOriginalFilename()); | ||
| 155 | + pluginInfoDo.setConfigSchema(configJson); | ||
| 156 | + pluginInfoDo.setScript(script); | ||
| 157 | + | ||
| 158 | + PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); | ||
| 159 | + pluginInfoDo.setVersion(pluginDescriptor.getVersion()); | ||
| 160 | + pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription()); | ||
| 161 | + pluginInfoMapper.updateById(pluginInfoDo); | ||
| 162 | + | ||
| 163 | + | ||
| 164 | + // 5. 读取配置文件和脚本 | ||
| 165 | +// String configJson = ""; | ||
| 166 | + // String script = ""; | ||
| 167 | +// try (JarFile jarFile = new JarFile(pluginInfoUpdate.getPluginPath())) { | ||
| 168 | +// // 5.1 获取config文件在jar包中的路径 | ||
| 169 | +// String configFile = "classes/config.json"; | ||
| 170 | +// JarEntry configEntry = jarFile.getJarEntry(configFile); | ||
| 171 | +// | ||
| 172 | +// if (configEntry != null) { | ||
| 173 | +// // 5.2 读取配置文件 | ||
| 174 | +// configJson = IoUtil.read(jarFile.getInputStream(configEntry), Charset.defaultCharset()); | ||
| 175 | +// log.info("configJson:{}", configJson); | ||
| 176 | +// } | ||
| 177 | +// | ||
| 178 | +// // 5.3 读取script.js脚本 | ||
| 179 | +// String scriptFile = "classes/script.js"; | ||
| 180 | +// JarEntry scriptEntity = jarFile.getJarEntry(scriptFile); | ||
| 181 | +// if (scriptEntity != null) { | ||
| 182 | +// // 5.4 读取脚本文件 | ||
| 183 | +// script = IoUtil.read(jarFile.getInputStream(scriptEntity), Charset.defaultCharset()); | ||
| 184 | +// log.info("script:{}", script); | ||
| 185 | +// } | ||
| 186 | +// } catch (Exception e) { | ||
| 187 | +// throw exception(PLUGIN_INSTALL_FAILED); | ||
| 188 | +// } | ||
| 189 | + | ||
| 190 | + | ||
| 191 | +// PluginState pluginState = pluginInfoUpdate.getPluginState(); | ||
| 192 | +// if (pluginState == PluginState.STARTED) { | ||
| 193 | +// pluginInfoDo.setStatus(IotPluginStatusEnum.RUNNING.getStatus()); | ||
| 194 | +// } | ||
| 195 | +// pluginInfoDo.setPluginId(pluginInfoUpdate.getPluginId()); | ||
| 196 | +// pluginInfoDo.setFile(file.getOriginalFilename()); | ||
| 197 | +// pluginInfoDo.setConfigSchema(configJson); | ||
| 198 | +// pluginInfoDo.setScript(script); | ||
| 199 | +// | ||
| 200 | +// PluginDescriptor pluginDescriptor = pluginInfoUpdate.getPluginDescriptor(); | ||
| 201 | +// pluginInfoDo.setVersion(pluginDescriptor.getPluginVersion()); | ||
| 202 | +// pluginInfoDo.setDescription(pluginDescriptor.getDescription()); | ||
| 203 | +// pluginInfoMapper.updateById(pluginInfoDo); | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + @Override | ||
| 207 | + public void updatePluginStatus(Long id, Integer status) { | ||
| 208 | + // 1. 校验存在 | ||
| 209 | + PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); | ||
| 210 | + | ||
| 211 | + // 插件状态无效 | ||
| 212 | + if (!IotPluginStatusEnum.contains(status)) { | ||
| 213 | + throw exception(PLUGIN_STATUS_INVALID); | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + // 插件包为空 | ||
| 217 | +// String pluginId = pluginInfoDo.getPluginId(); | ||
| 218 | +// if (StrUtil.isBlank(pluginId)) { | ||
| 219 | +// throw exception(PLUGIN_INFO_NOT_EXISTS); | ||
| 220 | +// } | ||
| 221 | +// com.gitee.starblues.core.PluginInfo pluginInfo = pluginOperator.getPluginInfo(pluginId); | ||
| 222 | +// if (pluginInfo != null) { | ||
| 223 | +// if (pluginInfoDo.getStatus().equals(IotPluginStatusEnum.RUNNING.getStatus()) && pluginInfo.getPluginState() != PluginState.STARTED) { | ||
| 224 | +// // 启动插件 | ||
| 225 | +// pluginOperator.start(pluginId); | ||
| 226 | +// } else if (pluginInfoDo.getStatus().equals(IotPluginStatusEnum.STOPPED.getStatus()) && pluginInfo.getPluginState() == PluginState.STARTED) { | ||
| 227 | +// // 停止插件 | ||
| 228 | +// pluginOperator.stop(pluginId); | ||
| 229 | +// } | ||
| 230 | +// } else { | ||
| 231 | +// // 已经停止,未获取到插件 | ||
| 232 | +// if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { | ||
| 233 | +// throw exception(PLUGIN_STATUS_INVALID); | ||
| 234 | +// } | ||
| 235 | +// } | ||
| 236 | + pluginInfoDo.setStatus(status); | ||
| 237 | + pluginInfoMapper.updateById(pluginInfoDo); | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + @PostConstruct | ||
| 241 | + public void init() { | ||
| 242 | + Executors.newSingleThreadScheduledExecutor().schedule(this::startPlugins, 3, TimeUnit.SECONDS); | ||
| 243 | + } | ||
| 244 | + | ||
| 245 | + @SneakyThrows | ||
| 246 | + private void startPlugins() { | ||
| 247 | +// while (!pluginOperator.inited()) { | ||
| 248 | +// Thread.sleep(1000L); | ||
| 249 | +// } | ||
| 250 | + | ||
| 251 | + for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { | ||
| 252 | + if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { | ||
| 253 | + continue; | ||
| 254 | + } | ||
| 255 | + log.info("start plugin:{}", pluginInfoDO.getPluginId()); | ||
| 256 | + try { | ||
| 257 | +// com.gitee.starblues.core.PluginInfo plugin = pluginOperator.getPluginInfo(pluginInfoDO.getPluginId()); | ||
| 258 | +// if (plugin != null) { | ||
| 259 | +// pluginOperator.start(plugin.getPluginId()); | ||
| 260 | +// } | ||
| 261 | + } catch (Exception e) { | ||
| 262 | + log.error("start plugin error", e); | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | +} | ||
| 0 | \ No newline at end of file | 268 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.plugininstance; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstancePageReqVO; | ||
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstanceSaveReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; | ||
| 7 | +import jakarta.validation.Valid; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * IoT 插件实例 Service 接口 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +public interface PluginInstanceService { | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 创建IoT 插件实例 | ||
| 18 | + * | ||
| 19 | + * @param createReqVO 创建信息 | ||
| 20 | + * @return 编号 | ||
| 21 | + */ | ||
| 22 | + Long createPluginInstance(@Valid PluginInstanceSaveReqVO createReqVO); | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 更新IoT 插件实例 | ||
| 26 | + * | ||
| 27 | + * @param updateReqVO 更新信息 | ||
| 28 | + */ | ||
| 29 | + void updatePluginInstance(@Valid PluginInstanceSaveReqVO updateReqVO); | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 删除IoT 插件实例 | ||
| 33 | + * | ||
| 34 | + * @param id 编号 | ||
| 35 | + */ | ||
| 36 | + void deletePluginInstance(Long id); | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 获得IoT 插件实例 | ||
| 40 | + * | ||
| 41 | + * @param id 编号 | ||
| 42 | + * @return IoT 插件实例 | ||
| 43 | + */ | ||
| 44 | + PluginInstanceDO getPluginInstance(Long id); | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 获得IoT 插件实例分页 | ||
| 48 | + * | ||
| 49 | + * @param pageReqVO 分页查询 | ||
| 50 | + * @return IoT 插件实例分页 | ||
| 51 | + */ | ||
| 52 | + PageResult<PluginInstanceDO> getPluginInstancePage(PluginInstancePageReqVO pageReqVO); | ||
| 53 | + | ||
| 54 | +} | ||
| 0 | \ No newline at end of file | 55 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.plugininstance; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstancePageReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.PluginInstanceSaveReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; | ||
| 8 | +import cn.iocoder.yudao.module.iot.dal.mysql.plugininstance.PluginInstanceMapper; | ||
| 9 | +import jakarta.annotation.Resource; | ||
| 10 | +import org.springframework.stereotype.Service; | ||
| 11 | +import org.springframework.validation.annotation.Validated; | ||
| 12 | + | ||
| 13 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 14 | +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INSTANCE_NOT_EXISTS; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * IoT 插件实例 Service 实现类 | ||
| 18 | + * | ||
| 19 | + * @author 芋道源码 | ||
| 20 | + */ | ||
| 21 | +@Service | ||
| 22 | +@Validated | ||
| 23 | +public class PluginInstanceServiceImpl implements PluginInstanceService { | ||
| 24 | + | ||
| 25 | + @Resource | ||
| 26 | + private PluginInstanceMapper pluginInstanceMapper; | ||
| 27 | + | ||
| 28 | + @Override | ||
| 29 | + public Long createPluginInstance(PluginInstanceSaveReqVO createReqVO) { | ||
| 30 | + // 插入 | ||
| 31 | + PluginInstanceDO pluginInstance = BeanUtils.toBean(createReqVO, PluginInstanceDO.class); | ||
| 32 | + pluginInstanceMapper.insert(pluginInstance); | ||
| 33 | + // 返回 | ||
| 34 | + return pluginInstance.getId(); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + @Override | ||
| 38 | + public void updatePluginInstance(PluginInstanceSaveReqVO updateReqVO) { | ||
| 39 | + // 校验存在 | ||
| 40 | + validatePluginInstanceExists(updateReqVO.getId()); | ||
| 41 | + // 更新 | ||
| 42 | + PluginInstanceDO updateObj = BeanUtils.toBean(updateReqVO, PluginInstanceDO.class); | ||
| 43 | + pluginInstanceMapper.updateById(updateObj); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + @Override | ||
| 47 | + public void deletePluginInstance(Long id) { | ||
| 48 | + // 校验存在 | ||
| 49 | + validatePluginInstanceExists(id); | ||
| 50 | + // 删除 | ||
| 51 | + pluginInstanceMapper.deleteById(id); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + private void validatePluginInstanceExists(Long id) { | ||
| 55 | + if (pluginInstanceMapper.selectById(id) == null) { | ||
| 56 | + throw exception(PLUGIN_INSTANCE_NOT_EXISTS); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + @Override | ||
| 61 | + public PluginInstanceDO getPluginInstance(Long id) { | ||
| 62 | + return pluginInstanceMapper.selectById(id); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + @Override | ||
| 66 | + public PageResult<PluginInstanceDO> getPluginInstancePage(PluginInstancePageReqVO pageReqVO) { | ||
| 67 | + return pluginInstanceMapper.selectPage(pageReqVO); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | +} | ||
| 0 | \ No newline at end of file | 71 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininfo/PluginInfoMapper.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
| 3 | +<mapper namespace="cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper"> | ||
| 4 | + | ||
| 5 | + <!-- | ||
| 6 | + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。 | ||
| 7 | + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。 | ||
| 8 | + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。 | ||
| 9 | + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/ | ||
| 10 | + --> | ||
| 11 | + | ||
| 12 | +</mapper> | ||
| 0 | \ No newline at end of file | 13 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
| 3 | +<mapper namespace="cn.iocoder.yudao.module.iot.dal.mysql.plugininstance.PluginInstanceMapper"> | ||
| 4 | + | ||
| 5 | + <!-- | ||
| 6 | + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。 | ||
| 7 | + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。 | ||
| 8 | + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。 | ||
| 9 | + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/ | ||
| 10 | + --> | ||
| 11 | + | ||
| 12 | +</mapper> | ||
| 0 | \ No newline at end of file | 13 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImplTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.plugininfo; | ||
| 2 | + | ||
| 3 | +import org.junit.jupiter.api.Disabled; | ||
| 4 | +import org.junit.jupiter.api.Test; | ||
| 5 | + | ||
| 6 | +import jakarta.annotation.Resource; | ||
| 7 | + | ||
| 8 | +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | ||
| 9 | + | ||
| 10 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.*; | ||
| 11 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; | ||
| 12 | +import cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper; | ||
| 13 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 14 | + | ||
| 15 | +import org.springframework.context.annotation.Import; | ||
| 16 | + | ||
| 17 | +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; | ||
| 18 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; | ||
| 19 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; | ||
| 20 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; | ||
| 21 | +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; | ||
| 22 | +import static org.junit.jupiter.api.Assertions.*; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * {@link PluginInfoServiceImpl} 的单元测试类 | ||
| 26 | + * | ||
| 27 | + * @author 芋道源码 | ||
| 28 | + */ | ||
| 29 | +@Import(PluginInfoServiceImpl.class) | ||
| 30 | +public class PluginInfoServiceImplTest extends BaseDbUnitTest { | ||
| 31 | + | ||
| 32 | + @Resource | ||
| 33 | + private PluginInfoServiceImpl pluginInfoService; | ||
| 34 | + | ||
| 35 | + @Resource | ||
| 36 | + private PluginInfoMapper pluginInfoMapper; | ||
| 37 | + | ||
| 38 | + @Test | ||
| 39 | + public void testCreatePluginInfo_success() { | ||
| 40 | + // 准备参数 | ||
| 41 | + PluginInfoSaveReqVO createReqVO = randomPojo(PluginInfoSaveReqVO.class).setId(null); | ||
| 42 | + | ||
| 43 | + // 调用 | ||
| 44 | + Long pluginInfoId = pluginInfoService.createPluginInfo(createReqVO); | ||
| 45 | + // 断言 | ||
| 46 | + assertNotNull(pluginInfoId); | ||
| 47 | + // 校验记录的属性是否正确 | ||
| 48 | + PluginInfoDO pluginInfo = pluginInfoMapper.selectById(pluginInfoId); | ||
| 49 | + assertPojoEquals(createReqVO, pluginInfo, "id"); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + @Test | ||
| 53 | + public void testUpdatePluginInfo_success() { | ||
| 54 | + // mock 数据 | ||
| 55 | + PluginInfoDO dbPluginInfo = randomPojo(PluginInfoDO.class); | ||
| 56 | + pluginInfoMapper.insert(dbPluginInfo);// @Sql: 先插入出一条存在的数据 | ||
| 57 | + // 准备参数 | ||
| 58 | + PluginInfoSaveReqVO updateReqVO = randomPojo(PluginInfoSaveReqVO.class, o -> { | ||
| 59 | + o.setId(dbPluginInfo.getId()); // 设置更新的 ID | ||
| 60 | + }); | ||
| 61 | + | ||
| 62 | + // 调用 | ||
| 63 | + pluginInfoService.updatePluginInfo(updateReqVO); | ||
| 64 | + // 校验是否更新正确 | ||
| 65 | + PluginInfoDO pluginInfo = pluginInfoMapper.selectById(updateReqVO.getId()); // 获取最新的 | ||
| 66 | + assertPojoEquals(updateReqVO, pluginInfo); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + @Test | ||
| 70 | + public void testUpdatePluginInfo_notExists() { | ||
| 71 | + // 准备参数 | ||
| 72 | + PluginInfoSaveReqVO updateReqVO = randomPojo(PluginInfoSaveReqVO.class); | ||
| 73 | + | ||
| 74 | + // 调用, 并断言异常 | ||
| 75 | + assertServiceException(() -> pluginInfoService.updatePluginInfo(updateReqVO), PLUGIN_INFO_NOT_EXISTS); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @Test | ||
| 79 | + public void testDeletePluginInfo_success() { | ||
| 80 | + // mock 数据 | ||
| 81 | + PluginInfoDO dbPluginInfo = randomPojo(PluginInfoDO.class); | ||
| 82 | + pluginInfoMapper.insert(dbPluginInfo);// @Sql: 先插入出一条存在的数据 | ||
| 83 | + // 准备参数 | ||
| 84 | + Long id = dbPluginInfo.getId(); | ||
| 85 | + | ||
| 86 | + // 调用 | ||
| 87 | + pluginInfoService.deletePluginInfo(id); | ||
| 88 | + // 校验数据不存在了 | ||
| 89 | + assertNull(pluginInfoMapper.selectById(id)); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + @Test | ||
| 93 | + public void testDeletePluginInfo_notExists() { | ||
| 94 | + // 准备参数 | ||
| 95 | + Long id = randomLongId(); | ||
| 96 | + | ||
| 97 | + // 调用, 并断言异常 | ||
| 98 | + assertServiceException(() -> pluginInfoService.deletePluginInfo(id), PLUGIN_INFO_NOT_EXISTS); | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + @Test | ||
| 102 | + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 | ||
| 103 | + public void testGetPluginInfoPage() { | ||
| 104 | + // mock 数据 | ||
| 105 | + PluginInfoDO dbPluginInfo = randomPojo(PluginInfoDO.class, o -> { // 等会查询到 | ||
| 106 | + o.setPluginId(null); | ||
| 107 | + o.setName(null); | ||
| 108 | + o.setDescription(null); | ||
| 109 | + o.setDeployType(null); | ||
| 110 | + o.setFile(null); | ||
| 111 | + o.setVersion(null); | ||
| 112 | + o.setType(null); | ||
| 113 | + o.setProtocol(null); | ||
| 114 | + o.setStatus(null); | ||
| 115 | + o.setConfigSchema(null); | ||
| 116 | + o.setConfig(null); | ||
| 117 | + o.setScript(null); | ||
| 118 | + o.setCreateTime(null); | ||
| 119 | + }); | ||
| 120 | + pluginInfoMapper.insert(dbPluginInfo); | ||
| 121 | + // 测试 pluginId 不匹配 | ||
| 122 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setPluginId(null))); | ||
| 123 | + // 测试 name 不匹配 | ||
| 124 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setName(null))); | ||
| 125 | + // 测试 description 不匹配 | ||
| 126 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setDescription(null))); | ||
| 127 | + // 测试 deployType 不匹配 | ||
| 128 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setDeployType(null))); | ||
| 129 | + // 测试 file 不匹配 | ||
| 130 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setFile(null))); | ||
| 131 | + // 测试 version 不匹配 | ||
| 132 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setVersion(null))); | ||
| 133 | + // 测试 type 不匹配 | ||
| 134 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setType(null))); | ||
| 135 | + // 测试 protocol 不匹配 | ||
| 136 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setProtocol(null))); | ||
| 137 | + // 测试 state 不匹配 | ||
| 138 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setStatus(null))); | ||
| 139 | + // 测试 configSchema 不匹配 | ||
| 140 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setConfigSchema(null))); | ||
| 141 | + // 测试 config 不匹配 | ||
| 142 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setConfig(null))); | ||
| 143 | + // 测试 script 不匹配 | ||
| 144 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setScript(null))); | ||
| 145 | + // 测试 createTime 不匹配 | ||
| 146 | + pluginInfoMapper.insert(cloneIgnoreId(dbPluginInfo, o -> o.setCreateTime(null))); | ||
| 147 | + // 准备参数 | ||
| 148 | + PluginInfoPageReqVO reqVO = new PluginInfoPageReqVO(); | ||
| 149 | + reqVO.setPluginId(null); | ||
| 150 | + reqVO.setName(null); | ||
| 151 | + reqVO.setDescription(null); | ||
| 152 | + reqVO.setDeployType(null); | ||
| 153 | + reqVO.setFile(null); | ||
| 154 | + reqVO.setVersion(null); | ||
| 155 | + reqVO.setType(null); | ||
| 156 | + reqVO.setProtocol(null); | ||
| 157 | + reqVO.setStatus(null); | ||
| 158 | + reqVO.setConfigSchema(null); | ||
| 159 | + reqVO.setConfig(null); | ||
| 160 | + reqVO.setScript(null); | ||
| 161 | + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); | ||
| 162 | + | ||
| 163 | + // 调用 | ||
| 164 | + PageResult<PluginInfoDO> pageResult = pluginInfoService.getPluginInfoPage(reqVO); | ||
| 165 | + // 断言 | ||
| 166 | + assertEquals(1, pageResult.getTotal()); | ||
| 167 | + assertEquals(1, pageResult.getList().size()); | ||
| 168 | + assertPojoEquals(dbPluginInfo, pageResult.getList().get(0)); | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | +} | ||
| 0 | \ No newline at end of file | 172 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImplTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.plugininstance; | ||
| 2 | + | ||
| 3 | +import org.junit.jupiter.api.Disabled; | ||
| 4 | +import org.junit.jupiter.api.Test; | ||
| 5 | +import org.springframework.boot.test.mock.mockito.MockBean; | ||
| 6 | + | ||
| 7 | +import jakarta.annotation.Resource; | ||
| 8 | + | ||
| 9 | +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | ||
| 10 | + | ||
| 11 | +import cn.iocoder.yudao.module.iot.controller.admin.plugininstance.vo.*; | ||
| 12 | +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; | ||
| 13 | +import cn.iocoder.yudao.module.iot.dal.mysql.plugininstance.PluginInstanceMapper; | ||
| 14 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 15 | + | ||
| 16 | +import jakarta.annotation.Resource; | ||
| 17 | +import org.springframework.context.annotation.Import; | ||
| 18 | +import java.util.*; | ||
| 19 | +import java.time.LocalDateTime; | ||
| 20 | + | ||
| 21 | +import static cn.hutool.core.util.RandomUtil.*; | ||
| 22 | +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; | ||
| 23 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; | ||
| 24 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; | ||
| 25 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; | ||
| 26 | +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; | ||
| 27 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; | ||
| 28 | +import static org.junit.jupiter.api.Assertions.*; | ||
| 29 | +import static org.mockito.Mockito.*; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * {@link PluginInstanceServiceImpl} 的单元测试类 | ||
| 33 | + * | ||
| 34 | + * @author 芋道源码 | ||
| 35 | + */ | ||
| 36 | +@Import(PluginInstanceServiceImpl.class) | ||
| 37 | +public class PluginInstanceServiceImplTest extends BaseDbUnitTest { | ||
| 38 | + | ||
| 39 | + @Resource | ||
| 40 | + private PluginInstanceServiceImpl pluginInstanceService; | ||
| 41 | + | ||
| 42 | + @Resource | ||
| 43 | + private PluginInstanceMapper pluginInstanceMapper; | ||
| 44 | + | ||
| 45 | + @Test | ||
| 46 | + public void testCreatePluginInstance_success() { | ||
| 47 | + // 准备参数 | ||
| 48 | + PluginInstanceSaveReqVO createReqVO = randomPojo(PluginInstanceSaveReqVO.class).setId(null); | ||
| 49 | + | ||
| 50 | + // 调用 | ||
| 51 | + Long pluginInstanceId = pluginInstanceService.createPluginInstance(createReqVO); | ||
| 52 | + // 断言 | ||
| 53 | + assertNotNull(pluginInstanceId); | ||
| 54 | + // 校验记录的属性是否正确 | ||
| 55 | + PluginInstanceDO pluginInstance = pluginInstanceMapper.selectById(pluginInstanceId); | ||
| 56 | + assertPojoEquals(createReqVO, pluginInstance, "id"); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + @Test | ||
| 60 | + public void testUpdatePluginInstance_success() { | ||
| 61 | + // mock 数据 | ||
| 62 | + PluginInstanceDO dbPluginInstance = randomPojo(PluginInstanceDO.class); | ||
| 63 | + pluginInstanceMapper.insert(dbPluginInstance);// @Sql: 先插入出一条存在的数据 | ||
| 64 | + // 准备参数 | ||
| 65 | + PluginInstanceSaveReqVO updateReqVO = randomPojo(PluginInstanceSaveReqVO.class, o -> { | ||
| 66 | + o.setId(dbPluginInstance.getId()); // 设置更新的 ID | ||
| 67 | + }); | ||
| 68 | + | ||
| 69 | + // 调用 | ||
| 70 | + pluginInstanceService.updatePluginInstance(updateReqVO); | ||
| 71 | + // 校验是否更新正确 | ||
| 72 | + PluginInstanceDO pluginInstance = pluginInstanceMapper.selectById(updateReqVO.getId()); // 获取最新的 | ||
| 73 | + assertPojoEquals(updateReqVO, pluginInstance); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + @Test | ||
| 77 | + public void testUpdatePluginInstance_notExists() { | ||
| 78 | + // 准备参数 | ||
| 79 | + PluginInstanceSaveReqVO updateReqVO = randomPojo(PluginInstanceSaveReqVO.class); | ||
| 80 | + | ||
| 81 | + // 调用, 并断言异常 | ||
| 82 | + assertServiceException(() -> pluginInstanceService.updatePluginInstance(updateReqVO), PLUGIN_INSTANCE_NOT_EXISTS); | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + @Test | ||
| 86 | + public void testDeletePluginInstance_success() { | ||
| 87 | + // mock 数据 | ||
| 88 | + PluginInstanceDO dbPluginInstance = randomPojo(PluginInstanceDO.class); | ||
| 89 | + pluginInstanceMapper.insert(dbPluginInstance);// @Sql: 先插入出一条存在的数据 | ||
| 90 | + // 准备参数 | ||
| 91 | + Long id = dbPluginInstance.getId(); | ||
| 92 | + | ||
| 93 | + // 调用 | ||
| 94 | + pluginInstanceService.deletePluginInstance(id); | ||
| 95 | + // 校验数据不存在了 | ||
| 96 | + assertNull(pluginInstanceMapper.selectById(id)); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + @Test | ||
| 100 | + public void testDeletePluginInstance_notExists() { | ||
| 101 | + // 准备参数 | ||
| 102 | + Long id = randomLongId(); | ||
| 103 | + | ||
| 104 | + // 调用, 并断言异常 | ||
| 105 | + assertServiceException(() -> pluginInstanceService.deletePluginInstance(id), PLUGIN_INSTANCE_NOT_EXISTS); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + @Test | ||
| 109 | + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 | ||
| 110 | + public void testGetPluginInstancePage() { | ||
| 111 | + // mock 数据 | ||
| 112 | + PluginInstanceDO dbPluginInstance = randomPojo(PluginInstanceDO.class, o -> { // 等会查询到 | ||
| 113 | + o.setMainId(null); | ||
| 114 | + o.setPluginId(null); | ||
| 115 | + o.setIp(null); | ||
| 116 | + o.setPort(null); | ||
| 117 | + o.setHeartbeatAt(null); | ||
| 118 | + o.setCreateTime(null); | ||
| 119 | + }); | ||
| 120 | + pluginInstanceMapper.insert(dbPluginInstance); | ||
| 121 | + // 测试 mainId 不匹配 | ||
| 122 | + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setMainId(null))); | ||
| 123 | + // 测试 pluginId 不匹配 | ||
| 124 | + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setPluginId(null))); | ||
| 125 | + // 测试 ip 不匹配 | ||
| 126 | + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setIp(null))); | ||
| 127 | + // 测试 port 不匹配 | ||
| 128 | + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setPort(null))); | ||
| 129 | + // 测试 heartbeatAt 不匹配 | ||
| 130 | + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setHeartbeatAt(null))); | ||
| 131 | + // 测试 createTime 不匹配 | ||
| 132 | + pluginInstanceMapper.insert(cloneIgnoreId(dbPluginInstance, o -> o.setCreateTime(null))); | ||
| 133 | + // 准备参数 | ||
| 134 | + PluginInstancePageReqVO reqVO = new PluginInstancePageReqVO(); | ||
| 135 | + reqVO.setMainId(null); | ||
| 136 | + reqVO.setPluginId(null); | ||
| 137 | + reqVO.setIp(null); | ||
| 138 | + reqVO.setPort(null); | ||
| 139 | + reqVO.setHeartbeatAt(null); | ||
| 140 | + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); | ||
| 141 | + | ||
| 142 | + // 调用 | ||
| 143 | + PageResult<PluginInstanceDO> pageResult = pluginInstanceService.getPluginInstancePage(reqVO); | ||
| 144 | + // 断言 | ||
| 145 | + assertEquals(1, pageResult.getTotal()); | ||
| 146 | + assertEquals(1, pageResult.getList().size()); | ||
| 147 | + assertPojoEquals(dbPluginInstance, pageResult.getList().get(0)); | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | +} | ||
| 0 | \ No newline at end of file | 151 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-plugin/pom.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| 5 | + <parent> | ||
| 6 | + <artifactId>yudao-module-iot</artifactId> | ||
| 7 | + <groupId>cn.iocoder.boot</groupId> | ||
| 8 | + <version>${revision}</version> | ||
| 9 | + </parent> | ||
| 10 | + <modelVersion>4.0.0</modelVersion> | ||
| 11 | + <artifactId>yudao-module-iot-plugin</artifactId> | ||
| 12 | + <packaging>jar</packaging> | ||
| 13 | + | ||
| 14 | + <name>${project.artifactId}</name> | ||
| 15 | + <description> | ||
| 16 | + 物联网 模块 - 插件 | ||
| 17 | + </description> | ||
| 18 | + | ||
| 19 | + <dependencies> | ||
| 20 | + <dependency> | ||
| 21 | + <groupId>cn.iocoder.boot</groupId> | ||
| 22 | + <artifactId>yudao-common</artifactId> | ||
| 23 | + </dependency> | ||
| 24 | + | ||
| 25 | + <dependency> | ||
| 26 | + <groupId>org.pf4j</groupId> | ||
| 27 | + <artifactId>pf4j-spring</artifactId> | ||
| 28 | + </dependency> | ||
| 29 | + </dependencies> | ||
| 30 | + | ||
| 31 | +</project> |