Commit 77b89aad773e021b2a7f9d0c85bdbbec468af000

Authored by 安浩浩
1 parent cde6ebf9

【功能完善】IoT: 集成 Vert.x 支持,重构 HTTP 插件为 Vert.x 插件

yudao-dependencies/pom.xml
... ... @@ -67,6 +67,7 @@
67 67 <bizlog-sdk.version>3.0.6</bizlog-sdk.version>
68 68 <mqtt.version>1.2.5</mqtt.version>
69 69 <pf4j-spring.version>0.9.0</pf4j-spring.version>
  70 + <vertx.version>4.4.0</vertx.version>
70 71 <!-- 三方云服务相关 -->
71 72 <okio.version>3.5.0</okio.version>
72 73 <okhttp3.version>4.11.0</okhttp3.version>
... ... @@ -613,6 +614,19 @@
613 614 <version>${pf4j-spring.version}</version>
614 615 </dependency>
615 616  
  617 + <!-- Vert.x 核心依赖 -->
  618 + <dependency>
  619 + <groupId>io.vertx</groupId>
  620 + <artifactId>vertx-core</artifactId>
  621 + <version>${vertx.version}</version>
  622 + </dependency>
  623 + <!-- Vert.x Web 模块 -->
  624 + <dependency>
  625 + <groupId>io.vertx</groupId>
  626 + <artifactId>vertx-web</artifactId>
  627 + <version>${vertx.version}</version>
  628 + </dependency>
  629 +
616 630 </dependencies>
617 631 </dependencyManagement>
618 632  
... ...
yudao-module-iot/yudao-module-iot-biz/pom.xml
... ... @@ -64,6 +64,16 @@
64 64 <artifactId>yudao-spring-boot-starter-excel</artifactId>
65 65 </dependency>
66 66  
  67 + <!-- Vert.x 核心依赖 -->
  68 + <dependency>
  69 + <groupId>io.vertx</groupId>
  70 + <artifactId>vertx-core</artifactId>
  71 + </dependency>
  72 + <!-- Vert.x Web 模块 -->
  73 + <dependency>
  74 + <groupId>io.vertx</groupId>
  75 + <artifactId>vertx-web</artifactId>
  76 + </dependency>
