Commit e998b0c7ebe0123972f9a3aaaf43aacdba0ff75d

Authored by YunaiV
1 parent a2532013

【代码评审】IoT:评审 plugin 实现

yudao-module-iot/yudao-module-iot-api/pom.xml
... ... @@ -22,6 +22,7 @@
22 22 <artifactId>yudao-common</artifactId>
23 23 </dependency>
24 24 <!-- PF4J -->
  25 + <!-- TODO 芋艿:这个依赖,要不要放在 api 包 -->
25 26 <dependency>
26 27 <groupId>org.pf4j</groupId>
27 28 <artifactId>pf4j-spring</artifactId>
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java
... ... @@ -7,6 +7,7 @@ import java.util.Map;
7 7 * 服务注册表 - 插架模块使用,无法使用 Spring 注入
8 8 */
9 9 public class ServiceRegistry {
  10 +
10 11 private static final Map<Class<?>, Object> services = new HashMap<>();
11 12  
12 13 /**
... ... @@ -31,4 +32,5 @@ public class ServiceRegistry {
31 32 public static <T> T getService(Class<T> serviceClass) {
32 33 return (T) services.get(serviceClass);
33 34 }
  35 +
34 36 }
35 37 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java
1   -package cn.iocoder.yudao.module.iot.api;
  1 +package cn.iocoder.yudao.module.iot.api.device;
2 2  
3 3 /**
4 4 * 设备数据 API
... ...
yudao-module-iot/yudao-module-iot-biz/pom.xml
... ... @@ -81,6 +81,7 @@
81 81 <dependency>
82 82 <groupId>org.pf4j</groupId>
83 83 <artifactId>pf4j-spring</artifactId>
  84 + <!-- TODO @芋艿:可以放到 bom 里配置 -->
84 85 <exclusions>
85 86 <exclusion>
86 87 <groupId>org.slf4j</groupId>
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java
1 1 package cn.iocoder.yudao.module.iot.api.device;
2 2  
3   -import cn.iocoder.yudao.module.iot.api.DeviceDataApi;
4 3 import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService;
5 4 import org.springframework.stereotype.Service;
6 5 import org.springframework.validation.annotation.Validated;
... ... @@ -15,11 +14,11 @@ import javax.annotation.Resource;
15 14 public class DeviceDataApiImpl implements DeviceDataApi {
16 15  
17 16 @Resource
18   - private IotDeviceDataService iotDeviceDataService;
  17 + private IotDeviceDataService deviceDataService;
19 18  
20 19 @Override
21 20 public void saveDeviceData(String productKey, String deviceName, String message) {
22   - iotDeviceDataService.saveDeviceData(productKey, deviceName, message);
  21 + deviceDataService.saveDeviceData(productKey, deviceName, message);
23 22 }
24 23  
25 24 }
26 25 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
  1 +/**
  2 + * 占位
  3 + *
  4 + * TODO 芋艿:后续删除
  5 + */
1 6 package cn.iocoder.yudao.module.iot.api;
2 7 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java
1 1 package cn.iocoder.yudao.module.iot.framework.plugin;
2 2  
3   -import cn.iocoder.yudao.module.iot.api.DeviceDataApi;
  3 +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
4 4 import cn.iocoder.yudao.module.iot.api.ServiceRegistry;
5 5 import lombok.extern.slf4j.Slf4j;
6 6 import org.springframework.context.annotation.Bean;
... ... @@ -26,9 +26,10 @@ public class ServiceRegistryConfiguration {
26 26 /**
27 27 * 定义一个标记用的 Bean,用于表示 ServiceRegistry 已初始化完成
28 28 */
29   - @Bean("serviceRegistryInitializedMarker")
  29 + @Bean("serviceRegistryInitializedMarker") // TODO @haohao:1)这个名字,可以搞个 public static final 常量;2)是不是 conditionBefore 啥
30 30 public Object serviceRegistryInitializedMarker() {
31   - // 返回任意对象即可,这里返回null都可以,但最好返回个实际对象
  31 + // 返回任意对象即可,这里返回 null 都可以,但最好返回个实际对象
32 32 return new Object();
33 33 }
  34 +
34 35 }
35 36 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java
... ... @@ -21,7 +21,7 @@ public interface IotDeviceDataService {
21 21 * @param productKey 产品 key
22 22 * @param deviceName 设备名称
23 23 * @param message 消息
24   - * <p>JSON 格式,参见 <a href="https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services?spm=a2c4g.11186623.0.0.3a3335aeUdzkz2#concept-mvc-4tw-y2b">...</a>
  24 + * <p>参见 <a href="https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services?spm=a2c4g.11186623.0.0.3a3335aeUdzkz2#concept-mvc-4tw-y2b">JSON 格式</a>
25 25 */
26 26 void saveDeviceData(String productKey, String deviceName, String message);
27 27  
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java
... ... @@ -13,6 +13,7 @@ import org.springframework.validation.annotation.Validated;
13 13 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
14 14 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INSTANCE_NOT_EXISTS;
15 15  
  16 +// TODO @haohao:可以搞个 plugin 包,然后把 plugininfo、plugininstance
16 17 /**
17 18 * IoT 插件实例 Service 实现类
18 19 *
... ...
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java
... ... @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin;
2 2  
3 3 import cn.hutool.json.JSONObject;
4 4 import cn.hutool.json.JSONUtil;
5   -import cn.iocoder.yudao.module.iot.api.DeviceDataApi;
  5 +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
6 6 import io.netty.buffer.Unpooled;
7 7 import io.netty.channel.ChannelFutureListener;
8 8 import io.netty.channel.ChannelHandlerContext;
... ... @@ -12,12 +12,9 @@ import io.netty.util.CharsetUtil;
12 12  
13 13 /**
14 14 * 基于 Netty 的 HTTP 处理器,用于接收设备上报的数据并调用主程序的 DeviceDataApi 接口进行处理。
15   - * <p>
16   - * 请求格式:
17   - * POST /sys/{productKey}/{deviceName}/thing/event/property/post
18   - * 请求体为 JSON 格式数据。
19   - * <p>
20   - * 返回结果为 JSON 格式,包含统一的 code、data、id、message、method、version 字段。
  15 + *
  16 + * 1. 请求格式:JSON 格式,地址为 POST /sys/{productKey}/{deviceName}/thing/event/property/post
  17 + * 2. 返回结果:JSON 格式,包含统一的 code、data、id、message、method、version 字段
21 18 */
22 19 public class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
23 20  
... ... @@ -29,10 +26,9 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
29 26  
30 27 @Override
31 28 protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {
32   - String uri = request.uri();
33   -
34 29 // 期望的路径格式: /sys/{productKey}/{deviceName}/thing/event/property/post
35 30 // 使用 "/" 拆分路径
  31 + String uri = request.uri();
36 32 String[] parts = uri.split("/");
37 33  
38 34 /*
... ... @@ -52,25 +48,19 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
52 48 && "event".equals(parts[5])
53 49 && "property".equals(parts[6])
54 50 && "post".equals(parts[7]);
55   -
56 51 if (!isCorrectPath) {
57   - // 如果路径不匹配,返回 404 错误
58 52 writeResponse(ctx, HttpResponseStatus.NOT_FOUND, "Not Found");
59 53 return;
60 54 }
61   -
62 55 String productKey = parts[2];
63 56 String deviceName = parts[3];
64 57  
65   - // 从请求中获取原始数据
  58 + // 从请求中获取原始数据,尝试解析请求数据为 JSON 对象
66 59 String requestBody = request.content().toString(CharsetUtil.UTF_8);
67   -
68   - // 尝试解析请求数据为 JSON 对象
69 60 JSONObject jsonData;
70 61 try {
71 62 jsonData = JSONUtil.parseObj(requestBody);
72 63 } catch (Exception e) {
73   - // 数据不是合法的 JSON 格式,返回 400 错误
74 64 JSONObject res = createResponseJson(
75 65 400,
76 66 new JSONObject(),
... ... @@ -82,8 +72,6 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
82 72 writeResponse(ctx, HttpResponseStatus.BAD_REQUEST, res.toString());
83 73 return;
84 74 }
85   -
86   - // 获取请求中的 id 字段,若不存在则为 null
87 75 String id = jsonData.getStr("id", null);
88 76  
89 77 try {
... ... @@ -101,7 +89,6 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
101 89 );
102 90 writeResponse(ctx, HttpResponseStatus.OK, successRes.toString());
103 91 } catch (Exception e) {
104   - // 保存数据过程中出现异常,返回 500 错误
105 92 JSONObject errorRes = createResponseJson(
106 93 500,
107 94 new JSONObject(),
... ... @@ -128,7 +115,7 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
128 115 private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, String version) {
129 116 JSONObject res = new JSONObject();
130 117 res.set("code", code);
131   - res.set("data", data != null ? data : new JSONObject()); // 确保 data 不为 null
  118 + res.set("data", data != null ? data : new JSONObject());
132 119 res.set("id", id);
133 120 res.set("message", message);
134 121 res.set("method", method);
... ... @@ -137,24 +124,24 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
137 124 }
138 125  
139 126 /**
140   - * 向客户端返回 HTTP 响应的辅助方法。
  127 + * 向客户端返回 HTTP 响应的辅助方法
141 128 *
142 129 * @param ctx 通道上下文
143 130 * @param status HTTP 响应状态码(网络层面的)
144 131 * @param content 响应内容(JSON 字符串或其他文本)
145 132 */
146 133 private void writeResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String content) {
  134 + // 设置响应头为 JSON 类型和正确的编码
147 135 FullHttpResponse response = new DefaultFullHttpResponse(
148 136 HttpVersion.HTTP_1_1,
149 137 status,
150 138 Unpooled.copiedBuffer(content, CharsetUtil.UTF_8)
151 139 );
152   -
153   - // 设置响应头为 JSON 类型和正确的编码
154 140 response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
155 141 response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
156 142  
157 143 // 发送响应并在发送完成后关闭连接
158 144 ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
159 145 }
  146 +
160 147 }
161 148 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java
1 1 package cn.iocoder.yudao.module.iot.plugin;
2 2  
3   -import cn.iocoder.yudao.module.iot.api.DeviceDataApi;
  3 +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
4 4 import cn.iocoder.yudao.module.iot.api.ServiceRegistry;
5 5 import io.netty.bootstrap.ServerBootstrap;
6 6 import io.netty.channel.*;
... ... @@ -18,12 +18,14 @@ import java.util.concurrent.Executors;
18 18 public class HttpPlugin extends Plugin {
19 19  
20 20 private static final int PORT = 8092;
  21 +
21 22 private final ExecutorService executorService;
22   - private DeviceDataApi deviceDataApi; // 用于保存设备数据的 API
  23 + private DeviceDataApi deviceDataApi;
23 24  
24 25 public HttpPlugin(PluginWrapper wrapper) {
25 26 super(wrapper);
26   - this.executorService = Executors.newSingleThreadExecutor(); // 创建单线程池
  27 + // 创建单线程池
  28 + this.executorService = Executors.newSingleThreadExecutor();
27 29 }
28 30  
29 31 @Override
... ... @@ -44,10 +46,13 @@ public class HttpPlugin extends Plugin {
44 46 @Override
45 47 public void stop() {
46 48 log.info("HttpPlugin.stop()");
47   - executorService.shutdownNow(); // 停止线程池
  49 + // 停止线程池
  50 + executorService.shutdownNow();
48 51 }
49 52  
50   - // 启动 HTTP 服务
  53 + /**
  54 + * 启动 HTTP 服务
  55 + */
51 56 private void startHttpServer() {
52 57 EventLoopGroup bossGroup = new NioEventLoopGroup(1);
53 58 EventLoopGroup workerGroup = new NioEventLoopGroup();
... ... @@ -56,7 +61,8 @@ public class HttpPlugin extends Plugin {
56 61 ServerBootstrap bootstrap = new ServerBootstrap();
57 62 bootstrap.group(bossGroup, workerGroup)
58 63 .channel(NioServerSocketChannel.class)
59   - .childHandler(new ChannelInitializer<Channel>() {
  64 + .childHandler(new ChannelInitializer<>() {
  65 +
60 66 @Override
61 67 protected void initChannel(Channel channel) {
62 68 channel.pipeline().addLast(new HttpServerCodec());
... ... @@ -64,6 +70,7 @@ public class HttpPlugin extends Plugin {
64 70 // 将从 ServiceRegistry 获取的 deviceDataApi 传入处理器
65 71 channel.pipeline().addLast(new HttpHandler(deviceDataApi));
66 72 }
  73 +
67 74 });
68 75  
69 76 // 绑定端口并启动服务器
... ... @@ -78,4 +85,5 @@ public class HttpPlugin extends Plugin {
78 85 workerGroup.shutdownGracefully();
79 86 }
80 87 }
  88 +
81 89 }
... ...