From 290fcd94d56334e4706935a5b250c1d925a5eaee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Mon, 16 Dec 2024 18:18:53 +0800
Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0=E5=A2=9E?=
=?UTF-8?q?=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=E6=8F=92=E4=BB=B6?=
=?UTF-8?q?=E6=94=AF=E6=8C=81=EF=BC=8C=E5=8C=85=E5=90=AB=E6=8F=92=E4=BB=B6?=
=?UTF-8?q?API=E5=92=8C=E7=A4=BA=E4=BE=8B=E6=8E=A7=E5=88=B6=E5=99=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yudao-module-iot/pom.xml | 1 +
yudao-module-iot/yudao-module-iot-biz/pom.xml | 8 +
.../admin/plugininfo/Greetings.java | 40 +++++
.../admin/plugininfo/PluginController.java | 134 ++++++++++++++++
.../admin/plugininfo/WhazzupGreeting.java | 34 ++++
.../framework/plugin/SpringConfiguration.java | 8 +
.../service/plugininfo/PluginInfoService.java | 6 +-
.../plugininfo/PluginInfoServiceImpl.java | 120 ++++++--------
.../yudao-module-iot-plugin-api/pom.xml | 30 ++++
.../yudao/module/iot/api/Greeting.java | 27 ++++
.../yudao/module/iot/api}/package-info.java | 2 +-
.../yudao-module-iot-plugin/plugin.properties | 5 +
.../yudao-module-iot-plugin/pom.xml | 148 ++++++++++++++++--
.../src/main/assembly/assembly.xml | 37 +++++
.../iot/plugin/IoTHttpPluginController.java | 22 +++
.../yudao/module/iot/plugin/IoTPlugin.java | 33 ++++
.../module/iot/plugin/IotPluginConfig.java | 16 ++
.../module/iot/plugin/WelcomePlugin.java | 58 +++++++
18 files changed, 637 insertions(+), 92 deletions(-)
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java
create mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/pom.xml
create mode 100644 yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java
rename yudao-module-iot/{yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin => yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api}/package-info.java (53%)
create mode 100644 yudao-module-iot/yudao-module-iot-plugin/plugin.properties
create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml
create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java
create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java
create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java
create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java
diff --git a/yudao-module-iot/pom.xml b/yudao-module-iot/pom.xml
index d9002abea5..d47d3c7f64 100644
--- a/yudao-module-iot/pom.xml
+++ b/yudao-module-iot/pom.xml
@@ -11,6 +11,7 @@
yudao-module-iot-api
yudao-module-iot-biz
yudao-module-iot-plugin
+ yudao-module-iot-plugin-api
4.0.0
diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml
index b003e1785a..774d353809 100644
--- a/yudao-module-iot/yudao-module-iot-biz/pom.xml
+++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml
@@ -25,6 +25,13 @@
${revision}
+
+ cn.iocoder.boot
+ yudao-module-iot-plugin-api
+ 0.0.1
+ compile
+
+
cn.iocoder.boot
yudao-spring-boot-starter-biz-tenant
@@ -75,6 +82,7 @@
org.pf4j
pf4j-spring
+
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java
new file mode 100644
index 0000000000..a8e557f15f
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/Greetings.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.iocoder.yudao.module.iot.controller.admin.plugininfo;
+
+import cn.iocoder.yudao.module.iot.api.Greeting;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 打招呼 测试用例
+ */
+@Component
+public class Greetings {
+
+ @Autowired
+ private List greetings;
+
+ public void printGreetings() {
+ System.out.printf("找到扩展点的 %d 个扩展 '%s'%n", greetings.size(), Greeting.class.getName());
+ for (Greeting greeting : greetings) {
+ System.out.println(">>> " + greeting.getGreeting());
+ }
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java
new file mode 100644
index 0000000000..c4f9ab4653
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginController.java
@@ -0,0 +1,134 @@
+package cn.iocoder.yudao.module.iot.controller.admin.plugininfo;
+
+import jakarta.annotation.Resource;
+import org.pf4j.spring.SpringPluginManager;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.security.PermitAll;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 插件 Controller 测试用例
+ */
+@RestController
+@RequestMapping("/iot/plugins")
+public class PluginController {
+
+ @Resource
+ private ApplicationContext applicationContext;
+ @Resource
+ private SpringPluginManager springPluginManager;
+ @Resource
+ private Greetings greetings;
+
+ @Value("${pf4j.pluginsDir}")
+ private String pluginsDir;
+
+ /**
+ * 上传插件 JAR 文件并加载插件
+ *
+ * @param file 上传的 JAR 文件
+ * @return 上传结果
+ */
+ @PermitAll
+ @PostMapping("/upload")
+ public ResponseEntity uploadPlugin(@RequestParam("file") MultipartFile file) {
+ if (file.isEmpty()) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("上传的文件为空");
+ }
+
+ // 确保插件目录存在
+ Path pluginsPath = Paths.get(pluginsDir);
+ try {
+ if (!Files.exists(pluginsPath)) {
+ Files.createDirectories(pluginsPath);
+ }
+
+ // 保存上传的 JAR 文件到插件目录
+ String filename = file.getOriginalFilename();
+ if (filename == null || (!filename.endsWith(".jar") && !filename.endsWith(".zip"))) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("上传的文件不是 JAR 或 ZIP 文件");
+ }
+
+ Path jarPath = pluginsPath.resolve(filename);
+
+ Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING);
+
+ // 加载插件
+ String pluginId = springPluginManager.loadPlugin(jarPath.toAbsolutePath());
+
+ // 启动插件
+ springPluginManager.startPlugin(pluginId);
+
+ return ResponseEntity.ok("插件上传并加载成功");
+ } catch (IOException e) {
+ e.printStackTrace();
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("上传插件时发生错误: " + e.getMessage());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("加载插件时发生错误: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 卸载指定插件
+ *
+ * @param pluginId 插件 ID
+ * @return 卸载结果
+ */
+ @PermitAll
+ @DeleteMapping("/unload/{pluginId}")
+ public ResponseEntity unloadPlugin(@PathVariable String pluginId) {
+ if (springPluginManager.getPlugins().stream().noneMatch(plugin -> plugin.getDescriptor().getPluginId().equals(pluginId))) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("插件未加载: " + pluginId);
+ }
+
+ springPluginManager.stopPlugin(pluginId);
+ springPluginManager.unloadPlugin(pluginId);
+
+ // 删除插件 JAR 文件(可选)
+// PluginWrapper plugin = pluginManager.getPlugin(pluginId);
+// PluginDescriptor descriptor = plugin.getDescriptor();
+// Path jarPath = Paths.get(pluginsDir).resolve(descriptor.getPluginId() + ".jar");
+// Files.deleteIfExists(jarPath);
+
+ return ResponseEntity.ok("插件卸载成功: " + pluginId);
+ }
+
+ /**
+ * 列出所有已加载的插件
+ *
+ * @return 插件列表
+ */
+ @PermitAll
+ @GetMapping("/list")
+ public ResponseEntity> listPlugins() {
+ List plugins = springPluginManager.getPlugins().stream()
+ .map(plugin -> plugin.getDescriptor().getPluginId())
+ .collect(Collectors.toList());
+ return ResponseEntity.ok(plugins);
+ }
+
+ /**
+ * 打印问候语
+ *
+ * @return 1
+ */
+ @PermitAll
+ @GetMapping("/printGreetings")
+ public ResponseEntity printGreetings() {
+ greetings.printGreetings();
+ return ResponseEntity.ok(1);
+ }
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java
new file mode 100644
index 0000000000..b6ca7f322b
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/WhazzupGreeting.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.iocoder.yudao.module.iot.controller.admin.plugininfo;
+
+import cn.iocoder.yudao.module.iot.api.Greeting;
+import org.pf4j.Extension;
+import org.springframework.stereotype.Component;
+
+/**
+ * 打招呼 测试用例
+ */
+@Extension
+@Component
+public class WhazzupGreeting implements Greeting {
+
+ @Override
+ public String getGreeting() {
+ return "Whazzup";
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java
index f43b69c12c..db03332d90 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java
@@ -1,8 +1,10 @@
package cn.iocoder.yudao.module.iot.framework.plugin;
+import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.Greetings;
import org.pf4j.spring.SpringPluginManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
@Configuration
public class SpringConfiguration {
@@ -12,4 +14,10 @@ public class SpringConfiguration {
return new SpringPluginManager();
}
+ @Bean
+ @DependsOn("pluginManager")
+ public Greetings greetings() {
+ return new Greetings();
+ }
+
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java
index f9ae486772..8671034021 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java
@@ -7,8 +7,6 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO;
import jakarta.validation.Valid;
import org.springframework.web.multipart.MultipartFile;
-import java.io.InputStream;
-
/**
* IoT 插件信息 Service 接口
*
@@ -57,7 +55,7 @@ public interface PluginInfoService {
/**
* 上传插件的 JAR 包
*
- * @param id 插件id
+ * @param id 插件id
* @param file 文件
*/
void uploadJar(Long id, MultipartFile file);
@@ -65,7 +63,7 @@ public interface PluginInfoService {
/**
* 更新插件的状态
*
- * @param id 插件id
+ * @param id 插件id
* @param status 状态
*/
void updatePluginStatus(Long id, Integer status);
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java
index 65ad6ad1db..daa76acc63 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java
@@ -17,13 +17,18 @@ import org.pf4j.PluginDescriptor;
import org.pf4j.PluginState;
import org.pf4j.PluginWrapper;
import org.pf4j.spring.SpringPluginManager;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
@@ -47,6 +52,9 @@ public class PluginInfoServiceImpl implements PluginInfoService {
@Resource
private FileApi fileApi;
+ @Value("${pf4j.pluginsDir}")
+ private String pluginsDir;
+
@Override
public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) {
// 插入
@@ -132,7 +140,7 @@ public class PluginInfoServiceImpl implements PluginInfoService {
// 4. 上传插件
String pluginIdNew;
try {
- String path = fileApi.createFile(IoUtil.readBytes(file.getInputStream()));
+ String path = fileApi.createFile(pluginsDir, IoUtil.readBytes(file.getInputStream()));
Path pluginPath = Path.of(path);
pluginIdNew = pluginManager.loadPlugin(pluginPath);
} catch (Exception e) {
@@ -144,10 +152,31 @@ public class PluginInfoServiceImpl implements PluginInfoService {
throw exception(PLUGIN_INSTALL_FAILED);
}
-
// 5. 读取配置文件和脚本
String configJson = "";
String script = "";
+ try (JarFile jarFile = new JarFile(pluginWrapper.getPluginPath().toFile())) {
+ // 5.1 获取config文件在jar包中的路径
+ String configFile = "classes/config.json";
+ JarEntry configEntry = jarFile.getJarEntry(configFile);
+
+ if (configEntry != null) {
+ // 5.2 读取配置文件
+ configJson = IoUtil.readUtf8(jarFile.getInputStream(configEntry));
+ log.info("configJson:{}", configJson);
+ }
+
+ // 5.3 读取script.js脚本
+ String scriptFile = "classes/script.js";
+ JarEntry scriptEntity = jarFile.getJarEntry(scriptFile);
+ if (scriptEntity != null) {
+ // 5.4 读取脚本文件
+ script = IoUtil.readUtf8(jarFile.getInputStream(scriptEntity));
+ log.info("script:{}", script);
+ }
+ } catch (Exception e) {
+ throw exception(PLUGIN_INSTALL_FAILED);
+ }
pluginInfoDo.setPluginId(pluginIdNew);
pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus());
@@ -159,48 +188,6 @@ public class PluginInfoServiceImpl implements PluginInfoService {
pluginInfoDo.setVersion(pluginDescriptor.getVersion());
pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription());
pluginInfoMapper.updateById(pluginInfoDo);
-
-
- // 5. 读取配置文件和脚本
-// String configJson = "";
- // String script = "";
-// try (JarFile jarFile = new JarFile(pluginInfoUpdate.getPluginPath())) {
-// // 5.1 获取config文件在jar包中的路径
-// String configFile = "classes/config.json";
-// JarEntry configEntry = jarFile.getJarEntry(configFile);
-//
-// if (configEntry != null) {
-// // 5.2 读取配置文件
-// configJson = IoUtil.read(jarFile.getInputStream(configEntry), Charset.defaultCharset());
-// log.info("configJson:{}", configJson);
-// }
-//
-// // 5.3 读取script.js脚本
-// String scriptFile = "classes/script.js";
-// JarEntry scriptEntity = jarFile.getJarEntry(scriptFile);
-// if (scriptEntity != null) {
-// // 5.4 读取脚本文件
-// script = IoUtil.read(jarFile.getInputStream(scriptEntity), Charset.defaultCharset());
-// log.info("script:{}", script);
-// }
-// } catch (Exception e) {
-// throw exception(PLUGIN_INSTALL_FAILED);
-// }
-
-
-// PluginState pluginState = pluginInfoUpdate.getPluginState();
-// if (pluginState == PluginState.STARTED) {
-// pluginInfoDo.setStatus(IotPluginStatusEnum.RUNNING.getStatus());
-// }
-// pluginInfoDo.setPluginId(pluginInfoUpdate.getPluginId());
-// pluginInfoDo.setFile(file.getOriginalFilename());
-// pluginInfoDo.setConfigSchema(configJson);
-// pluginInfoDo.setScript(script);
-//
-// PluginDescriptor pluginDescriptor = pluginInfoUpdate.getPluginDescriptor();
-// pluginInfoDo.setVersion(pluginDescriptor.getPluginVersion());
-// pluginInfoDo.setDescription(pluginDescriptor.getDescription());
-// pluginInfoMapper.updateById(pluginInfoDo);
}
@Override
@@ -213,26 +200,22 @@ public class PluginInfoServiceImpl implements PluginInfoService {
throw exception(PLUGIN_STATUS_INVALID);
}
- // 插件包为空
-// String pluginId = pluginInfoDo.getPluginId();
-// if (StrUtil.isBlank(pluginId)) {
-// throw exception(PLUGIN_INFO_NOT_EXISTS);
-// }
-// com.gitee.starblues.core.PluginInfo pluginInfo = pluginOperator.getPluginInfo(pluginId);
-// if (pluginInfo != null) {
-// if (pluginInfoDo.getStatus().equals(IotPluginStatusEnum.RUNNING.getStatus()) && pluginInfo.getPluginState() != PluginState.STARTED) {
-// // 启动插件
-// pluginOperator.start(pluginId);
-// } else if (pluginInfoDo.getStatus().equals(IotPluginStatusEnum.STOPPED.getStatus()) && pluginInfo.getPluginState() == PluginState.STARTED) {
-// // 停止插件
-// pluginOperator.stop(pluginId);
-// }
-// } else {
-// // 已经停止,未获取到插件
-// if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) {
-// throw exception(PLUGIN_STATUS_INVALID);
-// }
-// }
+ String pluginId = pluginInfoDo.getPluginId();
+ PluginWrapper plugin = pluginManager.getPlugin(pluginId);
+ if (plugin != null) {
+ if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) && plugin.getPluginState() != PluginState.STARTED) {
+ // 启动插件
+ pluginManager.startPlugin(pluginId);
+ } else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) && plugin.getPluginState() == PluginState.STARTED) {
+ // 停止插件
+ pluginManager.stopPlugin(pluginId);
+ }
+ } else {
+ // 已经停止,未获取到插件
+ if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) {
+ throw exception(PLUGIN_STATUS_INVALID);
+ }
+ }
pluginInfoDo.setStatus(status);
pluginInfoMapper.updateById(pluginInfoDo);
}
@@ -244,20 +227,13 @@ public class PluginInfoServiceImpl implements PluginInfoService {
@SneakyThrows
private void startPlugins() {
-// while (!pluginOperator.inited()) {
-// Thread.sleep(1000L);
-// }
-
for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) {
if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) {
continue;
}
log.info("start plugin:{}", pluginInfoDO.getPluginId());
try {
-// com.gitee.starblues.core.PluginInfo plugin = pluginOperator.getPluginInfo(pluginInfoDO.getPluginId());
-// if (plugin != null) {
-// pluginOperator.start(plugin.getPluginId());
-// }
+ pluginManager.startPlugin(pluginInfoDO.getPluginId());
} catch (Exception e) {
log.error("start plugin error", e);
}
diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml b/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml
new file mode 100644
index 0000000000..e04e818deb
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin-api/pom.xml
@@ -0,0 +1,30 @@
+
+
+ 4.0.0
+ cn.iocoder.boot
+ yudao-module-iot-plugin-api
+ 0.0.1
+ jar
+
+ ${project.artifactId}
+
+ 物联网 模块插件 API,暴露给其它模块调用
+
+
+
+ 0.9.0
+
+
+
+
+
+ org.pf4j
+ pf4j-spring
+ ${pf4j-spring.version}
+ provided
+
+
+
+
diff --git a/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java
new file mode 100644
index 0000000000..b284549373
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/Greeting.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.iocoder.yudao.module.iot.api;
+
+import org.pf4j.ExtensionPoint;
+
+/**
+ * @author Decebal Suiu
+ */
+public interface Greeting extends ExtensionPoint {
+
+ String getGreeting();
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
similarity index 53%
rename from yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java
rename to yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
index 567dcb038b..7da0c665ba 100644
--- a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/package-info.java
+++ b/yudao-module-iot/yudao-module-iot-plugin-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
@@ -3,4 +3,4 @@
*
* TODO 芋艿:后续删除
*/
-package cn.iocoder.yudao.module.iot.plugin;
+package cn.iocoder.yudao.module.iot.api;
diff --git a/yudao-module-iot/yudao-module-iot-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/plugin.properties
new file mode 100644
index 0000000000..bbfe3185c6
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/plugin.properties
@@ -0,0 +1,5 @@
+plugin.id=iot-plugin-hppt
+plugin.class=cn.iocoder.yudao.module.iot.plugin.WelcomePlugin
+plugin.version=0.0.1
+plugin.provider=ahh
+plugin.dependencies=
diff --git a/yudao-module-iot/yudao-module-iot-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/pom.xml
index 49c3215810..52e58d57b4 100644
--- a/yudao-module-iot/yudao-module-iot-plugin/pom.xml
+++ b/yudao-module-iot/yudao-module-iot-plugin/pom.xml
@@ -1,31 +1,149 @@
-
-
- yudao-module-iot
- cn.iocoder.boot
- ${revision}
-
+
4.0.0
+ cn.iocoder.boot
yudao-module-iot-plugin
+ 0.0.1
jar
${project.artifactId}
-
- 物联网 模块 - 插件
-
+ 物联网 模块 - 插件
+
+
+
+ iot-plugin-http
+ cn.iocoder.yudao.module.iot.plugin.WelcomePlugin
+ 0.0.1
+ ahh
+
+
+
+ 17
+ ${java.version}
+ ${java.version}
+ 1.6
+ 2.3
+ 2.4
+ 0.9.0
+
+ 3.3.1
+ UTF-8
+
+
- cn.iocoder.boot
- yudao-common
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring.boot.version}
+ provided
-
+
org.pf4j
pf4j-spring
+ ${pf4j-spring.version}
+ provided
+
+
+
+ cn.iocoder.boot
+ yudao-module-iot-plugin-api
+ ${project.version}
-
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+ ${maven-antrun-plugin.version}
+
+
+ unzip jar file
+ package
+
+
+
+
+
+
+ run
+
+
+
+
+
+
+ maven-assembly-plugin
+ ${maven-assembly-plugin.version}
+
+
+
+ src/main/assembly/assembly.xml
+
+
+ false
+
+
+
+ make-assembly
+ package
+
+ attached
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ ${maven-jar-plugin.version}
+
+
+
+ ${plugin.id}
+ ${plugin.class}
+ ${plugin.version}
+ ${plugin.provider}
+ ${plugin.dependencies}
+
+
+
+
+
+
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml
new file mode 100644
index 0000000000..ce2e92cf95
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/assembly/assembly.xml
@@ -0,0 +1,37 @@
+
+
+ plugin
+
+ zip
+
+ false
+
+
+ false
+ runtime
+ lib
+
+ *:jar:*
+
+
+
+
+
+
+ target/plugin-classes
+ classes
+
+
+
diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java
new file mode 100644
index 0000000000..a6633388e5
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTHttpPluginController.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.iot.plugin;
+
+
+import org.pf4j.Extension;
+import org.pf4j.ExtensionPoint;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/iot/plugin-demo")
+@Extension
+public class IoTHttpPluginController implements ExtensionPoint {
+
+ @GetMapping("/greet")
+ public String greet() {
+ return "Hello from MyPlugin!";
+ }
+
+ @PostMapping("/message")
+ public void receiveMessage(@RequestBody String message) {
+ System.out.println("Received message: " + message);
+ }
+}
diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java
new file mode 100644
index 0000000000..78c07c404f
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IoTPlugin.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.iot.plugin;
+
+import org.pf4j.PluginWrapper;
+import org.pf4j.spring.SpringPlugin;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+public class IoTPlugin extends SpringPlugin {
+ public IoTPlugin(PluginWrapper wrapper) {
+ super(wrapper);
+ }
+
+ @Override
+ public void start() {
+ System.out.println("IoTPlugin 启动");
+ }
+
+ @Override
+ public void stop() {
+ System.out.println("IoTPlugin 停止");
+ super.stop(); // to close applicationContext
+ }
+
+ @Override
+ protected ApplicationContext createApplicationContext() {
+ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
+ applicationContext.setClassLoader(getWrapper().getPluginClassLoader());
+ applicationContext.register(IoTHttpPluginController.class); // 注册 IoTPluginConfig
+ applicationContext.refresh();
+ System.out.println("IoTPlugin 加载完成");
+ return applicationContext;
+ }
+}
diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java
new file mode 100644
index 0000000000..02b8bb5a04
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/IotPluginConfig.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.iot.plugin;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.boot.web.server.ConfigurableWebServerFactory;
+import org.springframework.context.annotation.Bean;
+
+@Configuration
+public class IoTPluginConfig {
+
+ @Bean
+ public IoTHttpPluginController ioTHttpPluginController() {
+ return new IoTHttpPluginController();
+ }
+}
diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java
new file mode 100644
index 0000000000..5c53cf8a86
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.iocoder.yudao.module.iot.plugin;
+
+import cn.iocoder.yudao.module.iot.api.Greeting;
+import org.apache.commons.lang.StringUtils;
+import org.pf4j.Extension;
+import org.pf4j.Plugin;
+import org.pf4j.PluginWrapper;
+import org.pf4j.RuntimeMode;
+
+/**
+ * 打招呼 测试用例
+ */
+public class WelcomePlugin extends Plugin {
+
+ public WelcomePlugin(PluginWrapper wrapper) {
+ super(wrapper);
+ }
+
+ @Override
+ public void start() {
+ System.out.println("WelcomePlugin.start()");
+ // for testing the development mode
+ if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) {
+ System.out.println(StringUtils.upperCase("WelcomePlugin"));
+ }
+ }
+
+ @Override
+ public void stop() {
+ System.out.println("WelcomePlugin.stop()");
+ }
+
+ @Extension
+ public static class WelcomeGreeting implements Greeting {
+
+ @Override
+ public String getGreeting() {
+ return "Welcome to PF4J";
+ }
+
+ }
+
+}
\ No newline at end of file