67 77 <!-- MQTT -->
68 78 <dependency>
69 79 <groupId>org.eclipse.paho</groupId>
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java
... ... @@ -196,10 +196,8 @@ public class PluginInstanceServiceImpl implements PluginInstanceService {
196 196 .collect(Collectors.toMap(PluginInfoDO::getPluginKey, Function.identity()));
197 197  
198 198 // 3. 获取本机 IP 和 MAC 地址
199   - LinkedHashSet<InetAddress> localAddressList = NetUtil.localAddressList(t -> t instanceof Inet4Address);
200   - LinkedHashSet<String> ipList = NetUtil.toIpList(localAddressList);
201   - String ip = ipList.stream().findFirst().orElse("127.0.0.1");
202   - String mac = NetUtil.getMacAddress(localAddressList.stream().findFirst().orElse(null));
  199 + String ip = NetUtil.getLocalhostStr();
  200 + String mac = NetUtil.getLocalMacAddress();
203 201 String mainId = MAIN_ID + "-" + mac;
204 202  
205 203 // 4. 遍历插件列表,并保存为插件实例
... ...
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/dependency-reduced-pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  3 + <parent>
  4 + <artifactId>yudao-module-iot-plugin</artifactId>
  5 + <groupId>cn.iocoder.boot</groupId>
  6 + <version>2.2.0-snapshot</version>
  7 + </parent>
  8 + <modelVersion>4.0.0</modelVersion>
  9 + <artifactId>yudao-module-iot-http-plugin</artifactId>
  10 + <name>${project.artifactId}</name>
  11 + <version>2.2.0-snapshot</version>
  12 + <description>物联网 插件模块 - http 插件</description>
  13 + <build>
  14 + <plugins>
  15 + <plugin>
  16 + <artifactId>maven-jar-plugin</artifactId>
  17 + <version>2.4</version>
  18 + <configuration>
  19 + <archive>
  20 + <manifestEntries>
  21 + <Plugin-Id>${plugin.id}</Plugin-Id>
  22 + <Plugin-Class>${plugin.class}</Plugin-Class>
  23 + <Plugin-Version>${plugin.version}</Plugin-Version>
  24 + <Plugin-Provider>${plugin.provider}</Plugin-Provider>
  25 + <Plugin-Description>${plugin.description}</Plugin-Description>
  26 + <Plugin-Dependencies>${plugin.dependencies}</Plugin-Dependencies>
  27 + </manifestEntries>
  28 + </archive>
  29 + </configuration>
  30 + </plugin>
  31 + <plugin>
  32 + <artifactId>maven-deploy-plugin</artifactId>
  33 + <configuration>
  34 + <skip>true</skip>
  35 + </configuration>
  36 + </plugin>
  37 + <plugin>
  38 + <artifactId>maven-shade-plugin</artifactId>
  39 + <version>3.4.1</version>
  40 + <executions>
  41 + <execution>
  42 + <phase>package</phase>
  43 + <goals>
  44 + <goal>shade</goal>
  45 + </goals>
  46 + <configuration>
  47 + <shadedArtifactAttached>true</shadedArtifactAttached>
  48 + <shadedClassifierName>shaded</shadedClassifierName>
  49 + <transformers>
  50 + <transformer>
  51 + <mainClass>cn.iocoder.yudao.module.iot.HttpPluginSpringbootApplication</mainClass>
  52 + </transformer>
  53 + </transformers>
  54 + </configuration>
  55 + </execution>
  56 + </executions>
  57 + </plugin>
  58 + </plugins>
  59 + </build>
  60 + <dependencies>
  61 + <dependency>
  62 + <groupId>org.pf4j</groupId>
  63 + <artifactId>pf4j-spring</artifactId>
  64 + <version>0.9.0</version>
  65 + <scope>provided</scope>
  66 + </dependency>
  67 + <dependency>
  68 + <groupId>org.projectlombok</groupId>
  69 + <artifactId>lombok</artifactId>
  70 + <version>1.18.34</version>
  71 + <scope>provided</scope>
  72 + </dependency>
  73 + </dependencies>
  74 + <properties>
  75 + <plugin.class>cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin</plugin.class>
  76 + <plugin.version>0.0.1</plugin.version>
  77 + <plugin.id>http-plugin</plugin.id>
  78 + <plugin.description>http-plugin-0.0.1</plugin.description>
  79 + <plugin.provider>ahh</plugin.provider>
  80 + </properties>
  81 +</project>
... ...
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/plugin.properties
1 1 plugin.id=http-plugin
2   -plugin.class=cn.iocoder.yudao.module.iot.plugin.HttpPlugin
  2 +plugin.class=cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin
3 3 plugin.version=0.0.1
4 4 plugin.provider=ahh
5 5 plugin.dependencies=
... ...
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml
... ... @@ -21,7 +21,7 @@
21 21 <properties>
22 22 <!-- 插件相关 -->
23 23 <plugin.id>http-plugin</plugin.id>
24   - <plugin.class>cn.iocoder.yudao.module.iot.plugin.HttpPlugin</plugin.class>
  24 + <plugin.class>cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin</plugin.class>
25 25 <plugin.version>0.0.1</plugin.version>
26 26 <plugin.provider>ahh</plugin.provider>
27 27 <plugin.description>http-plugin-0.0.1</plugin.description>
... ... @@ -30,27 +30,6 @@
30 30  
31 31 <build>
32 32 <plugins>
33   - <!-- DOESN'T WORK WITH MAVEN 3 (I defined the plugin metadata in properties section)
34   - <plugin>
35   - <groupId>org.codehaus.mojo</groupId>
36   - <artifactId>properties-maven-plugin</artifactId>
37   - <version>1.0-alpha-2</version>
38   - <executions>
39   - <execution>
40   - <phase>initialize</phase>
41   - <goals>
42   - <goal>read-project-properties</goal>
43   - </goals>
44   - <configuration>
45   - <files>
46   - <file>plugin.properties</file>
47   - </files>
48   - </configuration>
49   - </execution>
50   - </executions>
51   - </plugin>
52   - -->
53   -
54 33 <plugin>
55 34 <groupId>org.apache.maven.plugins</groupId>
56 35 <artifactId>maven-antrun-plugin</artifactId>
... ... @@ -118,6 +97,29 @@
118 97 <skip>true</skip>
119 98 </configuration>
120 99 </plugin>
  100 +
  101 + <!-- <plugin>-->
  102 + <!-- <groupId>org.apache.maven.plugins</groupId>-->
  103 + <!-- <artifactId>maven-shade-plugin</artifactId>-->
  104 + <!-- <version>3.4.1</version>-->
  105 + <!-- <executions>-->
  106 + <!-- <execution>-->
  107 + <!-- <phase>package</phase>-->
  108 + <!-- <goals>-->
  109 + <!-- <goal>shade</goal>-->
  110 + <!-- </goals>-->
  111 + <!-- <configuration>-->
  112 + <!-- <shadedArtifactAttached>true</shadedArtifactAttached>-->
  113 + <!-- <shadedClassifierName>shaded</shadedClassifierName>-->
  114 + <!-- <transformers>-->
  115 + <!-- <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">-->
  116 + <!-- <mainClass>cn.iocoder.yudao.module.iot.HttpPluginSpringbootApplication</mainClass>-->
  117 + <!-- </transformer>-->
  118 + <!-- </transformers>-->
  119 + <!-- </configuration>-->
  120 + <!-- </execution>-->
  121 + <!-- </executions>-->
  122 + <!-- </plugin>-->
121 123 </plugins>
122 124 </build>
123 125  
... ... @@ -145,10 +147,15 @@
145 147 <version>${lombok.version}</version>
146 148 <scope>provided</scope>
147 149 </dependency>
  150 + <!-- Vert.x 核心依赖 -->
  151 + <dependency>
  152 + <groupId>io.vertx</groupId>
  153 + <artifactId>vertx-core</artifactId>
  154 + </dependency>
  155 + <!-- Vert.x Web 模块 -->
148 156 <dependency>
149   - <groupId>io.netty</groupId>
150   - <artifactId>netty-all</artifactId>
151   - <version>4.1.63.Final</version> <!-- 版本可根据需要调整 -->
  157 + <groupId>io.vertx</groupId>
  158 + <artifactId>vertx-web</artifactId>
152 159 </dependency>
153 160 <!-- MQTT -->
154 161 <dependency>
... ...
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpPlugin.java deleted
1   -package cn.iocoder.yudao.module.iot.plugin;
2   -
3   -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
4   -import cn.iocoder.yudao.module.iot.api.ServiceRegistry;
5   -import io.netty.bootstrap.ServerBootstrap;
6   -import io.netty.channel.*;
7   -import io.netty.channel.nio.NioEventLoopGroup;
8   -import io.netty.channel.socket.nio.NioServerSocketChannel;
9   -import io.netty.handler.codec.http.*;
10   -import lombok.extern.slf4j.Slf4j;
11   -import org.pf4j.PluginWrapper;
12   -import org.pf4j.Plugin;
13   -
14   -import java.util.concurrent.ExecutorService;
15   -import java.util.concurrent.Executors;
16   -
17   -@Slf4j
18   -public class HttpPlugin extends Plugin {
19   -
20   - private static final int PORT = 8092;
21   -
22   - private ExecutorService executorService;
23   - private DeviceDataApi deviceDataApi;
24   -
25   - public HttpPlugin(PluginWrapper wrapper) {
26   - super(wrapper);
27   - // 初始化线程池
28   - this.executorService = Executors.newSingleThreadExecutor();
29   - }
30   -
31   - @Override
32   - public void start() {
33   - log.info("HttpPlugin.start()");
34   -
35   - // 重新初始化线程池,确保它是活跃的
36   - if (executorService.isShutdown() || executorService.isTerminated()) {
37   - executorService = Executors.newSingleThreadExecutor();
38   - }
39   -
40   - // 从 ServiceRegistry 中获取主程序暴露的 DeviceDataApi 接口实例
41   - deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class);
42   - if (deviceDataApi == null) {
43   - log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!");
44   - return;
45   - }
46   -
47   - // 异步启动 Netty 服务器
48   - executorService.submit(this::startHttpServer);
49   - }
50   -
51   - @Override
52   - public void stop() {
53   - log.info("HttpPlugin.stop()");
54   - // 停止线程池
55   - executorService.shutdownNow();
56   - }
57   -
58   - /**
59   - * 启动 HTTP 服务
60   - */
61   - private void startHttpServer() {
62   - EventLoopGroup bossGroup = new NioEventLoopGroup(1);
63   - EventLoopGroup workerGroup = new NioEventLoopGroup();
64   -
65   - try {
66   - ServerBootstrap bootstrap = new ServerBootstrap();
67   - bootstrap.group(bossGroup, workerGroup)
68   - .channel(NioServerSocketChannel.class)
69   - .childHandler(new ChannelInitializer<>() {
70   -
71   - @Override
72   - protected void initChannel(Channel channel) {
73   - channel.pipeline().addLast(new HttpServerCodec());
74   - channel.pipeline().addLast(new HttpObjectAggregator(65536));
75   - // 将从 ServiceRegistry 获取的 deviceDataApi 传入处理器
76   - channel.pipeline().addLast(new HttpHandler(deviceDataApi));
77   - }
78   -
79   - });
80   -
81   - // 绑定端口并启动服务器
82   - ChannelFuture future = bootstrap.bind(PORT).sync();
83   - log.info("HTTP 服务器启动成功,端口为: {}", PORT);
84   - future.channel().closeFuture().sync();
85   - } catch (InterruptedException e) {
86   - Thread.currentThread().interrupt();
87   - log.warn("HTTP 服务启动被中断", e);
88   - } finally {
89   - bossGroup.shutdownGracefully();
90   - workerGroup.shutdownGracefully();
91   - }
92   - }
93   -
94   -}
95 0 \ 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/HttpHandler.java renamed to yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxHandler.java
... ... @@ -4,63 +4,29 @@ import cn.hutool.json.JSONObject;
4 4 import cn.hutool.json.JSONUtil;
5 5 import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
6 6 import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO;
7   -import io.netty.buffer.Unpooled;
8   -import io.netty.channel.ChannelFutureListener;
9   -import io.netty.channel.ChannelHandlerContext;
10   -import io.netty.channel.SimpleChannelInboundHandler;
11   -import io.netty.handler.codec.http.*;
12   -import io.netty.util.CharsetUtil;
  7 +import io.vertx.core.Handler;
  8 +import io.vertx.ext.web.RequestBody;
  9 +import io.vertx.ext.web.RoutingContext;
  10 +import lombok.extern.slf4j.Slf4j;
