Commit 7bfa83062859d0e32e58cae406d60b66f7593e8c
1 parent
269dec1b
【代码优化】重构 HTTP插件并添加自动配置
Showing
9 changed files
with
181 additions
and
86 deletions
plugins/yudao-module-iot-plugin-http-1.0.0.jar
No preview for this file type
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java
| @@ -40,9 +40,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | @@ -40,9 +40,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | ||
| 40 | @Slf4j | 40 | @Slf4j |
| 41 | public class PluginInstanceServiceImpl implements PluginInstanceService { | 41 | public class PluginInstanceServiceImpl implements PluginInstanceService { |
| 42 | 42 | ||
| 43 | - // TODO @haohao:这个可以后续确认下,有没更合适的标识。例如说 mac 地址之类的 | ||
| 44 | - // 简化的 UUID + mac 地址 会不会好一些,一台机子有可能会部署多个插件; | ||
| 45 | - // 那就 mac@uuid ? | 43 | + // TODO @haohao:mac@uuid |
| 46 | public static final String MAIN_ID = IdUtil.fastSimpleUUID(); | 44 | public static final String MAIN_ID = IdUtil.fastSimpleUUID(); |
| 47 | 45 | ||
| 48 | @Resource | 46 | @Resource |
| @@ -60,32 +58,31 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { | @@ -60,32 +58,31 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { | ||
| 60 | @Override | 58 | @Override |
| 61 | public void stopAndUnloadPlugin(String pluginKey) { | 59 | public void stopAndUnloadPlugin(String pluginKey) { |
| 62 | PluginWrapper plugin = pluginManager.getPlugin(pluginKey); | 60 | PluginWrapper plugin = pluginManager.getPlugin(pluginKey); |
| 63 | - // TODO @haohao:改成 if return 会更简洁一点; | ||
| 64 | - if (plugin != null) { | ||
| 65 | - if (plugin.getPluginState().equals(PluginState.STARTED)) { | ||
| 66 | - pluginManager.stopPlugin(pluginKey); // 停止插件 | ||
| 67 | - log.info("已停止插件: {}", pluginKey); | ||
| 68 | - } | ||
| 69 | - pluginManager.unloadPlugin(pluginKey); // 卸载插件 | ||
| 70 | - log.info("已卸载插件: {}", pluginKey); | ||
| 71 | - } else { | 61 | + if (plugin == null) { |
| 72 | log.warn("插件不存在或已卸载: {}", pluginKey); | 62 | log.warn("插件不存在或已卸载: {}", pluginKey); |
| 63 | + return; | ||
| 64 | + } | ||
| 65 | + if (plugin.getPluginState().equals(PluginState.STARTED)) { | ||
| 66 | + pluginManager.stopPlugin(pluginKey); // 停止插件 | ||
| 67 | + log.info("已停止插件: {}", pluginKey); | ||
| 73 | } | 68 | } |
| 69 | + pluginManager.unloadPlugin(pluginKey); // 卸载插件 | ||
| 70 | + log.info("已卸载插件: {}", pluginKey); | ||
| 74 | } | 71 | } |
| 75 | 72 | ||
| 76 | @Override | 73 | @Override |
| 77 | public void deletePluginFile(PluginInfoDO pluginInfoDO) { | 74 | public void deletePluginFile(PluginInfoDO pluginInfoDO) { |
| 78 | File file = new File(pluginsDir, pluginInfoDO.getFileName()); | 75 | File file = new File(pluginsDir, pluginInfoDO.getFileName()); |
| 79 | - // TODO @haohao:改成 if return 会更简洁一点; | ||
| 80 | - if (file.exists()) { | ||
| 81 | - try { | ||
| 82 | - TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 | ||
| 83 | - if (!file.delete()) { | ||
| 84 | - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName()); | ||
| 85 | - } | ||
| 86 | - } catch (InterruptedException e) { | ||
| 87 | - log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), e); | 76 | + if (!file.exists()) { |
| 77 | + return; | ||
| 78 | + } | ||
| 79 | + try { | ||
| 80 | + TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 | ||
| 81 | + if (!file.delete()) { | ||
| 82 | + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName()); | ||
| 88 | } | 83 | } |
| 84 | + } catch (InterruptedException e) { | ||
| 85 | + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFileName(), e); | ||
| 89 | } | 86 | } |
| 90 | } | 87 | } |
| 91 | 88 | ||
| @@ -120,25 +117,25 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { | @@ -120,25 +117,25 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { | ||
| 120 | String pluginKey = pluginInfoDo.getPluginKey(); | 117 | String pluginKey = pluginInfoDo.getPluginKey(); |
| 121 | PluginWrapper plugin = pluginManager.getPlugin(pluginKey); | 118 | PluginWrapper plugin = pluginManager.getPlugin(pluginKey); |
| 122 | 119 | ||
| 123 | - // TODO @haohao:改成 if return 会更简洁一点; | ||
| 124 | - if (plugin != null) { | ||
| 125 | - // 启动插件 | ||
| 126 | - if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) | ||
| 127 | - && plugin.getPluginState() != PluginState.STARTED) { | ||
| 128 | - pluginManager.startPlugin(pluginKey); | ||
| 129 | - log.info("已启动插件: {}", pluginKey); | ||
| 130 | - } | ||
| 131 | - // 停止插件 | ||
| 132 | - else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) | ||
| 133 | - && plugin.getPluginState() == PluginState.STARTED) { | ||
| 134 | - pluginManager.stopPlugin(pluginKey); | ||
| 135 | - log.info("已停止插件: {}", pluginKey); | ||
| 136 | - } | ||
| 137 | - } else { | 120 | + if (plugin == null) { |
| 138 | // 插件不存在且状态为停止,抛出异常 | 121 | // 插件不存在且状态为停止,抛出异常 |
| 139 | if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { | 122 | if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { |
| 140 | throw exception(ErrorCodeConstants.PLUGIN_STATUS_INVALID); | 123 | throw exception(ErrorCodeConstants.PLUGIN_STATUS_INVALID); |
| 141 | } | 124 | } |
| 125 | + return; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + // 启动插件 | ||
| 129 | + if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) | ||
| 130 | + && plugin.getPluginState() != PluginState.STARTED) { | ||
| 131 | + pluginManager.startPlugin(pluginKey); | ||
| 132 | + log.info("已启动插件: {}", pluginKey); | ||
| 133 | + } | ||
| 134 | + // 停止插件 | ||
| 135 | + else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) | ||
| 136 | + && plugin.getPluginState() == PluginState.STARTED) { | ||
| 137 | + pluginManager.stopPlugin(pluginKey); | ||
| 138 | + log.info("已停止插件: {}", pluginKey); | ||
| 142 | } | 139 | } |
| 143 | } | 140 | } |
| 144 | 141 | ||
| @@ -152,10 +149,10 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { | @@ -152,10 +149,10 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { | ||
| 152 | Map<String, PluginInfoDO> pluginInfoMap = pluginInfos.stream() | 149 | Map<String, PluginInfoDO> pluginInfoMap = pluginInfos.stream() |
| 153 | .collect(Collectors.toMap(PluginInfoDO::getPluginKey, Function.identity())); | 150 | .collect(Collectors.toMap(PluginInfoDO::getPluginKey, Function.identity())); |
| 154 | 151 | ||
| 155 | - // 1.3 获取本机 IP 和 MAC 地址 | 152 | + // 1.3 获取本机 IP 和 MAC 地址,mac@uuid |
| 156 | String ip = NetUtil.getLocalhostStr(); | 153 | String ip = NetUtil.getLocalhostStr(); |
| 157 | String mac = NetUtil.getLocalMacAddress(); | 154 | String mac = NetUtil.getLocalMacAddress(); |
| 158 | - String mainId = MAIN_ID + "-" + mac; | 155 | + String mainId = mac + "@" + MAIN_ID; |
| 159 | 156 | ||
| 160 | // 2. 遍历插件列表,并保存为插件实例 | 157 | // 2. 遍历插件列表,并保存为插件实例 |
| 161 | for (PluginWrapper plugin : plugins) { | 158 | for (PluginWrapper plugin : plugins) { |
| @@ -173,14 +170,21 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { | @@ -173,14 +170,21 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { | ||
| 173 | pluginInfo.getId()); | 170 | pluginInfo.getId()); |
| 174 | if (pluginInstance == null) { | 171 | if (pluginInstance == null) { |
| 175 | // 4.4 如果插件实例不存在,则创建 | 172 | // 4.4 如果插件实例不存在,则创建 |
| 176 | - pluginInstance = PluginInstanceDO.builder().pluginId(pluginInfo.getId()).mainId(MAIN_ID + "-" + mac) | ||
| 177 | - .ip(ip).port(port).heartbeatAt(System.currentTimeMillis()).build(); | 173 | + pluginInstance = PluginInstanceDO.builder() |
| 174 | + .pluginId(pluginInfo.getId()) | ||
| 175 | + .mainId(MAIN_ID + "-" + mac) | ||
| 176 | + .ip(ip) | ||
| 177 | + .port(port) | ||
| 178 | + .heartbeatAt(System.currentTimeMillis()) | ||
| 179 | + .build(); | ||
| 178 | pluginInstanceMapper.insert(pluginInstance); | 180 | pluginInstanceMapper.insert(pluginInstance); |
| 179 | } else { | 181 | } else { |
| 180 | // 2.2 情况二:如果存在,则更新 heartbeatAt | 182 | // 2.2 情况二:如果存在,则更新 heartbeatAt |
| 181 | - // TODO @haohao:这里最好 new 去 update;避免并发更新(虽然目前没有) | ||
| 182 | - pluginInstance.setHeartbeatAt(System.currentTimeMillis()); | ||
| 183 | - pluginInstanceMapper.updateById(pluginInstance); | 183 | + PluginInstanceDO updatePluginInstance = PluginInstanceDO.builder() |
| 184 | + .id(pluginInstance.getId()) | ||
| 185 | + .heartbeatAt(System.currentTimeMillis()) | ||
| 186 | + .build(); | ||
| 187 | + pluginInstanceMapper.updateById(updatePluginInstance); | ||
| 184 | } | 188 | } |
| 185 | } | 189 | } |
| 186 | } | 190 | } |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java
| @@ -5,24 +5,30 @@ import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | @@ -5,24 +5,30 @@ import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | ||
| 5 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; | 5 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO; |
| 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; | 6 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; |
| 7 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO; |
| 8 | +import lombok.RequiredArgsConstructor; | ||
| 8 | import lombok.extern.slf4j.Slf4j; | 9 | import lombok.extern.slf4j.Slf4j; |
| 9 | import org.springframework.web.client.RestTemplate; | 10 | import org.springframework.web.client.RestTemplate; |
| 10 | 11 | ||
| 11 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 12 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 12 | 13 | ||
| 13 | -// TODO @haohao:类注释,写一下,比较好 | 14 | +/** |
| 15 | + * 用于通过 {@link RestTemplate} 向远程 IoT 服务发送设备数据相关的请求, | ||
| 16 | + * 包括设备状态更新、事件数据上报、属性数据上报等操作。 | ||
| 17 | + */ | ||
| 14 | @Slf4j | 18 | @Slf4j |
| 19 | +@RequiredArgsConstructor | ||
| 15 | public class DeviceDataApiClient implements DeviceDataApi { | 20 | public class DeviceDataApiClient implements DeviceDataApi { |
| 16 | 21 | ||
| 22 | + /** | ||
| 23 | + * 用于发送 HTTP 请求的工具 | ||
| 24 | + */ | ||
| 17 | private final RestTemplate restTemplate; | 25 | private final RestTemplate restTemplate; |
| 18 | - private final String deviceDataUrl; | ||
| 19 | 26 | ||
| 20 | - // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 | ||
| 21 | - // TODO @haohao:可以用 lombok 简化 | ||
| 22 | - public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) { | ||
| 23 | - this.restTemplate = restTemplate; | ||
| 24 | - this.deviceDataUrl = deviceDataUrl; | ||
| 25 | - } | 27 | + /** |
| 28 | + * 远程 IoT 服务的基础 URL | ||
| 29 | + * 例如:http://127.0.0.1:8080 | ||
| 30 | + */ | ||
| 31 | + private final String deviceDataUrl; | ||
| 26 | 32 | ||
| 27 | // TODO @haohao:返回结果,不用 CommonResult 哈。 | 33 | // TODO @haohao:返回结果,不用 CommonResult 哈。 |
| 28 | @Override | 34 | @Override |
| @@ -43,17 +49,51 @@ public class DeviceDataApiClient implements DeviceDataApi { | @@ -43,17 +49,51 @@ public class DeviceDataApiClient implements DeviceDataApi { | ||
| 43 | return doPost(url, reportReqDTO, "reportDevicePropertyData"); | 49 | return doPost(url, reportReqDTO, "reportDevicePropertyData"); |
| 44 | } | 50 | } |
| 45 | 51 | ||
| 46 | - // TODO @haohao:未来可能有 get 类型哈 | 52 | + |
| 53 | + /** | ||
| 54 | + * 发送 GET 请求 | ||
| 55 | + * | ||
| 56 | + * @param <T> 请求体类型 | ||
| 57 | + * @param url 请求 URL | ||
| 58 | + * @param requestBody 请求体 | ||
| 59 | + * @param actionName 操作名称 | ||
| 60 | + * @return 响应结果 | ||
| 61 | + */ | ||
| 62 | + private <T> CommonResult<Boolean> doGet(String url, T requestBody, String actionName) { | ||
| 63 | + log.info("[{}] Sending request to URL: {}", actionName, url); | ||
| 64 | + try { | ||
| 65 | + CommonResult<?> response = restTemplate.getForObject(url, CommonResult.class); | ||
| 66 | + if (response != null && response.isSuccess()) { | ||
| 67 | + return success(true); | ||
| 68 | + } else { | ||
| 69 | + log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response); | ||
| 70 | + return CommonResult.error(500, "Request failed"); | ||
| 71 | + } | ||
| 72 | + } catch (Exception e) { | ||
| 73 | + log.error("[{}] Error sending request to URL: {}", actionName, url, e); | ||
| 74 | + return CommonResult.error(400, "Request error: " + e.getMessage()); | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + | ||
| 47 | /** | 78 | /** |
| 48 | - * 将与远程服务交互的通用逻辑抽取成一个私有方法 | 79 | + * 发送 POST 请求 |
| 80 | + * | ||
| 81 | + * @param <T> 请求体类型 | ||
| 82 | + * @param url 请求 URL | ||
| 83 | + * @param requestBody 请求体 | ||
| 84 | + * @param actionName 操作名称 | ||
| 85 | + * @return 响应结果 | ||
| 49 | */ | 86 | */ |
| 50 | private <T> CommonResult<Boolean> doPost(String url, T requestBody, String actionName) { | 87 | private <T> CommonResult<Boolean> doPost(String url, T requestBody, String actionName) { |
| 51 | log.info("[{}] Sending request to URL: {}", actionName, url); | 88 | log.info("[{}] Sending request to URL: {}", actionName, url); |
| 52 | try { | 89 | try { |
| 53 | - // 这里指定返回类型为 CommonResult<?>,根据后台服务返回的实际结构做调整 | ||
| 54 | - restTemplate.postForObject(url, requestBody, CommonResult.class); | ||
| 55 | - // TODO @haohao:check 结果,是否成功 | ||
| 56 | - return success(true); | 90 | + CommonResult<?> response = restTemplate.postForObject(url, requestBody, CommonResult.class); |
| 91 | + if (response != null && response.isSuccess()) { | ||
| 92 | + return success(true); | ||
| 93 | + } else { | ||
| 94 | + log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response); | ||
| 95 | + return CommonResult.error(500, "Request failed"); | ||
| 96 | + } | ||
| 57 | } catch (Exception e) { | 97 | } catch (Exception e) { |
| 58 | log.error("[{}] Error sending request to URL: {}", actionName, url, e); | 98 | log.error("[{}] Error sending request to URL: {}", actionName, url, e); |
| 59 | return CommonResult.error(400, "Request error: " + e.getMessage()); | 99 | return CommonResult.error(400, "Request error: " + e.getMessage()); |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/DeviceDataApiInitializer.java renamed to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java
| @@ -3,29 +3,49 @@ package cn.iocoder.yudao.module.iot.plugin.common.config; | @@ -3,29 +3,49 @@ package cn.iocoder.yudao.module.iot.plugin.common.config; | ||
| 3 | import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | 3 | import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; |
| 4 | import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient; | 4 | import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient; |
| 5 | import org.springframework.beans.factory.annotation.Value; | 5 | import org.springframework.beans.factory.annotation.Value; |
| 6 | +import org.springframework.boot.autoconfigure.AutoConfiguration; | ||
| 6 | import org.springframework.boot.web.client.RestTemplateBuilder; | 7 | import org.springframework.boot.web.client.RestTemplateBuilder; |
| 7 | import org.springframework.context.annotation.Bean; | 8 | import org.springframework.context.annotation.Bean; |
| 8 | -import org.springframework.context.annotation.Configuration; | ||
| 9 | import org.springframework.web.client.RestTemplate; | 9 | import org.springframework.web.client.RestTemplate; |
| 10 | 10 | ||
| 11 | -// TODO @haohao:这个最好是 autoconfiguration | ||
| 12 | -@Configuration | ||
| 13 | -public class DeviceDataApiInitializer { | 11 | +import java.time.Duration; |
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * 设备数据 API 初始化器 | ||
| 15 | + * | ||
| 16 | + * @author haohao | ||
| 17 | + */ | ||
| 18 | +@AutoConfiguration | ||
| 19 | +public class YudaoDeviceDataApiAutoConfiguration { | ||
| 20 | + | ||
| 14 | 21 | ||
| 15 | // TODO @haohao:这个要不搞个配置类哈 | 22 | // TODO @haohao:这个要不搞个配置类哈 |
| 16 | @Value("${iot.device-data.url}") | 23 | @Value("${iot.device-data.url}") |
| 17 | private String deviceDataUrl; | 24 | private String deviceDataUrl; |
| 18 | 25 | ||
| 26 | + /** | ||
| 27 | + * 创建 RestTemplate 实例 | ||
| 28 | + * | ||
| 29 | + * @return RestTemplate 实例 | ||
| 30 | + */ | ||
| 19 | @Bean | 31 | @Bean |
| 20 | public RestTemplate restTemplate() { | 32 | public RestTemplate restTemplate() { |
| 21 | - // TODO haohao:如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 | ||
| 22 | - return new RestTemplateBuilder().build(); | 33 | + // 如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 |
| 34 | + return new RestTemplateBuilder() | ||
| 35 | + .setConnectTimeout(Duration.ofMillis(5000)) // 设置连接超时时间 | ||
| 36 | + .setReadTimeout(Duration.ofMillis(5000)) // 设置读取超时时间 | ||
| 37 | + .build(); | ||
| 23 | } | 38 | } |
| 24 | 39 | ||
| 25 | - // TODO @haohao:不存在时,才构建 | 40 | + /** |
| 41 | + * 创建 DeviceDataApi 实例 | ||
| 42 | + * | ||
| 43 | + * @param restTemplate RestTemplate 实例 | ||
| 44 | + * @return DeviceDataApi 实例 | ||
| 45 | + */ | ||
| 26 | @Bean | 46 | @Bean |
| 27 | public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { | 47 | public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { |
| 28 | return new DeviceDataApiClient(restTemplate, deviceDataUrl); | 48 | return new DeviceDataApiClient(restTemplate, deviceDataUrl); |
| 29 | } | 49 | } |
| 30 | 50 | ||
| 31 | -} | 51 | -} |
| 52 | +} | ||
| 32 | \ No newline at end of file | 53 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
0 → 100644
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java
| @@ -11,7 +11,7 @@ import org.springframework.context.ConfigurableApplicationContext; | @@ -11,7 +11,7 @@ import org.springframework.context.ConfigurableApplicationContext; | ||
| 11 | * 独立运行入口 | 11 | * 独立运行入口 |
| 12 | */ | 12 | */ |
| 13 | @Slf4j | 13 | @Slf4j |
| 14 | -@SpringBootApplication(scanBasePackages = "cn.iocoder.yudao.module.iot.plugin") // TODO @haohao:建议不扫描 cn.iocoder.yudao.module.iot.plugin;而是通过自动配置,初始化 common 的 | 14 | +@SpringBootApplication |
| 15 | public class HttpPluginSpringbootApplication { | 15 | public class HttpPluginSpringbootApplication { |
| 16 | 16 | ||
| 17 | public static void main(String[] args) { | 17 | public static void main(String[] args) { |
| @@ -21,6 +21,7 @@ public class HttpPluginSpringbootApplication { | @@ -21,6 +21,7 @@ public class HttpPluginSpringbootApplication { | ||
| 21 | 21 | ||
| 22 | // 手动获取 VertxService 并启动 | 22 | // 手动获取 VertxService 并启动 |
| 23 | // TODO @haohao:可以放在 bean 的 init 里么? | 23 | // TODO @haohao:可以放在 bean 的 init 里么? |
| 24 | + // 会和插件模式冲突 | ||
| 24 | VertxService vertxService = context.getBean(VertxService.class); | 25 | VertxService vertxService = context.getBean(VertxService.class); |
| 25 | vertxService.startServer(); | 26 | vertxService.startServer(); |
| 26 | 27 |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java
| @@ -21,30 +21,41 @@ public class HttpVertxPlugin extends SpringPlugin { | @@ -21,30 +21,41 @@ public class HttpVertxPlugin extends SpringPlugin { | ||
| 21 | 21 | ||
| 22 | @Override | 22 | @Override |
| 23 | public void start() { | 23 | public void start() { |
| 24 | - // TODO @haohao:这种最好启动中,启动完成,成对打印日志,方便定位问题 | ||
| 25 | - log.info("[HttpVertxPlugin][start ...]"); | 24 | + log.info("[HttpVertxPlugin][start][begin] 开始启动 HttpVertxPlugin 插件..."); |
| 26 | 25 | ||
| 27 | - // 1. 获取插件上下文 | ||
| 28 | - ApplicationContext pluginContext = getApplicationContext(); | ||
| 29 | - if (pluginContext == null) { | ||
| 30 | - log.error("[HttpVertxPlugin] pluginContext is null, start failed."); | ||
| 31 | - return; | ||
| 32 | - } | 26 | + try { |
| 27 | + // 1. 获取插件上下文 | ||
| 28 | + ApplicationContext pluginContext = getApplicationContext(); | ||
| 29 | + if (pluginContext == null) { | ||
| 30 | + log.error("[HttpVertxPlugin][start][fail] pluginContext is null, 启动失败!"); | ||
| 31 | + return; | ||
| 32 | + } | ||
| 33 | 33 | ||
| 34 | - // 2. 启动 Vertx | ||
| 35 | - VertxService vertxService = pluginContext.getBean(VertxService.class); | ||
| 36 | - vertxService.startServer(); | ||
| 37 | - } | 34 | + // 2. 启动 Vert.x |
| 35 | + VertxService vertxService = pluginContext.getBean(VertxService.class); | ||
| 36 | + vertxService.startServer(); | ||
| 38 | 37 | ||
| 38 | + log.info("[HttpVertxPlugin][start][end] 启动完成"); | ||
| 39 | + } catch (Exception e) { | ||
| 40 | + log.error("[HttpVertxPlugin][start][exception] 启动过程出现异常!", e); | ||
| 41 | + } | ||
| 42 | + } | ||
| 39 | 43 | ||
| 40 | @Override | 44 | @Override |
| 41 | public void stop() { | 45 | public void stop() { |
| 42 | - log.info("[HttpVertxPlugin][stop ...]"); | ||
| 43 | - ApplicationContext pluginContext = getApplicationContext(); | ||
| 44 | - if (pluginContext != null) { | ||
| 45 | - // 停止服务器 | ||
| 46 | - VertxService vertxService = pluginContext.getBean(VertxService.class); | ||
| 47 | - vertxService.stopServer(); | 46 | + log.info("[HttpVertxPlugin][stop][begin] 开始停止 HttpVertxPlugin 插件..."); |
| 47 | + | ||
| 48 | + try { | ||
| 49 | + ApplicationContext pluginContext = getApplicationContext(); | ||
| 50 | + if (pluginContext != null) { | ||
| 51 | + // 停止服务器 | ||
| 52 | + VertxService vertxService = pluginContext.getBean(VertxService.class); | ||
| 53 | + vertxService.stopServer(); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + log.info("[HttpVertxPlugin][stop][end] 停止完成"); | ||
| 57 | + } catch (Exception e) { | ||
| 58 | + log.error("[HttpVertxPlugin][stop][exception] 停止过程出现异常!", e); | ||
| 48 | } | 59 | } |
| 49 | } | 60 | } |
| 50 | 61 | ||
| @@ -68,5 +79,4 @@ public class HttpVertxPlugin extends SpringPlugin { | @@ -68,5 +79,4 @@ public class HttpVertxPlugin extends SpringPlugin { | ||
| 68 | 79 | ||
| 69 | return pluginContext; | 80 | return pluginContext; |
| 70 | } | 81 | } |
| 71 | - | ||
| 72 | -} | 82 | +} |
| 73 | \ No newline at end of file | 83 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java
| @@ -34,6 +34,10 @@ public class HttpVertxPluginConfiguration { | @@ -34,6 +34,10 @@ public class HttpVertxPluginConfiguration { | ||
| 34 | 34 | ||
| 35 | /** | 35 | /** |
| 36 | * 创建路由 | 36 | * 创建路由 |
| 37 | + * | ||
| 38 | + * @param vertx Vertx 实例 | ||
| 39 | + * @param httpVertxHandler HttpVertxHandler 实例 | ||
| 40 | + * @return Router 实例 | ||
| 37 | */ | 41 | */ |
| 38 | @Bean | 42 | @Bean |
| 39 | public Router router(Vertx vertx, HttpVertxHandler httpVertxHandler) { | 43 | public Router router(Vertx vertx, HttpVertxHandler httpVertxHandler) { |
| @@ -50,6 +54,12 @@ public class HttpVertxPluginConfiguration { | @@ -50,6 +54,12 @@ public class HttpVertxPluginConfiguration { | ||
| 50 | return router; | 54 | return router; |
| 51 | } | 55 | } |
| 52 | 56 | ||
| 57 | + /** | ||
| 58 | + * 创建 HttpVertxHandler 实例 | ||
| 59 | + * | ||
| 60 | + * @param deviceDataApi DeviceDataApi 实例 | ||
| 61 | + * @return HttpVertxHandler 实例 | ||
| 62 | + */ | ||
| 53 | @Bean | 63 | @Bean |
| 54 | public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) { | 64 | public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) { |
| 55 | return new HttpVertxHandler(deviceDataApi); | 65 | return new HttpVertxHandler(deviceDataApi); |
| @@ -58,6 +68,10 @@ public class HttpVertxPluginConfiguration { | @@ -58,6 +68,10 @@ public class HttpVertxPluginConfiguration { | ||
| 58 | /** | 68 | /** |
| 59 | * 定义一个 VertxService 来管理服务器启动逻辑 | 69 | * 定义一个 VertxService 来管理服务器启动逻辑 |
| 60 | * 无论是独立运行还是插件方式,都可以共用此类 | 70 | * 无论是独立运行还是插件方式,都可以共用此类 |
| 71 | + * | ||
| 72 | + * @param vertx Vertx 实例 | ||
| 73 | + * @param router Router 实例 | ||
| 74 | + * @return VertxService 实例 | ||
| 61 | */ | 75 | */ |
| 62 | @Bean | 76 | @Bean |
| 63 | public VertxService vertxService(Vertx vertx, Router router) { | 77 | public VertxService vertxService(Vertx vertx, Router router) { |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml