From e998b0c7ebe0123972f9a3aaaf43aacdba0ff75d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 21 Dec 2024 16:28:25 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84=E5=AE=A1?= =?UTF-8?q?=E3=80=91IoT=EF=BC=9A=E8=AF=84=E5=AE=A1=20plugin=20=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/yudao-module-iot-api/pom.xml | 1 + .../yudao/module/iot/api/ServiceRegistry.java | 2 ++ .../iot/api/{ => device}/DeviceDataApi.java | 2 +- yudao-module-iot/yudao-module-iot-biz/pom.xml | 1 + .../iot/api/device/DeviceDataApiImpl.java | 5 ++- .../yudao/module/iot/api/package-info.java | 5 +++ .../plugin/ServiceRegistryConfiguration.java | 7 ++-- .../service/device/IotDeviceDataService.java | 2 +- .../PluginInstanceServiceImpl.java | 1 + .../yudao/module/iot/plugin/HttpHandler.java | 33 ++++++------------- .../yudao/module/iot/plugin/HttpPlugin.java | 20 +++++++---- 11 files changed, 42 insertions(+), 37 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/{ => device}/DeviceDataApi.java (85%) diff --git a/yudao-module-iot/yudao-module-iot-api/pom.xml b/yudao-module-iot/yudao-module-iot-api/pom.xml index a370944457..d2f83b785e 100644 --- a/yudao-module-iot/yudao-module-iot-api/pom.xml +++ b/yudao-module-iot/yudao-module-iot-api/pom.xml @@ -22,6 +22,7 @@ yudao-common + org.pf4j pf4j-spring diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java index 5c55bd89cb..5603ad8d72 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java +++ b/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; * 服务注册表 - 插架模块使用,无法使用 Spring 注入 */ public class ServiceRegistry { + private static final Map, Object> services = new HashMap<>(); /** @@ -31,4 +32,5 @@ public class ServiceRegistry { public static T getService(Class serviceClass) { return (T) services.get(serviceClass); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java index 2f3ef60477..cb747f5053 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/DeviceDataApi.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApi.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.api; +package cn.iocoder.yudao.module.iot.api.device; /** * 设备数据 API diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index c0810a183d..19b50ec215 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -81,6 +81,7 @@ org.pf4j pf4j-spring + org.slf4j diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java index 59ae850a1e..d62c20cb54 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/DeviceDataApiImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.api.device; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; import cn.iocoder.yudao.module.iot.service.device.IotDeviceDataService; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -15,11 +14,11 @@ import javax.annotation.Resource; public class DeviceDataApiImpl implements DeviceDataApi { @Resource - private IotDeviceDataService iotDeviceDataService; + private IotDeviceDataService deviceDataService; @Override public void saveDeviceData(String productKey, String deviceName, String message) { - iotDeviceDataService.saveDeviceData(productKey, deviceName, message); + deviceDataService.saveDeviceData(productKey, deviceName, message); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java index c0f3d748a1..07852180d4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java @@ -1 +1,6 @@ +/** + * 占位 + * + * TODO 芋艿:后续删除 + */ package cn.iocoder.yudao.module.iot.api; \ 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/ServiceRegistryConfiguration.java index 385c8aee56..3450b67fb9 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/ServiceRegistryConfiguration.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; @@ -26,9 +26,10 @@ public class ServiceRegistryConfiguration { /** * 定义一个标记用的 Bean,用于表示 ServiceRegistry 已初始化完成 */ - @Bean("serviceRegistryInitializedMarker") + @Bean("serviceRegistryInitializedMarker") // TODO @haohao:1)这个名字,可以搞个 public static final 常量;2)是不是 conditionBefore 啥 public Object serviceRegistryInitializedMarker() { - // 返回任意对象即可,这里返回null都可以,但最好返回个实际对象 + // 返回任意对象即可,这里返回 null 都可以,但最好返回个实际对象 return new Object(); } + } \ 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/device/IotDeviceDataService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java index 1dd4ad666e..1c246e2c70 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceDataService.java +++ b/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 { * @param productKey 产品 key * @param deviceName 设备名称 * @param message 消息 - *

JSON 格式,参见 ... + *

参见 JSON 格式 */ void saveDeviceData(String productKey, String deviceName, String message); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java index 405efe1636..afb05ef2f8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininstance/PluginInstanceServiceImpl.java +++ b/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; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INSTANCE_NOT_EXISTS; +// TODO @haohao:可以搞个 plugin 包,然后把 plugininfo、plugininstance /** * IoT 插件实例 Service 实现类 * diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java index c145182eda..6d0908683b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpHandler.java +++ b/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; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; @@ -12,12 +12,9 @@ import io.netty.util.CharsetUtil; /** * 基于 Netty 的 HTTP 处理器,用于接收设备上报的数据并调用主程序的 DeviceDataApi 接口进行处理。 - *

- * 请求格式: - * POST /sys/{productKey}/{deviceName}/thing/event/property/post - * 请求体为 JSON 格式数据。 - *

- * 返回结果为 JSON 格式,包含统一的 code、data、id、message、method、version 字段。 + * + * 1. 请求格式:JSON 格式,地址为 POST /sys/{productKey}/{deviceName}/thing/event/property/post + * 2. 返回结果:JSON 格式,包含统一的 code、data、id、message、method、version 字段 */ public class HttpHandler extends SimpleChannelInboundHandler { @@ -29,10 +26,9 @@ public class HttpHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { - String uri = request.uri(); - // 期望的路径格式: /sys/{productKey}/{deviceName}/thing/event/property/post // 使用 "/" 拆分路径 + String uri = request.uri(); String[] parts = uri.split("/"); /* @@ -52,25 +48,19 @@ public class HttpHandler extends SimpleChannelInboundHandler { && "event".equals(parts[5]) && "property".equals(parts[6]) && "post".equals(parts[7]); - if (!isCorrectPath) { - // 如果路径不匹配,返回 404 错误 writeResponse(ctx, HttpResponseStatus.NOT_FOUND, "Not Found"); return; } - String productKey = parts[2]; String deviceName = parts[3]; - // 从请求中获取原始数据 + // 从请求中获取原始数据,尝试解析请求数据为 JSON 对象 String requestBody = request.content().toString(CharsetUtil.UTF_8); - - // 尝试解析请求数据为 JSON 对象 JSONObject jsonData; try { jsonData = JSONUtil.parseObj(requestBody); } catch (Exception e) { - // 数据不是合法的 JSON 格式,返回 400 错误 JSONObject res = createResponseJson( 400, new JSONObject(), @@ -82,8 +72,6 @@ public class HttpHandler extends SimpleChannelInboundHandler { writeResponse(ctx, HttpResponseStatus.BAD_REQUEST, res.toString()); return; } - - // 获取请求中的 id 字段,若不存在则为 null String id = jsonData.getStr("id", null); try { @@ -101,7 +89,6 @@ public class HttpHandler extends SimpleChannelInboundHandler { ); writeResponse(ctx, HttpResponseStatus.OK, successRes.toString()); } catch (Exception e) { - // 保存数据过程中出现异常,返回 500 错误 JSONObject errorRes = createResponseJson( 500, new JSONObject(), @@ -128,7 +115,7 @@ public class HttpHandler extends SimpleChannelInboundHandler { private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, String version) { JSONObject res = new JSONObject(); res.set("code", code); - res.set("data", data != null ? data : new JSONObject()); // 确保 data 不为 null + res.set("data", data != null ? data : new JSONObject()); res.set("id", id); res.set("message", message); res.set("method", method); @@ -137,24 +124,24 @@ public class HttpHandler extends SimpleChannelInboundHandler { } /** - * 向客户端返回 HTTP 响应的辅助方法。 + * 向客户端返回 HTTP 响应的辅助方法 * * @param ctx 通道上下文 * @param status HTTP 响应状态码(网络层面的) * @param content 响应内容(JSON 字符串或其他文本) */ private void writeResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String content) { + // 设置响应头为 JSON 类型和正确的编码 FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(content, CharsetUtil.UTF_8) ); - - // 设置响应头为 JSON 类型和正确的编码 response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8"); response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); // 发送响应并在发送完成后关闭连接 ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java index 68311300e7..70da0131ce 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; @@ -18,12 +18,14 @@ import java.util.concurrent.Executors; public class HttpPlugin extends Plugin { private static final int PORT = 8092; + private final ExecutorService executorService; - private DeviceDataApi deviceDataApi; // 用于保存设备数据的 API + private DeviceDataApi deviceDataApi; public HttpPlugin(PluginWrapper wrapper) { super(wrapper); - this.executorService = Executors.newSingleThreadExecutor(); // 创建单线程池 + // 创建单线程池 + this.executorService = Executors.newSingleThreadExecutor(); } @Override @@ -44,10 +46,13 @@ public class HttpPlugin extends Plugin { @Override public void stop() { log.info("HttpPlugin.stop()"); - executorService.shutdownNow(); // 停止线程池 + // 停止线程池 + executorService.shutdownNow(); } - // 启动 HTTP 服务 + /** + * 启动 HTTP 服务 + */ private void startHttpServer() { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); @@ -56,7 +61,8 @@ public class HttpPlugin extends Plugin { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { + .childHandler(new ChannelInitializer<>() { + @Override protected void initChannel(Channel channel) { channel.pipeline().addLast(new HttpServerCodec()); @@ -64,6 +70,7 @@ public class HttpPlugin extends Plugin { // 将从 ServiceRegistry 获取的 deviceDataApi 传入处理器 channel.pipeline().addLast(new HttpHandler(deviceDataApi)); } + }); // 绑定端口并启动服务器 @@ -78,4 +85,5 @@ public class HttpPlugin extends Plugin { workerGroup.shutdownGracefully(); } } + }