13 11  
14   -/**
15   - * 基于 Netty 的 HTTP 处理器,用于接收设备上报的数据并调用主程序的 DeviceDataApi 接口进行处理。
16   - * <p>
17   - * 1. 请求格式:JSON 格式,地址为 POST /sys/{productKey}/{deviceName}/thing/event/property/post
18   - * 2. 返回结果:JSON 格式,包含统一的 code、data、id、message、method、version 字段
19   - */
20   -public class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
  12 +@Slf4j
  13 +public class HttpVertxHandler implements Handler<RoutingContext> {
21 14  
22 15 private final DeviceDataApi deviceDataApi;
23 16  
24   - public HttpHandler(DeviceDataApi deviceDataApi) {
  17 + public HttpVertxHandler(DeviceDataApi deviceDataApi) {
25 18 this.deviceDataApi = deviceDataApi;
26 19 }
27 20  
28 21 @Override
29   - protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {
30   - // 期望的路径格式: /sys/{productKey}/{deviceName}/thing/event/property/post
31   - // 使用 "/" 拆分路径
32   - String uri = request.uri();
33   - String[] parts = uri.split("/");
  22 + public void handle(RoutingContext ctx) {
  23 + String productKey = ctx.pathParam("productKey");
  24 + String deviceName = ctx.pathParam("deviceName");
  25 + RequestBody requestBody = ctx.body();
34 26  
35   - /*
36   - 拆分结果示例:
37   - parts[0] = ""
38   - parts[1] = "sys"
39   - parts[2] = productKey
40   - parts[3] = deviceName
41   - parts[4] = "thing"
42   - parts[5] = "event"
43   - parts[6] = "property"
44   - parts[7] = "post"
45   - */
46   - boolean isCorrectPath = parts.length == 8
47   - && "sys".equals(parts[1])
48   - && "thing".equals(parts[4])
49   - && "event".equals(parts[5])
50   - && "property".equals(parts[6])
51   - && "post".equals(parts[7]);
52   - if (!isCorrectPath) {
53   - writeResponse(ctx, HttpResponseStatus.NOT_FOUND, "Not Found");
54   - return;
55   - }
56   - String productKey = parts[2];
57   - String deviceName = parts[3];
58   -
59   - // 从请求中获取原始数据,尝试解析请求数据为 JSON 对象
60   - String requestBody = request.content().toString(CharsetUtil.UTF_8);
61 27 JSONObject jsonData;
62 28 try {
63   - jsonData = JSONUtil.parseObj(requestBody);
  29 + jsonData = JSONUtil.parseObj(requestBody.asJsonObject());
64 30 } catch (Exception e) {
65 31 JSONObject res = createResponseJson(
66 32 400,
... ... @@ -68,11 +34,14 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
68 34 null,
69 35 "请求数据不是合法的 JSON 格式: " + e.getMessage(),
70 36 "thing.event.property.post",
71   - "1.0"
72   - );
73   - writeResponse(ctx, HttpResponseStatus.BAD_REQUEST, res.toString());
  37 + "1.0");
  38 + ctx.response()
  39 + .setStatusCode(400)
  40 + .putHeader("Content-Type", "application/json; charset=UTF-8")
  41 + .end(res.toString());
74 42 return;
75 43 }
  44 +
76 45 String id = jsonData.getStr("id", null);
77 46  
78 47 try {
... ... @@ -91,9 +60,11 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
91 60 id,
92 61 "success",
93 62 "thing.event.property.post",
94   - "1.0"
95   - );
96   - writeResponse(ctx, HttpResponseStatus.OK, successRes.toString());
  63 + "1.0");
  64 + ctx.response()
  65 + .setStatusCode(200)
  66 + .putHeader("Content-Type", "application/json; charset=UTF-8")
  67 + .end(successRes.toString());
97 68 } catch (Exception e) {
98 69 JSONObject errorRes = createResponseJson(
99 70 500,
... ... @@ -101,9 +72,11 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
101 72 id,
102 73 "The format of result is error!",
103 74 "thing.event.property.post",
104   - "1.0"
105   - );
106   - writeResponse(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR, errorRes.toString());
  75 + "1.0");
  76 + ctx.response()
  77 + .setStatusCode(500)
  78 + .putHeader("Content-Type", "application/json; charset=UTF-8")
  79 + .end(errorRes.toString());
107 80 }
108 81 }
109 82  
... ... @@ -118,7 +91,8 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
118 91 * @param version 返回的版本号
119 92 * @return 构造好的 JSON 对象
120 93 */
121   - private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method, String version) {
  94 + private JSONObject createResponseJson(int code, JSONObject data, String id, String message, String method,
  95 + String version) {
122 96 JSONObject res = new JSONObject();
123 97 res.set("code", code);
124 98 res.set("data", data != null ? data : new JSONObject());
... ... @@ -128,26 +102,4 @@ public class HttpHandler extends SimpleChannelInboundHandler&lt;FullHttpRequest&gt; {
128 102 res.set("version", version);
129 103 return res;
130 104 }
131   -
132   - /**
133   - * 向客户端返回 HTTP 响应的辅助方法
134   - *
135   - * @param ctx 通道上下文
136   - * @param status HTTP 响应状态码(网络层面的)
137   - * @param content 响应内容(JSON 字符串或其他文本)
138   - */
139   - private void writeResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String content) {
140   - // 设置响应头为 JSON 类型和正确的编码
141   - FullHttpResponse response = new DefaultFullHttpResponse(
142   - HttpVersion.HTTP_1_1,
143   - status,
144   - Unpooled.copiedBuffer(content, CharsetUtil.UTF_8)
145   - );
146   - response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
147   - response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
148   -
149   - // 发送响应并在发送完成后关闭连接
150   - ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
151   - }
152   -
153   -}
154 105 \ No newline at end of file
  106 +}
