diff --git a/plugins/enabled.txt b/plugins/enabled.txt index e69de29bb2..b62400a815 100644 --- a/plugins/enabled.txt +++ b/plugins/enabled.txt @@ -0,0 +1 @@ +http-plugin@0.0.1 diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar index 0300a632ae..28b10d529c 100644 Binary files a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar and b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar differ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java index b7efd088ef..4bb5b6e78f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/PluginInfoController.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.plugininfo; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoImportReqVO; import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoRespVO; import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; @@ -16,11 +17,8 @@ import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_IS_EMPTY; @Tag(name = "管理后台 - IoT 插件信息") @RestController @@ -72,16 +70,10 @@ public class PluginInfoController { return success(BeanUtils.toBean(pageResult, PluginInfoRespVO.class)); } - @RequestMapping(value = "/update-jar", - method = {RequestMethod.POST, RequestMethod.PUT}) // 解决 uni-app 不支持 Put 上传文件的问题 - @Operation(summary = "上传Jar包") - public CommonResult uploadJar( - @RequestParam("id") Long id, - @RequestParam("jar") MultipartFile file) throws Exception { - if (file.isEmpty()) { - throw exception(FILE_IS_EMPTY); - } - pluginInfoService.uploadJar(id, file); + @PostMapping("/upload-file") + @Operation(summary = "上传插件文件") + public CommonResult uploadFile(@Valid PluginInfoImportReqVO reqVO) { + pluginInfoService.uploadFile(reqVO.getId(), reqVO.getFile()); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java new file mode 100644 index 0000000000..9216d09ecb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +@Schema(description = "管理后台 - IoT 插件上传 Request VO") +@Data +public class PluginInfoImportReqVO { + + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") + private Long id; + + @Schema(description = "插件文件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "插件文件不能为空") + private MultipartFile file; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java deleted file mode 100644 index d87a94f318..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.module.iot.framework.plugin; - -import org.pf4j.spring.SpringPluginManager; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; - -@Configuration -public class SpringConfiguration { - - @Bean - @DependsOn("serviceRegistryInitializedMarker") - public SpringPluginManager pluginManager() { - return new SpringPluginManager(); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java similarity index 55% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index 3450b67fb9..66adc3c9fc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -1,35 +1,36 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import lombok.extern.slf4j.Slf4j; +import org.pf4j.spring.SpringPluginManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; -import javax.annotation.PostConstruct; import javax.annotation.Resource; @Slf4j @Configuration -public class ServiceRegistryConfiguration { +public class UnifiedConfiguration { + + private static final String SERVICE_REGISTRY_INITIALIZED_MARKER = "serviceRegistryInitializedMarker"; @Resource private DeviceDataApi deviceDataApi; - @PostConstruct - public void init() { - // 将主程序中的 DeviceDataApi 实例注册到 ServiceRegistry + @Bean(SERVICE_REGISTRY_INITIALIZED_MARKER) + public Object serviceRegistryInitializedMarker() { ServiceRegistry.registerService(DeviceDataApi.class, deviceDataApi); log.info("[init][将 DeviceDataApi 实例注册到 ServiceRegistry 中]"); - } - - /** - * 定义一个标记用的 Bean,用于表示 ServiceRegistry 已初始化完成 - */ - @Bean("serviceRegistryInitializedMarker") // TODO @haohao:1)这个名字,可以搞个 public static final 常量;2)是不是 conditionBefore 啥 - public Object serviceRegistryInitializedMarker() { - // 返回任意对象即可,这里返回 null 都可以,但最好返回个实际对象 return new Object(); } + @Bean + @DependsOn(SERVICE_REGISTRY_INITIALIZED_MARKER) + public SpringPluginManager pluginManager() { + log.info("[init][实例化 SpringPluginManager]"); + return new SpringPluginManager(); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java index 8671034021..d023791c81 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import jakarta.validation.Valid; import org.springframework.web.multipart.MultipartFile; +import java.util.List; + /** * IoT 插件信息 Service 接口 * @@ -58,7 +60,7 @@ public interface PluginInfoService { * @param id 插件id * @param file 文件 */ - void uploadJar(Long id, MultipartFile file); + void uploadFile(Long id, MultipartFile file); /** * 更新插件的状态 @@ -67,4 +69,11 @@ public interface PluginInfoService { * @param status 状态 */ void updatePluginStatus(Long id, Integer status); + + /** + * 获得启用的插件列表 + * + * @return 插件列表-插件id + */ + List getEnabledPlugins(); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java index bd7efa8d0c..333d0fa988 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java @@ -1,17 +1,13 @@ package cn.iocoder.yudao.module.iot.service.plugininfo; -import cn.hutool.core.io.IoUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; -import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.pf4j.PluginDescriptor; import org.pf4j.PluginState; @@ -22,11 +18,13 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.web.multipart.MultipartFile; -import java.nio.file.Path; +import java.io.File; +import java.io.IOException; +import java.nio.file.*; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @@ -47,9 +45,6 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Resource private SpringPluginManager pluginManager; - @Resource - private FileApi fileApi; - @Value("${pf4j.pluginsDir}") private String pluginsDir; @@ -95,6 +90,19 @@ public class PluginInfoServiceImpl implements PluginInfoService { // 删除 pluginInfoMapper.deleteById(id); + // 删除插件文件 + Executors.newSingleThreadExecutor().submit(() -> { + try { + TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 + File file = new File(pluginsDir, pluginInfoDO.getFile()); + if (file.exists() && !file.delete()) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFile()); + } + } catch (InterruptedException e) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFile(), e); + } + }); + } private PluginInfoDO validatePluginInfoExists(Long id) { @@ -116,73 +124,100 @@ public class PluginInfoServiceImpl implements PluginInfoService { } @Override - public void uploadJar(Long id, MultipartFile file) { - // 1. 校验存在 + public void uploadFile(Long id, MultipartFile file) { + // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // 2. 判断文件名称与插件 ID 是否匹配 + // 2. 获取插件 ID String pluginId = pluginInfoDo.getPluginId(); - // 3. 停止卸载旧的插件 - // 3.1. 获取插件信息 + // 3. 停止并卸载旧的插件 + stopAndUnloadPlugin(pluginId); + + // 4. 上传新的插件文件 + String pluginIdNew = uploadAndLoadNewPlugin(file); + + // 5. 更新插件启用状态文件 + updatePluginStatusFile(pluginIdNew, false); + + // 6. 更新插件信息 + updatePluginInfo(pluginInfoDo, pluginIdNew, file); + } + + // 停止并卸载旧的插件 + private void stopAndUnloadPlugin(String pluginId) { PluginWrapper plugin = pluginManager.getPlugin(pluginId); if (plugin != null) { - // 3.2. 如果插件状态是启动的,停止插件 if (plugin.getPluginState().equals(PluginState.STARTED)) { - pluginManager.stopPlugin(pluginId); + pluginManager.stopPlugin(pluginId); // 停止插件 } - // 3.3. 卸载插件 - pluginManager.unloadPlugin(pluginId); + pluginManager.unloadPlugin(pluginId); // 卸载插件 } + } - // 4. 上传插件 - String pluginIdNew; + // 上传并加载新的插件文件 + private String uploadAndLoadNewPlugin(MultipartFile file) { + Path pluginsPath = Paths.get(pluginsDir); try { - String path = fileApi.createFile(pluginsDir, IoUtil.readBytes(file.getInputStream())); - Path pluginPath = Path.of(path); - pluginIdNew = pluginManager.loadPlugin(pluginPath); - } catch (Exception e) { - throw exception(PLUGIN_INSTALL_FAILED); - } - - PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginIdNew); - if (pluginWrapper == null) { - throw exception(PLUGIN_INSTALL_FAILED); - } - - // 5. 读取配置文件和脚本 - String configJson = ""; - String script = ""; - try (JarFile jarFile = new JarFile(pluginWrapper.getPluginPath().toFile())) { - // 5.1 获取config文件在jar包中的路径 - String configFile = "classes/config.json"; - JarEntry configEntry = jarFile.getJarEntry(configFile); - - if (configEntry != null) { - // 5.2 读取配置文件 - configJson = IoUtil.readUtf8(jarFile.getInputStream(configEntry)); - log.info("configJson:{}", configJson); + if (!Files.exists(pluginsPath)) { + Files.createDirectories(pluginsPath); // 创建插件目录 } - - // 5.3 读取script.js脚本 - String scriptFile = "classes/script.js"; - JarEntry scriptEntity = jarFile.getJarEntry(scriptFile); - if (scriptEntity != null) { - // 5.4 读取脚本文件 - script = IoUtil.readUtf8(jarFile.getInputStream(scriptEntity)); - log.info("script:{}", script); + String filename = file.getOriginalFilename(); + if (filename != null) { + Path jarPath = pluginsPath.resolve(filename); + Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING); // 保存上传的 JAR 文件 + return pluginManager.loadPlugin(jarPath.toAbsolutePath()); // 加载插件 + } else { + throw exception(PLUGIN_INSTALL_FAILED); } } catch (Exception e) { throw exception(PLUGIN_INSTALL_FAILED); } + } + // 更新插件状态文件 + private void updatePluginStatusFile(String pluginIdNew, boolean isEnabled) { + Path enabledFilePath = Paths.get(pluginsDir, "enabled.txt"); + Path disabledFilePath = Paths.get(pluginsDir, "disabled.txt"); + Path targetFilePath = isEnabled ? enabledFilePath : disabledFilePath; + Path oppositeFilePath = isEnabled ? disabledFilePath : enabledFilePath; + + try { + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginIdNew); + if (pluginWrapper == null) { + throw exception(PLUGIN_INSTALL_FAILED); + } + String pluginInfo = pluginIdNew + "@" + pluginWrapper.getDescriptor().getVersion(); + List targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) + : new ArrayList<>(); + List oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) + : new ArrayList<>(); + + if (!targetLines.contains(pluginInfo)) { + targetLines.add(pluginInfo); + Files.write(targetFilePath, targetLines, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + } + + if (oppositeLines.contains(pluginInfo)) { + oppositeLines.remove(pluginInfo); + Files.write(oppositeFilePath, oppositeLines, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + } + } catch (IOException e) { + throw exception(PLUGIN_INSTALL_FAILED); + } + } + + // 更新插件信息 + private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginIdNew, MultipartFile file) { pluginInfoDo.setPluginId(pluginIdNew); pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); pluginInfoDo.setFile(file.getOriginalFilename()); - pluginInfoDo.setConfigSchema(configJson); - pluginInfoDo.setScript(script); + pluginInfoDo.setScript(""); - PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); + PluginDescriptor pluginDescriptor = pluginManager.getPlugin(pluginIdNew).getDescriptor(); + pluginInfoDo.setConfigSchema(pluginDescriptor.getPluginDescription()); pluginInfoDo.setVersion(pluginDescriptor.getVersion()); pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription()); pluginInfoMapper.updateById(pluginInfoDo); @@ -190,52 +225,50 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Override public void updatePluginStatus(Long id, Integer status) { - // 1. 校验存在 + // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // 插件状态无效 + // 2. 校验插件状态是否有效 if (!IotPluginStatusEnum.contains(status)) { throw exception(PLUGIN_STATUS_INVALID); } + // 3. 获取插件ID和插件实例 String pluginId = pluginInfoDo.getPluginId(); PluginWrapper plugin = pluginManager.getPlugin(pluginId); + + // 4. 根据状态更新插件 if (plugin != null) { - if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) && plugin.getPluginState() != PluginState.STARTED) { - // 启动插件 + // 4.1 如果目标状态是运行且插件未启动,则启动插件 + if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) + && plugin.getPluginState() != PluginState.STARTED) { pluginManager.startPlugin(pluginId); - } else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) && plugin.getPluginState() == PluginState.STARTED) { - // 停止插件 + updatePluginStatusFile(pluginId, true); // 更新插件状态文件为启用 + } + // 4.2 如果目标状态是停止且插件已启动,则停止插件 + else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) + && plugin.getPluginState() == PluginState.STARTED) { pluginManager.stopPlugin(pluginId); + updatePluginStatusFile(pluginId, false); // 更新插件状态文件为禁用 } } else { - // 已经停止,未获取到插件 + // 5. 插件不存在且状态为停止,抛出异常 if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { throw exception(PLUGIN_STATUS_INVALID); } } + + // 6. 更新数据库中的插件状态 pluginInfoDo.setStatus(status); pluginInfoMapper.updateById(pluginInfoDo); } -// @PostConstruct -// public void init() { -// Executors.newSingleThreadScheduledExecutor().schedule(this::startPlugins, 3, TimeUnit.SECONDS); -// } -// -// @SneakyThrows -// private void startPlugins() { -// for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { -// if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { -// continue; -// } -// log.info("start plugin:{}", pluginInfoDO.getPluginId()); -// try { -// pluginManager.startPlugin(pluginInfoDO.getPluginId()); -// } catch (Exception e) { -// log.error("start plugin error", e); -// } -// } -// } + @Override + public List getEnabledPlugins() { + return pluginInfoMapper.selectList().stream() + .filter(pluginInfoDO -> IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) + .map(PluginInfoDO::getPluginId) + .toList(); + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java new file mode 100644 index 0000000000..18b9c1417d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.iocoder.yudao.module.iot.api.Greeting; +import org.apache.commons.lang.StringUtils; +import org.pf4j.Extension; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.pf4j.RuntimeMode; +import com.sun.net.httpserver.HttpServer; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; + +/** + * 打招呼 测试用例 + */ +public class WelcomePlugin extends Plugin { + + private HttpServer server; + + public WelcomePlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + System.out.println("WelcomePlugin.start()"); + // for testing the development mode + if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { + System.out.println(StringUtils.upperCase("WelcomePlugin")); + } + startHttpServer(); + } + + @Override + public void stop() { + System.out.println("WelcomePlugin.stop()"); + stopHttpServer(); + } + + private void startHttpServer() { + try { + server = HttpServer.create(new InetSocketAddress(9081), 0); + server.createContext("/", exchange -> { + String response = "Welcome to PF4J HTTP Server"; + exchange.sendResponseHeaders(200, response.getBytes().length); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + }); + server.setExecutor(null); + server.start(); + System.out.println("HTTP server started on port 9081"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void stopHttpServer() { + if (server != null) { + server.stop(0); + System.out.println("HTTP server stopped"); + } + } + + @Extension + public static class WelcomeGreeting implements Greeting { + + @Override + public String getGreeting() { + return "Welcome to PF4J"; + } + + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index 200a451b62..1ecf140a47 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -24,6 +24,7 @@ cn.iocoder.yudao.module.iot.plugin.HttpPlugin 0.0.1 ahh + http-plugin-0.0.1 @@ -104,6 +105,7 @@ ${plugin.class} ${plugin.version} ${plugin.provider} + ${plugin.description} ${plugin.dependencies}