【代码优化】重构 HTTP插件并添加自动配置
This commit is contained in:
@@ -5,24 +5,30 @@ import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
// TODO @haohao:类注释,写一下,比较好
|
||||
/**
|
||||
* 用于通过 {@link RestTemplate} 向远程 IoT 服务发送设备数据相关的请求,
|
||||
* 包括设备状态更新、事件数据上报、属性数据上报等操作。
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceDataApiClient implements DeviceDataApi {
|
||||
|
||||
/**
|
||||
* 用于发送 HTTP 请求的工具
|
||||
*/
|
||||
private final RestTemplate restTemplate;
|
||||
private final String deviceDataUrl;
|
||||
|
||||
// 可以通过构造器把 RestTemplate 和 baseUrl 注入进来
|
||||
// TODO @haohao:可以用 lombok 简化
|
||||
public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.deviceDataUrl = deviceDataUrl;
|
||||
}
|
||||
/**
|
||||
* 远程 IoT 服务的基础 URL
|
||||
* 例如:http://127.0.0.1:8080
|
||||
*/
|
||||
private final String deviceDataUrl;
|
||||
|
||||
// TODO @haohao:返回结果,不用 CommonResult 哈。
|
||||
@Override
|
||||
@@ -43,17 +49,51 @@ public class DeviceDataApiClient implements DeviceDataApi {
|
||||
return doPost(url, reportReqDTO, "reportDevicePropertyData");
|
||||
}
|
||||
|
||||
// TODO @haohao:未来可能有 get 类型哈
|
||||
|
||||
/**
|
||||
* 将与远程服务交互的通用逻辑抽取成一个私有方法
|
||||
* 发送 GET 请求
|
||||
*
|
||||
* @param <T> 请求体类型
|
||||
* @param url 请求 URL
|
||||
* @param requestBody 请求体
|
||||
* @param actionName 操作名称
|
||||
* @return 响应结果
|
||||
*/
|
||||
private <T> CommonResult<Boolean> doGet(String url, T requestBody, String actionName) {
|
||||
log.info("[{}] Sending request to URL: {}", actionName, url);
|
||||
try {
|
||||
CommonResult<?> response = restTemplate.getForObject(url, CommonResult.class);
|
||||
if (response != null && response.isSuccess()) {
|
||||
return success(true);
|
||||
} else {
|
||||
log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response);
|
||||
return CommonResult.error(500, "Request failed");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[{}] Error sending request to URL: {}", actionName, url, e);
|
||||
return CommonResult.error(400, "Request error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 POST 请求
|
||||
*
|
||||
* @param <T> 请求体类型
|
||||
* @param url 请求 URL
|
||||
* @param requestBody 请求体
|
||||
* @param actionName 操作名称
|
||||
* @return 响应结果
|
||||
*/
|
||||
private <T> CommonResult<Boolean> doPost(String url, T requestBody, String actionName) {
|
||||
log.info("[{}] Sending request to URL: {}", actionName, url);
|
||||
try {
|
||||
// 这里指定返回类型为 CommonResult<?>,根据后台服务返回的实际结构做调整
|
||||
restTemplate.postForObject(url, requestBody, CommonResult.class);
|
||||
// TODO @haohao:check 结果,是否成功
|
||||
return success(true);
|
||||
CommonResult<?> response = restTemplate.postForObject(url, requestBody, CommonResult.class);
|
||||
if (response != null && response.isSuccess()) {
|
||||
return success(true);
|
||||
} else {
|
||||
log.warn("[{}] Request to URL: {} failed with response: {}", actionName, url, response);
|
||||
return CommonResult.error(500, "Request failed");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[{}] Error sending request to URL: {}", actionName, url, e);
|
||||
return CommonResult.error(400, "Request error: " + e.getMessage());
|
||||
|
@@ -1,31 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.plugin.common.config;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
|
||||
import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
// TODO @haohao:这个最好是 autoconfiguration
|
||||
@Configuration
|
||||
public class DeviceDataApiInitializer {
|
||||
|
||||
// TODO @haohao:这个要不搞个配置类哈
|
||||
@Value("${iot.device-data.url}")
|
||||
private String deviceDataUrl;
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
// TODO haohao:如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置
|
||||
return new RestTemplateBuilder().build();
|
||||
}
|
||||
|
||||
// TODO @haohao:不存在时,才构建
|
||||
@Bean
|
||||
public DeviceDataApi deviceDataApi(RestTemplate restTemplate) {
|
||||
return new DeviceDataApiClient(restTemplate, deviceDataUrl);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package cn.iocoder.yudao.module.iot.plugin.common.config;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
|
||||
import cn.iocoder.yudao.module.iot.plugin.common.api.DeviceDataApiClient;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* 设备数据 API 初始化器
|
||||
*
|
||||
* @author haohao
|
||||
*/
|
||||
@AutoConfiguration
|
||||
public class YudaoDeviceDataApiAutoConfiguration {
|
||||
|
||||
|
||||
// TODO @haohao:这个要不搞个配置类哈
|
||||
@Value("${iot.device-data.url}")
|
||||
private String deviceDataUrl;
|
||||
|
||||
/**
|
||||
* 创建 RestTemplate 实例
|
||||
*
|
||||
* @return RestTemplate 实例
|
||||
*/
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
// 如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置
|
||||
return new RestTemplateBuilder()
|
||||
.setConnectTimeout(Duration.ofMillis(5000)) // 设置连接超时时间
|
||||
.setReadTimeout(Duration.ofMillis(5000)) // 设置读取超时时间
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 DeviceDataApi 实例
|
||||
*
|
||||
* @param restTemplate RestTemplate 实例
|
||||
* @return DeviceDataApi 实例
|
||||
*/
|
||||
@Bean
|
||||
public DeviceDataApi deviceDataApi(RestTemplate restTemplate) {
|
||||
return new DeviceDataApiClient(restTemplate, deviceDataUrl);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1 @@
|
||||
cn.iocoder.yudao.module.iot.plugin.common.config.YudaoDeviceDataApiAutoConfiguration
|
@@ -11,7 +11,7 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
* 独立运行入口
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootApplication(scanBasePackages = "cn.iocoder.yudao.module.iot.plugin") // TODO @haohao:建议不扫描 cn.iocoder.yudao.module.iot.plugin;而是通过自动配置,初始化 common 的
|
||||
@SpringBootApplication
|
||||
public class HttpPluginSpringbootApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
@@ -21,6 +21,7 @@ public class HttpPluginSpringbootApplication {
|
||||
|
||||
// 手动获取 VertxService 并启动
|
||||
// TODO @haohao:可以放在 bean 的 init 里么?
|
||||
// 会和插件模式冲突
|
||||
VertxService vertxService = context.getBean(VertxService.class);
|
||||
vertxService.startServer();
|
||||
|
||||
|
@@ -21,30 +21,41 @@ public class HttpVertxPlugin extends SpringPlugin {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// TODO @haohao:这种最好启动中,启动完成,成对打印日志,方便定位问题
|
||||
log.info("[HttpVertxPlugin][start ...]");
|
||||
log.info("[HttpVertxPlugin][start][begin] 开始启动 HttpVertxPlugin 插件...");
|
||||
|
||||
// 1. 获取插件上下文
|
||||
ApplicationContext pluginContext = getApplicationContext();
|
||||
if (pluginContext == null) {
|
||||
log.error("[HttpVertxPlugin] pluginContext is null, start failed.");
|
||||
return;
|
||||
try {
|
||||
// 1. 获取插件上下文
|
||||
ApplicationContext pluginContext = getApplicationContext();
|
||||
if (pluginContext == null) {
|
||||
log.error("[HttpVertxPlugin][start][fail] pluginContext is null, 启动失败!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 启动 Vert.x
|
||||
VertxService vertxService = pluginContext.getBean(VertxService.class);
|
||||
vertxService.startServer();
|
||||
|
||||
log.info("[HttpVertxPlugin][start][end] 启动完成");
|
||||
} catch (Exception e) {
|
||||
log.error("[HttpVertxPlugin][start][exception] 启动过程出现异常!", e);
|
||||
}
|
||||
|
||||
// 2. 启动 Vertx
|
||||
VertxService vertxService = pluginContext.getBean(VertxService.class);
|
||||
vertxService.startServer();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
log.info("[HttpVertxPlugin][stop ...]");
|
||||
ApplicationContext pluginContext = getApplicationContext();
|
||||
if (pluginContext != null) {
|
||||
// 停止服务器
|
||||
VertxService vertxService = pluginContext.getBean(VertxService.class);
|
||||
vertxService.stopServer();
|
||||
log.info("[HttpVertxPlugin][stop][begin] 开始停止 HttpVertxPlugin 插件...");
|
||||
|
||||
try {
|
||||
ApplicationContext pluginContext = getApplicationContext();
|
||||
if (pluginContext != null) {
|
||||
// 停止服务器
|
||||
VertxService vertxService = pluginContext.getBean(VertxService.class);
|
||||
vertxService.stopServer();
|
||||
}
|
||||
|
||||
log.info("[HttpVertxPlugin][stop][end] 停止完成");
|
||||
} catch (Exception e) {
|
||||
log.error("[HttpVertxPlugin][stop][exception] 停止过程出现异常!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,5 +79,4 @@ public class HttpVertxPlugin extends SpringPlugin {
|
||||
|
||||
return pluginContext;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -34,6 +34,10 @@ public class HttpVertxPluginConfiguration {
|
||||
|
||||
/**
|
||||
* 创建路由
|
||||
*
|
||||
* @param vertx Vertx 实例
|
||||
* @param httpVertxHandler HttpVertxHandler 实例
|
||||
* @return Router 实例
|
||||
*/
|
||||
@Bean
|
||||
public Router router(Vertx vertx, HttpVertxHandler httpVertxHandler) {
|
||||
@@ -50,6 +54,12 @@ public class HttpVertxPluginConfiguration {
|
||||
return router;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 HttpVertxHandler 实例
|
||||
*
|
||||
* @param deviceDataApi DeviceDataApi 实例
|
||||
* @return HttpVertxHandler 实例
|
||||
*/
|
||||
@Bean
|
||||
public HttpVertxHandler httpVertxHandler(DeviceDataApi deviceDataApi) {
|
||||
return new HttpVertxHandler(deviceDataApi);
|
||||
@@ -58,6 +68,10 @@ public class HttpVertxPluginConfiguration {
|
||||
/**
|
||||
* 定义一个 VertxService 来管理服务器启动逻辑
|
||||
* 无论是独立运行还是插件方式,都可以共用此类
|
||||
*
|
||||
* @param vertx Vertx 实例
|
||||
* @param router Router 实例
|
||||
* @return VertxService 实例
|
||||
*/
|
||||
@Bean
|
||||
public VertxService vertxService(Vertx vertx, Router router) {
|
||||
|
@@ -5,3 +5,8 @@ spring:
|
||||
iot:
|
||||
device-data:
|
||||
url: http://127.0.0.1:48080
|
||||
|
||||
plugin:
|
||||
http:
|
||||
server:
|
||||
port: 8092
|
||||
|
Reference in New Issue
Block a user