... ...
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.plugin;
  2 +
  3 +import cn.iocoder.yudao.module.iot.api.ServiceRegistry;
  4 +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
  5 +import io.vertx.core.Vertx;
  6 +import io.vertx.ext.web.Router;
  7 +import io.vertx.ext.web.handler.BodyHandler;
  8 +import org.pf4j.Plugin;
  9 +import org.pf4j.PluginWrapper;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +
  12 +@Slf4j
  13 +public class HttpVertxPlugin extends Plugin {
  14 +
  15 + private static final int PORT = 8092;
  16 + private Vertx vertx;
  17 + private DeviceDataApi deviceDataApi;
  18 +
  19 + public HttpVertxPlugin(PluginWrapper wrapper) {
  20 + super(wrapper);
  21 + }
  22 +
  23 + @Override
  24 + public void start() {
  25 + log.info("HttpVertxPlugin.start()");
  26 +
  27 + // 获取 DeviceDataApi 实例
  28 + deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class);
  29 + if (deviceDataApi == null) {
  30 + log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!");
  31 + return;
  32 + }
  33 +
  34 + // 初始化 Vert.x
  35 + vertx = Vertx.vertx();
  36 + Router router = Router.router(vertx);
  37 +
  38 + // 处理 Body
  39 + router.route().handler(BodyHandler.create());
  40 +
  41 + // 设置路由
  42 + router.post("/sys/:productKey/:deviceName/thing/event/property/post")
  43 + .handler(new HttpVertxHandler(deviceDataApi));
  44 +
  45 + // 启动 HTTP 服务器
  46 + vertx.createHttpServer()
  47 + .requestHandler(router)
  48 + .listen(PORT, http -> {
  49 + if (http.succeeded()) {
  50 + log.info("HTTP 服务器启动成功,端口为: {}", PORT);
  51 + } else {
  52 + log.error("HTTP 服务器启动失败", http.cause());
  53 + }
  54 + });
  55 + }
  56 +
  57 + @Override
  58 + public void stop() {
  59 + log.info("HttpVertxPlugin.stop()");
  60 + if (vertx != null) {
  61 + vertx.close(ar -> {
  62 + if (ar.succeeded()) {
  63 + log.info("Vert.x 关闭成功");
  64 + } else {
  65 + log.error("Vert.x 关闭失败", ar.cause());
  66 + }
  67 + });
  68 + }
  69 + }
  70 +}
