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