0 71 \ No newline at end of file
... ...
yudao-server/src/main/resources/application-dev.yaml
... ... @@ -212,4 +212,9 @@ iot:
212 212 # 保持连接
213 213 keepalive: 60
214 214 # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
215   - clearSession: true
216 215 \ No newline at end of file
  216 + clearSession: true
  217 +
  218 +
  219 +# 插件配置
  220 +pf4j:
  221 + pluginsDir: ${user.home}/plugins # 插件目录
217 222 \ No newline at end of file
... ...
yudao-server/src/main/resources/application-local.yaml
... ... @@ -45,7 +45,7 @@ spring:
45 45 primary: master
46 46 datasource:
47 47 master:
48   - url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
  48 + url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
49 49 # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例
50 50 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
51 51 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
... ... @@ -53,8 +53,8 @@ spring:
53 53 # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例
54 54 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例
55 55 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例
56   - username: root
57   - password: ahh@123456
  56 + username: ruoyi-vue-pro
  57 + password: ruoyi-@h2ju02hebp
58 58 # username: sa # SQL Server 连接的示例
59 59 # password: Yudao@2024 # SQL Server 连接的示例
60 60 # username: SYSDBA # DM 连接的示例
... ... @@ -63,17 +63,25 @@ spring:
63 63 # password: Yudao@2024 # OpenGauss 连接的示例
64 64 slave: # 模拟从库,可根据自己需要修改
65 65 lazy: true # 开启懒加载,保证启动速度
66   - url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
  66 + url: jdbc:mysql://chaojiniu.top:23306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
  67 + username: ruoyi-vue-pro
  68 + password: ruoyi-@h2ju02hebp
  69 + tdengine: # IOT 数据库
  70 +# lazy: true # 开启懒加载,保证启动速度
  71 + url: jdbc:TAOS-RS://chaojiniu.top:6041/ruoyi_vue_pro
  72 + driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
67 73 username: root
68   - password: ahh@123456
  74 + password: taosdata
  75 + druid:
  76 + validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL
69 77  
70 78 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
71 79 data:
72 80 redis:
73   - host: 127.0.0.1 # 地址
  81 + host: chaojiniu.top # 地址
74 82 port: 6379 # 端口
75   - database: 0 # 数据库索引
76   -# password: dev # 密码,建议生产环境开启
  83 + database: 15 # 数据库索引
  84 + password: fsknKD7UvQYZsyf2hXXn # 密码,建议生产环境开启
77 85  
78 86 --- #################### 定时任务相关配置 ####################
79 87  
... ... @@ -175,8 +183,10 @@ logging:
175 183 cn.iocoder.yudao.module.crm.dal.mysql: debug
176 184 cn.iocoder.yudao.module.erp.dal.mysql: debug
177 185 cn.iocoder.yudao.module.iot.dal.mysql: debug
  186 + cn.iocoder.yudao.module.iot.dal.tdengine: DEBUG
178 187 cn.iocoder.yudao.module.ai.dal.mysql: debug
179 188 org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示
  189 + com.taosdata: DEBUG # TDengine 的日志级别
180 190  
181 191 debug: false
182 192  
... ... @@ -259,7 +269,7 @@ justauth:
259 269 iot:
260 270 emq:
261 271 # 账号
262   - username: anhaohao
  272 + username: haohao
263 273 # 密码
264 274 password: ahh@123456
265 275 # 主机地址
... ... @@ -271,4 +281,18 @@ iot:
271 281 # 保持连接
272 282 keepalive: 60
273 283 # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
274   - clearSession: true
275 284 \ No newline at end of file
  285 + clearSession: true
  286 +
  287 +# MQTT-RPC 配置
  288 +mqtt:
  289 + broker: tcp://chaojiniu.top:1883
  290 + username: haohao
  291 + password: ahh@123456
  292 + clientId: mqtt-rpc-server-${random.int}
  293 + requestTopic: rpc/request
  294 + responseTopicPrefix: rpc/response/
  295 +
  296 +
  297 +# 插件配置
  298 +pf4j:
  299 + pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录
276 300 \ No newline at end of file
... ...