From 698cec92bdf4f5c416874fd89fb6cbc50b8d9c14 Mon Sep 17 00:00:00 2001 From: 安浩浩 <1036606149@qq.com> Date: Fri, 24 Jan 2025 23:17:26 +0800 Subject: [PATCH] 【功能完善】IoT: 重命名插件模块,重构插件管理逻辑,优化代码结构,更新配置文件以支持新插件架构。 --- yudao-module-iot/pom.xml | 2 +- yudao-module-iot/yudao-module-iot-plugin/pom.xml | 26 -------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties | 6 ------ yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml | 164 -------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml | 31 ------------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java | 42 ------------------------------------------ yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml | 43 ------------------------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties | 6 ------ yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml | 150 ------------------------------------------------------------------------------------------------------------------------------------------------------ yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml | 24 ------------------------ yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java | 26 -------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java | 81 --------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java | 69 --------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java | 105 --------------------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml | 3 --- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/plugin.properties | 7 ------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml | 155 ----------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml | 31 ------------------------------- yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java | 36 ------------------------------------ yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java | 231 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugins/pom.xml | 27 +++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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 | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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 | 29 +++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java | 1 + yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties | 6 ++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml | 31 +++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java | 42 ++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties | 6 ++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml | 24 ++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java | 16 ++++++++++++++++ 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 | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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 | 16 ++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml | 7 +++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/plugin.properties | 7 +++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml | 31 +++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java | 36 ++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 42 files changed, 1267 insertions(+), 1237 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/plugin.properties delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml create mode 100644 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 create mode 100644 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 create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml create mode 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 create mode 100644 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 create mode 100644 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 create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/plugin.properties create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java diff --git a/yudao-module-iot/pom.xml b/yudao-module-iot/pom.xml index d9002ab..0422c5d 100644 --- a/yudao-module-iot/pom.xml +++ b/yudao-module-iot/pom.xml @@ -10,7 +10,7 @@ yudao-module-iot-api yudao-module-iot-biz - yudao-module-iot-plugin + yudao-module-iot-plugins 4.0.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/pom.xml deleted file mode 100644 index 949ff13..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/pom.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - yudao-module-iot - cn.iocoder.boot - ${revision} - - - yudao-module-iot-plugin-http - yudao-module-iot-plugin-mqtt - yudao-module-iot-plugin-emqx - - - 4.0.0 - - yudao-module-iot-plugin - pom - - ${project.artifactId} - - 物联网 插件 模块 - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties deleted file mode 100644 index 7f565b7..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/plugin.properties +++ /dev/null @@ -1,6 +0,0 @@ -plugin.id=plugin-emqx -plugin.class=cn.iocoder.yudao.module.iot.plugin.EmqxPlugin -plugin.version=1.0.0 -plugin.provider=ahh -plugin.dependencies= -plugin.description=plugin-emqx-1.0.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml deleted file mode 100644 index 266e45f..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/pom.xml +++ /dev/null @@ -1,164 +0,0 @@ - - - - yudao-module-iot-plugin - cn.iocoder.boot - ${revision} - - 4.0.0 - jar - - yudao-module-iot-plugin-emqx - - ${project.artifactId} - - 物联网 插件模块 - emqx 插件 - - - - - emqx-plugin - cn.iocoder.yudao.module.iot.plugin.EmqxPlugin - 0.0.1 - ahh - emqx-plugin-0.0.1 - - - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - 1.6 - - - unzip jar file - package - - - - - - - run - - - - - - - maven-assembly-plugin - 2.3 - - - - src/main/assembly/assembly.xml - - - false - - - - make-assembly - package - - attached - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - ${plugin.id} - ${plugin.class} - ${plugin.version} - ${plugin.provider} - ${plugin.description} - ${plugin.dependencies} - - - - - - - maven-deploy-plugin - - true - - - - - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.pf4j - pf4j-spring - provided - - - - cn.iocoder.boot - yudao-module-iot-api - ${revision} - - - org.projectlombok - lombok - ${lombok.version} - provided - - - - io.vertx - vertx-core - - - - io.vertx - vertx-web - - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml deleted file mode 100644 index daec9e4..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml +++ /dev/null @@ -1,31 +0,0 @@ - - plugin - - zip - - false - - - false - runtime - lib - - *:jar:* - - - - - - - target/plugin-classes - classes - - - diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java deleted file mode 100644 index 27b9042..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java +++ /dev/null @@ -1,42 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - -import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.Plugin; -import org.pf4j.PluginWrapper; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -@Slf4j -public class EmqxPlugin extends Plugin { - - private ExecutorService executorService; - - public EmqxPlugin(PluginWrapper wrapper) { - super(wrapper); - this.executorService = Executors.newSingleThreadExecutor(); - } - - @Override - public void start() { - log.info("EmqxPlugin.start()"); - - if (executorService.isShutdown() || executorService.isTerminated()) { - executorService = Executors.newSingleThreadExecutor(); - } - - DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); - if (deviceDataApi == null) { - log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); - return; - } - - } - - @Override - public void stop() { - log.info("EmqxPlugin.stop()"); - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml deleted file mode 100644 index 260ef9c..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/dependency-reduced-pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - yudao-module-iot-plugin - cn.iocoder.boot - 2.2.0-snapshot - - 4.0.0 - yudao-module-iot-plugin-http - ${project.artifactId} - 1.0.0 - 物联网 插件模块 - http 插件 - - - - maven-shade-plugin - 3.2.4 - - - package - - shade - - - - - com.example.HttpPluginSpringbootApplication - - - - - - - - - - ${project.artifactId} - ${project.artifactId}-${project.version} - cn.iocoder.yudao.module.iot.config.HttpVertxPlugin - ${project.version} - yudao - - diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties deleted file mode 100644 index 49aef5b..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/plugin.properties +++ /dev/null @@ -1,6 +0,0 @@ -plugin.id=yudao-module-iot-plugin-http -plugin.class=cn.iocoder.yudao.module.iot.config.HttpVertxPlugin -plugin.version=1.0.0 -plugin.provider=yudao -plugin.dependencies= -plugin.description=yudao-module-iot-plugin-http-1.0.0 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml deleted file mode 100644 index cfea789..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/pom.xml +++ /dev/null @@ -1,150 +0,0 @@ - - - - yudao-module-iot-plugin - cn.iocoder.boot - ${revision} - - 4.0.0 - jar - - yudao-module-iot-plugin-http - 1.0.0 - - ${project.artifactId} - - 物联网 插件模块 - http 插件 - - - - - ${project.artifactId} - cn.iocoder.yudao.module.iot.config.HttpVertxPlugin - ${project.version} - yudao - ${project.artifactId}-${project.version} - - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - 1.6 - - - unzip jar file - package - - - - - - - run - - - - - - - maven-assembly-plugin - 2.3 - - - - src/main/assembly/assembly.xml - - - false - - - - make-assembly - package - - attached - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - ${plugin.id} - ${plugin.class} - ${plugin.version} - ${plugin.provider} - ${plugin.description} - ${plugin.dependencies} - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring.boot.version} - - - - repackage - - - -standalone - - - - - - - maven-deploy-plugin - - true - - - - - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.pf4j - pf4j-spring - - - - cn.iocoder.boot - yudao-module-iot-api - ${revision} - - - org.projectlombok - lombok - - - - io.vertx - vertx-web - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml deleted file mode 100644 index 9b79e61..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml +++ /dev/null @@ -1,24 +0,0 @@ - - plugin - - zip - - false - - - false - runtime - lib - - *:jar:* - - - - - - - target/plugin-classes - classes - - - diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java deleted file mode 100644 index 7b29367..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.iot; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -// TODO @haohao:建议包名:cn.iocoder.yudao.module.iot.plugin.${pluginName},例如说 http。然后子包如下: -// config:方配置类,以及 HttpVertxPlugin 初始化 -// service:放 HttpVertxHandler 逻辑; -@SpringBootApplication -public class HttpPluginSpringbootApplication { - - public static void main(String[] args) { -// SpringApplication.run(HttpPluginSpringbootApplication.class, args); - SpringApplication application = new SpringApplication(HttpPluginSpringbootApplication.class); - application.setWebApplicationType(WebApplicationType.NONE); - application.run(args); - } - -} - -// TODO @haohao:如下是 sdk 的包:cn.iocoder.yudao.module.iot.plugin.sdk -// 1. api 包:实现 DeviceDataApi 接口,通过 resttemplate 调用 -// 2. config 包:初始化 DeviceDataApi 等等 - -// 3. 其中 resttemplate 调用的后端地址,通过每个服务的 application.yaml 进行注入。 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java deleted file mode 100644 index d77f990..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/HttpVertxPlugin.java +++ /dev/null @@ -1,81 +0,0 @@ -package cn.iocoder.yudao.module.iot.config; - -import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.service.HttpVertxHandler; -import io.vertx.core.Vertx; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.handler.BodyHandler; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginWrapper; -import org.pf4j.spring.SpringPlugin; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -@Slf4j -public class HttpVertxPlugin extends SpringPlugin { - - private static final int PORT = 8092; - private Vertx vertx; - - public HttpVertxPlugin(PluginWrapper wrapper) { - super(wrapper); - } - - @Override - public void start() { - log.info("HttpVertxPlugin.start()"); - - // 获取 DeviceDataApi 实例 - DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); - if (deviceDataApi == null) { - log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); - return; - } - - // 初始化 Vert.x - vertx = Vertx.vertx(); - Router router = Router.router(vertx); - - // 处理 Body - router.route().handler(BodyHandler.create()); - - // 设置路由 - router.post("/sys/:productKey/:deviceName/thing/event/property/post") - .handler(new HttpVertxHandler(deviceDataApi)); - - // 启动 HTTP 服务器 - vertx.createHttpServer() - .requestHandler(router) - .listen(PORT, http -> { - if (http.succeeded()) { - log.info("HTTP 服务器启动成功,端口为: {}", PORT); - } else { - log.error("HTTP 服务器启动失败", http.cause()); - } - }); - } - - @Override - public void stop() { - log.info("HttpVertxPlugin.stop()"); - if (vertx != null) { - vertx.close(ar -> { - if (ar.succeeded()) { - log.info("Vert.x 关闭成功"); - } else { - log.error("Vert.x 关闭失败", ar.cause()); - } - }); - } - } - - @Override - protected ApplicationContext createApplicationContext() { - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); - applicationContext.setClassLoader(getWrapper().getPluginClassLoader()); - applicationContext.refresh(); - - return applicationContext; - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java deleted file mode 100644 index 18f6b28..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.iocoder.yudao.module.iot.config; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -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 org.pf4j.DefaultPluginManager; -import org.pf4j.PluginWrapper; -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; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -// TODO 芋艿:临时实现; -@Configuration -public class TestConfiguration { - -// @Resource -// private RestTemplate restTemplate; - - // TODO 芋艿:这里,后续看看怎么创建好点 - @Bean - public RestTemplate restTemplate() { - return new RestTemplateBuilder().build(); - } - - @Bean - public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { - return new DeviceDataApi() { - - @Override - public CommonResult updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { - // TODO haohao:待实现 - return null; - } - - @Override - public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { - // TODO haohao:待实现 - return null; - } - - @Override - public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { - // TODO haohao:待完整实现 - String url = "http://127.0.0.1:48080/rpc-api/iot/device-data/report-property"; - try { - restTemplate.postForObject(url, reportReqDTO, CommonResult.class); - return success(true); - } catch (Exception e) { - e.printStackTrace(); - return CommonResult.error(400, "error"); - } - } - - }; - } - - // TODO @haohao:可能要看下,有没更好的方式 - @Bean(initMethod = "start") - public HttpVertxPlugin HttpVertxPlugin() { - PluginWrapper pluginWrapper = new PluginWrapper(new DefaultPluginManager(), null, null, null); - return new HttpVertxPlugin(pluginWrapper); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java deleted file mode 100644 index b92b086..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/service/HttpVertxHandler.java +++ /dev/null @@ -1,105 +0,0 @@ -package cn.iocoder.yudao.module.iot.service; - -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; -import io.vertx.core.Handler; -import io.vertx.ext.web.RequestBody; -import io.vertx.ext.web.RoutingContext; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class HttpVertxHandler implements Handler { - - private final DeviceDataApi deviceDataApi; - - public HttpVertxHandler(DeviceDataApi deviceDataApi) { - this.deviceDataApi = deviceDataApi; - } - - @Override - public void handle(RoutingContext ctx) { - String productKey = ctx.pathParam("productKey"); - String deviceName = ctx.pathParam("deviceName"); - RequestBody requestBody = ctx.body(); - - JSONObject jsonData; - try { - jsonData = JSONUtil.parseObj(requestBody.asJsonObject()); - } catch (Exception e) { - JSONObject res = createResponseJson( - 400, - new JSONObject(), - null, - "请求数据不是合法的 JSON 格式: " + e.getMessage(), - "thing.event.property.post", - "1.0"); - ctx.response() - .setStatusCode(400) - .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(res.toString()); - return; - } - - String id = jsonData.getStr("id", null); - - try { - // 调用主程序的接口保存数据 - IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder() - .productKey(productKey) - .deviceName(deviceName) - .params(jsonData) // TODO 芋艿:这块要优化 - .build(); - deviceDataApi.reportDevicePropertyData(createDTO); - - // 构造成功响应内容 - JSONObject successRes = createResponseJson( - 200, - new JSONObject(), - id, - "success", - "thing.event.property.post", - "1.0"); - ctx.response() - .setStatusCode(200) - .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(successRes.toString()); - } catch (Exception e) { - JSONObject errorRes = createResponseJson( - 500, - new JSONObject(), - id, - "The format of result is error!", - "thing.event.property.post", - "1.0"); - ctx.response() - .setStatusCode(500) - .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(errorRes.toString()); - } - } - - /** - * 创建标准化的响应 JSON 对象 - * - * @param code 响应状态码(业务层面的) - * @param data 返回的数据对象(JSON) - * @param id 请求的 id(可选) - * @param message 返回的提示信息 - * @param method 返回的 method 标识 - * @param version 返回的版本号 - * @return 构造好的 JSON 对象 - */ - 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()); - res.set("id", id); - res.set("message", message); - res.set("method", method); - res.set("version", version); - return res; - } -} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml deleted file mode 100644 index c5a1ee8..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-http/src/main/resources/application.yml +++ /dev/null @@ -1,3 +0,0 @@ -spring: - application: - name: yudao-module-iot-plugin-http diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/plugin.properties deleted file mode 100644 index 939e0f6..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/plugin.properties +++ /dev/null @@ -1,7 +0,0 @@ -plugin.id=mqtt-plugin -plugin.description=Vert.x MQTT plugin -plugin.class=cn.iocoder.yudao.module.iot.plugin.MqttPlugin -plugin.version=1.0.0 -plugin.requires= -plugin.provider=ahh -plugin.license=Apache-2.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml deleted file mode 100644 index 7e4689b..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/pom.xml +++ /dev/null @@ -1,155 +0,0 @@ - - - - yudao-module-iot-plugin - cn.iocoder.boot - ${revision} - - 4.0.0 - jar - - yudao-module-iot-plugin-mqtt - - ${project.artifactId} - - 物联网 插件模块 - mqtt 插件 - - - - - mqtt-plugin - cn.iocoder.yudao.module.iot.plugin.MqttPlugin - 0.0.1 - ahh - mqtt-plugin-0.0.1 - - - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - 1.6 - - - unzip jar file - package - - - - - - - run - - - - - - - maven-assembly-plugin - 2.3 - - - - src/main/assembly/assembly.xml - - - false - - - - make-assembly - package - - attached - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - ${plugin.id} - ${plugin.class} - ${plugin.version} - ${plugin.provider} - ${plugin.description} - ${plugin.dependencies} - - - - - - - maven-deploy-plugin - - true - - - - - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.pf4j - pf4j-spring - provided - - - - cn.iocoder.boot - yudao-module-iot-api - ${revision} - - - org.projectlombok - lombok - ${lombok.version} - provided - - - - io.vertx - vertx-mqtt - 4.5.11 - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml deleted file mode 100644 index daec9e4..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml +++ /dev/null @@ -1,31 +0,0 @@ - - plugin - - zip - - false - - - false - runtime - lib - - *:jar:* - - - - - - - target/plugin-classes - classes - - - diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java deleted file mode 100644 index 54ff31f..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - -import lombok.extern.slf4j.Slf4j; -import org.pf4j.Plugin; -import org.pf4j.PluginWrapper; - -@Slf4j -public class MqttPlugin extends Plugin { - - private MqttServerExtension mqttServerExtension; - - public MqttPlugin(PluginWrapper wrapper) { - super(wrapper); - } - - @Override - public void start() { - log.info("MQTT Plugin started."); - mqttServerExtension = new MqttServerExtension(); - mqttServerExtension.startMqttServer(); - } - - @Override - public void stop() { - log.info("MQTT Plugin stopped."); - if (mqttServerExtension != null) { - mqttServerExtension.stopMqttServer().onComplete(ar -> { - if (ar.succeeded()) { - log.info("Stopped MQTT Server successfully"); - } else { - log.error("Failed to stop MQTT Server: {}", ar.cause().getMessage()); - } - }); - } - } -} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java deleted file mode 100644 index 868d238..0000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java +++ /dev/null @@ -1,231 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin; - -import io.netty.handler.codec.mqtt.MqttProperties; -import io.netty.handler.codec.mqtt.MqttQoS; -import io.vertx.core.Future; -import io.vertx.core.Vertx; -import io.vertx.core.buffer.Buffer; -import io.vertx.mqtt.MqttEndpoint; -import io.vertx.mqtt.MqttServer; -import io.vertx.mqtt.MqttServerOptions; -import io.vertx.mqtt.MqttTopicSubscription; -import io.vertx.mqtt.messages.MqttDisconnectMessage; -import io.vertx.mqtt.messages.MqttPublishMessage; -import io.vertx.mqtt.messages.MqttSubscribeMessage; -import io.vertx.mqtt.messages.MqttUnsubscribeMessage; -import io.vertx.mqtt.messages.codes.MqttSubAckReasonCode; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.Extension; - -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; - -/** - * 根据官方示例,整合常见 MQTT 功能到 PF4J 的 Extension 类中 - */ -@Slf4j -@Extension -public class MqttServerExtension { - - private Vertx vertx; - private MqttServer mqttServer; - - /** - * 启动 MQTT 服务端 - * 可根据需要决定是否启用 SSL/TLS、WebSocket、多实例部署等 - */ - public void startMqttServer() { - // 初始化 Vert.x - vertx = Vertx.vertx(); - - // ========== 如果需要 SSL/TLS,请参考下面注释,启用注释并替换端口、证书路径等 ========== - // MqttServerOptions options = new MqttServerOptions() - // .setPort(8883) - // .setKeyCertOptions(new PemKeyCertOptions() - // .setKeyPath("./src/test/resources/tls/server-key.pem") - // .setCertPath("./src/test/resources/tls/server-cert.pem")) - // .setSsl(true); - - // ========== 如果需要 WebSocket,请设置 setUseWebSocket(true) ========== - // options.setUseWebSocket(true); - - // ========== 默认不启用 SSL 的示例 ========== - MqttServerOptions options = new MqttServerOptions() - .setPort(1883) - .setHost("0.0.0.0") - .setUseWebSocket(false); // 如果需要 WebSocket,请改为 true - - mqttServer = MqttServer.create(vertx, options); - - // 指定 endpointHandler,处理客户端连接等 - mqttServer.endpointHandler(endpoint -> { - handleClientConnect(endpoint); - handleDisconnect(endpoint); - handleSubscribe(endpoint); - handleUnsubscribe(endpoint); - handlePublish(endpoint); - handlePing(endpoint); - }); - - // 启动监听 - mqttServer.listen(ar -> { - if (ar.succeeded()) { - log.info("MQTT server is listening on port {}", mqttServer.actualPort()); - } else { - log.error("Error on starting the server", ar.cause()); - } - }); - } - - /** - * 优雅关闭 MQTT 服务端 - */ - public Future stopMqttServer() { - if (mqttServer != null) { - return mqttServer.close().onComplete(ar -> { - if (ar.succeeded()) { - log.info("MQTT server closed."); - if (vertx != null) { - vertx.close(); - log.info("Vert.x instance closed."); - } - } else { - log.error("Failed to close MQTT server: {}", ar.cause().getMessage()); - } - }); - } - return Future.succeededFuture(); - } - - // ==================== 以下为官方示例中常见事件的处理封装 ==================== - - /** - * 处理客户端连接 (CONNECT) - */ - private void handleClientConnect(MqttEndpoint endpoint) { - // 打印 CONNECT 的主要信息 - log.info("MQTT client [{}] request to connect, clean session = {}", - endpoint.clientIdentifier(), endpoint.isCleanSession()); - - if (endpoint.auth() != null) { - log.info("[username = {}, password = {}]", endpoint.auth().getUsername(), endpoint.auth().getPassword()); - } - log.info("[properties = {}]", endpoint.connectProperties()); - - if (endpoint.will() != null) { - log.info("[will topic = {}, msg = {}, QoS = {}, isRetain = {}]", - endpoint.will().getWillTopic(), - new String(endpoint.will().getWillMessageBytes()), - endpoint.will().getWillQos(), - endpoint.will().isWillRetain()); - } - - log.info("[keep alive timeout = {}]", endpoint.keepAliveTimeSeconds()); - - // 接受远程客户端的连接 - endpoint.accept(false); - } - - /** - * 处理客户端主动断开 (DISCONNECT) - */ - private void handleDisconnect(MqttEndpoint endpoint) { - endpoint.disconnectMessageHandler((MqttDisconnectMessage disconnectMessage) -> { - log.info("Received disconnect from client [{}], reason code = {}", - endpoint.clientIdentifier(), disconnectMessage.code()); - }); - } - - /** - * 处理客户端订阅 (SUBSCRIBE) - */ - private void handleSubscribe(MqttEndpoint endpoint) { - endpoint.subscribeHandler((MqttSubscribeMessage subscribe) -> { - List reasonCodes = new ArrayList<>(); - for (MqttTopicSubscription s : subscribe.topicSubscriptions()) { - log.info("Subscription for {} with QoS {}", s.topicName(), s.qualityOfService()); - // 将客户端请求的 QoS 转换为返回给客户端的 reason code(可能是错误码或实际 granted QoS) - reasonCodes.add(MqttSubAckReasonCode.qosGranted(s.qualityOfService())); - } - // 回复 SUBACK,MQTT 5.0 时可指定 reasonCodes、properties - endpoint.subscribeAcknowledge(subscribe.messageId(), reasonCodes, MqttProperties.NO_PROPERTIES); - }); - } - - /** - * 处理客户端取消订阅 (UNSUBSCRIBE) - */ - private void handleUnsubscribe(MqttEndpoint endpoint) { - endpoint.unsubscribeHandler((MqttUnsubscribeMessage unsubscribe) -> { - for (String topic : unsubscribe.topics()) { - log.info("Unsubscription for {}", topic); - } - // 回复 UNSUBACK,MQTT 5.0 时可指定 reasonCodes、properties - endpoint.unsubscribeAcknowledge(unsubscribe.messageId()); - }); - } - - /** - * 处理客户端发布的消息 (PUBLISH) - */ - private void handlePublish(MqttEndpoint endpoint) { - // 接收 PUBLISH 消息 - endpoint.publishHandler((MqttPublishMessage message) -> { - String payload = message.payload().toString(Charset.defaultCharset()); - log.info("Received message [{}] on topic [{}] with QoS [{}]", - payload, message.topicName(), message.qosLevel()); - - // 根据不同 QoS,回复客户端 - if (message.qosLevel() == MqttQoS.AT_LEAST_ONCE) { - endpoint.publishAcknowledge(message.messageId()); - } else if (message.qosLevel() == MqttQoS.EXACTLY_ONCE) { - endpoint.publishReceived(message.messageId()); - } - }); - - // 如果 QoS = 2,需要处理 PUBREL - endpoint.publishReleaseHandler(messageId -> { - endpoint.publishComplete(messageId); - }); - } - - /** - * 处理客户端 PINGREQ - */ - private void handlePing(MqttEndpoint endpoint) { - endpoint.pingHandler(v -> { - // 这里仅做日志, PINGRESP 已自动发送 - log.info("Ping received from client [{}]", endpoint.clientIdentifier()); - }); - } - - // ==================== 如果需要服务端向客户端发布消息,可用以下示例 ==================== - - /** - * 服务端主动向已连接的某个 endpoint 发布消息的示例 - * 如果使用 MQTT 5.0,可以传递更多消息属性 - */ - public void publishToClient(MqttEndpoint endpoint, String topic, String content) { - endpoint.publish(topic, - Buffer.buffer(content), - MqttQoS.AT_LEAST_ONCE, // QoS 自行选择 - false, - false); - - // 处理 QoS 1 和 QoS 2 的 ACK - endpoint.publishAcknowledgeHandler(messageId -> { - log.info("Received PUBACK from client [{}] for messageId = {}", endpoint.clientIdentifier(), messageId); - }).publishReceivedHandler(messageId -> { - endpoint.publishRelease(messageId); - }).publishCompletionHandler(messageId -> { - log.info("Received PUBCOMP from client [{}] for messageId = {}", endpoint.clientIdentifier(), messageId); - }); - } - - // ==================== 如果需要多实例部署,用于多核扩展,可参考以下思路 ==================== - // 例如,在宿主应用或插件中循环启动多个 MqttServerExtension 实例,或使用 Vert.x 的 deployVerticle: - // DeploymentOptions options = new DeploymentOptions().setInstances(10); - // vertx.deployVerticle(() -> new MyMqttVerticle(), options); - -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/pom.xml new file mode 100644 index 0000000..d332925 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/pom.xml @@ -0,0 +1,27 @@ + + + + yudao-module-iot + cn.iocoder.boot + ${revision} + + + yudao-module-iot-plugin-common + yudao-module-iot-plugin-http + yudao-module-iot-plugin-mqtt + yudao-module-iot-plugin-emqx + + + 4.0.0 + + yudao-module-iot-plugins + pom + + ${project.artifactId} + + 物联网 插件 模块 + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml new file mode 100644 index 0000000..568f862 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/pom.xml @@ -0,0 +1,55 @@ + + + + yudao-module-iot-plugins + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-module-iot-plugin-common + jar + + ${project.artifactId} + + 物联网 插件 模块 - 通用功能 + + + + + cn.iocoder.boot + yudao-common + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.pf4j + pf4j-spring + + + org.slf4j + slf4j-log4j12 + + + + + + org.projectlombok + lombok + + + + diff --git a/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 b/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 new file mode 100644 index 0000000..183c76e --- /dev/null +++ b/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 @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.iot.plugin.common.api; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +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.extern.slf4j.Slf4j; +import org.springframework.web.client.RestTemplate; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Slf4j +public class DeviceDataApiClient implements DeviceDataApi { + + private final RestTemplate restTemplate; + private final String deviceDataUrl; + + // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 + public DeviceDataApiClient(RestTemplate restTemplate, String deviceDataUrl) { + this.restTemplate = restTemplate; + this.deviceDataUrl = deviceDataUrl; + } + + @Override + public CommonResult updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) { + // 示例:如果对应的远程地址是 /rpc-api/iot/device-data/update-status + String url = deviceDataUrl + "/rpc-api/iot/device-data/update-status"; + return doPost(url, updateReqDTO, "updateDeviceStatus"); + } + + @Override + public CommonResult reportDeviceEventData(IotDeviceEventReportReqDTO reportReqDTO) { + // 示例:如果对应的远程地址是 /rpc-api/iot/device-data/report-event + String url = deviceDataUrl + "/rpc-api/iot/device-data/report-event"; + return doPost(url, reportReqDTO, "reportDeviceEventData"); + } + + @Override + public CommonResult reportDevicePropertyData(IotDevicePropertyReportReqDTO reportReqDTO) { + // 示例:如果对应的远程地址是 /rpc-api/iot/device-data/report-property + String url = deviceDataUrl + "/rpc-api/iot/device-data/report-property"; + return doPost(url, reportReqDTO, "reportDevicePropertyData"); + } + + /** + * 将与远程服务交互的通用逻辑抽取成一个私有方法 + */ + private CommonResult doPost(String url, T requestBody, String actionName) { + log.info("[{}] Sending request to URL: {}", actionName, url); + try { + // 这里指定返回类型为 CommonResult,根据后台服务返回的实际结构做调整 + restTemplate.postForObject(url, requestBody, CommonResult.class); + return success(true); + } catch (Exception e) { + log.error("[{}] Error sending request to URL: {}", actionName, url, e); + return CommonResult.error(400, "Request error: " + e.getMessage()); + } + } +} diff --git a/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 b/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 new file mode 100644 index 0000000..9473033 --- /dev/null +++ b/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 @@ -0,0 +1,29 @@ +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; + +@Configuration +public class DeviceDataApiInitializer { + + @Value("${iot.device-data.url}") + private String deviceDataUrl; + + @Bean + public RestTemplate restTemplate() { + // 如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 + return new RestTemplateBuilder().build(); + } + + @Bean + public DeviceDataApi deviceDataApi(RestTemplate restTemplate) { + // 返回我们自定义的 Client 实例 + return new DeviceDataApiClient(restTemplate, deviceDataUrl); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java new file mode 100644 index 0000000..f9eae49 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.iot.plugin.common; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties new file mode 100644 index 0000000..7f565b7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/plugin.properties @@ -0,0 +1,6 @@ +plugin.id=plugin-emqx +plugin.class=cn.iocoder.yudao.module.iot.plugin.EmqxPlugin +plugin.version=1.0.0 +plugin.provider=ahh +plugin.dependencies= +plugin.description=plugin-emqx-1.0.0 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml new file mode 100644 index 0000000..cd89743 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/pom.xml @@ -0,0 +1,164 @@ + + + + yudao-module-iot-plugins + cn.iocoder.boot + ${revision} + + 4.0.0 + jar + + yudao-module-iot-plugin-emqx + + ${project.artifactId} + + 物联网 插件模块 - emqx 插件 + + + + + emqx-plugin + cn.iocoder.yudao.module.iot.plugin.EmqxPlugin + 0.0.1 + ahh + emqx-plugin-0.0.1 + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.6 + + + unzip jar file + package + + + + + + + run + + + + + + + maven-assembly-plugin + 2.3 + + + + src/main/assembly/assembly.xml + + + false + + + + make-assembly + package + + attached + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.description} + ${plugin.dependencies} + + + + + + + maven-deploy-plugin + + true + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.pf4j + pf4j-spring + provided + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + io.vertx + vertx-core + + + + io.vertx + vertx-web + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml new file mode 100644 index 0000000..daec9e4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/assembly/assembly.xml @@ -0,0 +1,31 @@ + + plugin + + zip + + false + + + false + runtime + lib + + *:jar:* + + + + + + + target/plugin-classes + classes + + + diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java new file mode 100644 index 0000000..27b9042 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-emqx/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Slf4j +public class EmqxPlugin extends Plugin { + + private ExecutorService executorService; + + public EmqxPlugin(PluginWrapper wrapper) { + super(wrapper); + this.executorService = Executors.newSingleThreadExecutor(); + } + + @Override + public void start() { + log.info("EmqxPlugin.start()"); + + if (executorService.isShutdown() || executorService.isTerminated()) { + executorService = Executors.newSingleThreadExecutor(); + } + + DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); + if (deviceDataApi == null) { + log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); + return; + } + + } + + @Override + public void stop() { + log.info("EmqxPlugin.stop()"); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties new file mode 100644 index 0000000..bcdce07 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties @@ -0,0 +1,6 @@ +plugin.id=yudao-module-iot-plugin-http +plugin.class=cn.iocoder.yudao.module.iot.plugin.http.config.HttpVertxPlugin +plugin.version=1.0.0 +plugin.provider=yudao +plugin.dependencies= +plugin.description=yudao-module-iot-plugin-http-1.0.0 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml new file mode 100644 index 0000000..15adef3 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml @@ -0,0 +1,136 @@ + + + + yudao-module-iot-plugins + cn.iocoder.boot + ${revision} + + 4.0.0 + jar + + yudao-module-iot-plugin-http + 1.0.0 + + ${project.artifactId} + + 物联网 插件模块 - http 插件 + + + + + ${project.artifactId} + cn.iocoder.yudao.module.iot.plugin.http.config.HttpVertxPlugin + ${project.version} + yudao + ${project.artifactId}-${project.version} + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.6 + + + unzip jar file + package + + + + + + + run + + + + + + + maven-assembly-plugin + 2.3 + + + + src/main/assembly/assembly.xml + + + false + + + + make-assembly + package + + attached + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.description} + ${plugin.dependencies} + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + -standalone + + + + + + + maven-deploy-plugin + + true + + + + + + + + + cn.iocoder.boot + yudao-module-iot-plugin-common + ${revision} + + + + io.vertx + vertx-web + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml new file mode 100644 index 0000000..9b79e61 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/assembly/assembly.xml @@ -0,0 +1,24 @@ + + plugin + + zip + + false + + + false + runtime + lib + + *:jar:* + + + + + + + target/plugin-classes + classes + + + diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java new file mode 100644 index 0000000..74c5651 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.plugin.http; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication(scanBasePackages = "cn.iocoder.yudao.module.iot.plugin") +public class HttpPluginSpringbootApplication { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(HttpPluginSpringbootApplication.class); + application.setWebApplicationType(WebApplicationType.NONE); + application.run(args); + } + +} \ No newline at end of file diff --git a/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 b/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 new file mode 100644 index 0000000..e6145b9 --- /dev/null +++ b/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 @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.iot.plugin.http.config; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.plugin.http.service.HttpVertxHandler; +import io.vertx.core.Vertx; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.handler.BodyHandler; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.PluginWrapper; +import org.pf4j.spring.SpringPlugin; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +@Slf4j +public class HttpVertxPlugin extends SpringPlugin { + + private static final int PORT = 8092; + private Vertx vertx; + + public HttpVertxPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + log.info("HttpVertxPlugin.start()"); + + // 获取 DeviceDataApi 实例 + DeviceDataApi deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); + if (deviceDataApi == null) { + log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); + return; + } + + // 初始化 Vert.x + vertx = Vertx.vertx(); + Router router = Router.router(vertx); + + // 处理 Body + router.route().handler(BodyHandler.create()); + + // 设置路由 + router.post("/sys/:productKey/:deviceName/thing/event/property/post") + .handler(new HttpVertxHandler(deviceDataApi)); + + // 启动 HTTP 服务器 + vertx.createHttpServer() + .requestHandler(router) + .listen(PORT, http -> { + if (http.succeeded()) { + log.info("HTTP 服务器启动成功,端口为: {}", PORT); + } else { + log.error("HTTP 服务器启动失败", http.cause()); + } + }); + } + + @Override + public void stop() { + log.info("HttpVertxPlugin.stop()"); + if (vertx != null) { + vertx.close(ar -> { + if (ar.succeeded()) { + log.info("Vert.x 关闭成功"); + } else { + log.error("Vert.x 关闭失败", ar.cause()); + } + }); + } + } + + @Override + protected ApplicationContext createApplicationContext() { + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + applicationContext.setClassLoader(getWrapper().getPluginClassLoader()); + applicationContext.refresh(); + + return applicationContext; + } +} \ No newline at end of file diff --git a/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 b/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 new file mode 100644 index 0000000..b5e977e --- /dev/null +++ b/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 @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.plugin.http.config; + +import org.pf4j.DefaultPluginManager; +import org.pf4j.PluginWrapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class HttpVertxPluginConfiguration { + + @Bean(initMethod = "start") + public HttpVertxPlugin httpVertxPlugin() { + PluginWrapper pluginWrapper = new PluginWrapper(new DefaultPluginManager(), null, null, null); + return new HttpVertxPlugin(pluginWrapper); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java new file mode 100644 index 0000000..becba2a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.iot.plugin.http.service; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO; +import io.vertx.core.Handler; +import io.vertx.ext.web.RequestBody; +import io.vertx.ext.web.RoutingContext; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class HttpVertxHandler implements Handler { + + private final DeviceDataApi deviceDataApi; + + public HttpVertxHandler(DeviceDataApi deviceDataApi) { + this.deviceDataApi = deviceDataApi; + } + + @Override + public void handle(RoutingContext ctx) { + String productKey = ctx.pathParam("productKey"); + String deviceName = ctx.pathParam("deviceName"); + RequestBody requestBody = ctx.body(); + + JSONObject jsonData; + try { + jsonData = JSONUtil.parseObj(requestBody.asJsonObject()); + } catch (Exception e) { + JSONObject res = createResponseJson( + 400, + new JSONObject(), + null, + "请求数据不是合法的 JSON 格式: " + e.getMessage(), + "thing.event.property.post", + "1.0"); + ctx.response() + .setStatusCode(400) + .putHeader("Content-Type", "application/json; charset=UTF-8") + .end(res.toString()); + return; + } + + String id = jsonData.getStr("id", null); + + try { + // 调用主程序的接口保存数据 + IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder() + .productKey(productKey) + .deviceName(deviceName) + .params(jsonData) // TODO 芋艿:这块要优化 + .build(); + deviceDataApi.reportDevicePropertyData(createDTO); + + // 构造成功响应内容 + JSONObject successRes = createResponseJson( + 200, + new JSONObject(), + id, + "success", + "thing.event.property.post", + "1.0"); + ctx.response() + .setStatusCode(200) + .putHeader("Content-Type", "application/json; charset=UTF-8") + .end(successRes.toString()); + } catch (Exception e) { + JSONObject errorRes = createResponseJson( + 500, + new JSONObject(), + id, + "The format of result is error!", + "thing.event.property.post", + "1.0"); + ctx.response() + .setStatusCode(500) + .putHeader("Content-Type", "application/json; charset=UTF-8") + .end(errorRes.toString()); + } + } + + /** + * 创建标准化的响应 JSON 对象 + * + * @param code 响应状态码(业务层面的) + * @param data 返回的数据对象(JSON) + * @param id 请求的 id(可选) + * @param message 返回的提示信息 + * @param method 返回的 method 标识 + * @param version 返回的版本号 + * @return 构造好的 JSON 对象 + */ + 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()); + res.set("id", id); + res.set("message", message); + res.set("method", method); + res.set("version", version); + return res; + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml new file mode 100644 index 0000000..e98d46e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/resources/application.yml @@ -0,0 +1,7 @@ +spring: + application: + name: yudao-module-iot-plugin-http + +iot: + device-data: + url: http://127.0.0.1:48080 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/plugin.properties b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/plugin.properties new file mode 100644 index 0000000..939e0f6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/plugin.properties @@ -0,0 +1,7 @@ +plugin.id=mqtt-plugin +plugin.description=Vert.x MQTT plugin +plugin.class=cn.iocoder.yudao.module.iot.plugin.MqttPlugin +plugin.version=1.0.0 +plugin.requires= +plugin.provider=ahh +plugin.license=Apache-2.0 diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml new file mode 100644 index 0000000..e007596 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/pom.xml @@ -0,0 +1,155 @@ + + + + yudao-module-iot-plugins + cn.iocoder.boot + ${revision} + + 4.0.0 + jar + + yudao-module-iot-plugin-mqtt + + ${project.artifactId} + + 物联网 插件模块 - mqtt 插件 + + + + + mqtt-plugin + cn.iocoder.yudao.module.iot.plugin.MqttPlugin + 0.0.1 + ahh + mqtt-plugin-0.0.1 + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.6 + + + unzip jar file + package + + + + + + + run + + + + + + + maven-assembly-plugin + 2.3 + + + + src/main/assembly/assembly.xml + + + false + + + + make-assembly + package + + attached + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.description} + ${plugin.dependencies} + + + + + + + maven-deploy-plugin + + true + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.pf4j + pf4j-spring + provided + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + io.vertx + vertx-mqtt + 4.5.11 + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml new file mode 100644 index 0000000..daec9e4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/assembly/assembly.xml @@ -0,0 +1,31 @@ + + plugin + + zip + + false + + + false + runtime + lib + + *:jar:* + + + + + + + target/plugin-classes + classes + + + diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java new file mode 100644 index 0000000..54ff31f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import lombok.extern.slf4j.Slf4j; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; + +@Slf4j +public class MqttPlugin extends Plugin { + + private MqttServerExtension mqttServerExtension; + + public MqttPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + log.info("MQTT Plugin started."); + mqttServerExtension = new MqttServerExtension(); + mqttServerExtension.startMqttServer(); + } + + @Override + public void stop() { + log.info("MQTT Plugin stopped."); + if (mqttServerExtension != null) { + mqttServerExtension.stopMqttServer().onComplete(ar -> { + if (ar.succeeded()) { + log.info("Stopped MQTT Server successfully"); + } else { + log.error("Failed to stop MQTT Server: {}", ar.cause().getMessage()); + } + }); + } + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java new file mode 100644 index 0000000..868d238 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-mqtt/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java @@ -0,0 +1,231 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import io.netty.handler.codec.mqtt.MqttProperties; +import io.netty.handler.codec.mqtt.MqttQoS; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.mqtt.MqttEndpoint; +import io.vertx.mqtt.MqttServer; +import io.vertx.mqtt.MqttServerOptions; +import io.vertx.mqtt.MqttTopicSubscription; +import io.vertx.mqtt.messages.MqttDisconnectMessage; +import io.vertx.mqtt.messages.MqttPublishMessage; +import io.vertx.mqtt.messages.MqttSubscribeMessage; +import io.vertx.mqtt.messages.MqttUnsubscribeMessage; +import io.vertx.mqtt.messages.codes.MqttSubAckReasonCode; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.Extension; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +/** + * 根据官方示例,整合常见 MQTT 功能到 PF4J 的 Extension 类中 + */ +@Slf4j +@Extension +public class MqttServerExtension { + + private Vertx vertx; + private MqttServer mqttServer; + + /** + * 启动 MQTT 服务端 + * 可根据需要决定是否启用 SSL/TLS、WebSocket、多实例部署等 + */ + public void startMqttServer() { + // 初始化 Vert.x + vertx = Vertx.vertx(); + + // ========== 如果需要 SSL/TLS,请参考下面注释,启用注释并替换端口、证书路径等 ========== + // MqttServerOptions options = new MqttServerOptions() + // .setPort(8883) + // .setKeyCertOptions(new PemKeyCertOptions() + // .setKeyPath("./src/test/resources/tls/server-key.pem") + // .setCertPath("./src/test/resources/tls/server-cert.pem")) + // .setSsl(true); + + // ========== 如果需要 WebSocket,请设置 setUseWebSocket(true) ========== + // options.setUseWebSocket(true); + + // ========== 默认不启用 SSL 的示例 ========== + MqttServerOptions options = new MqttServerOptions() + .setPort(1883) + .setHost("0.0.0.0") + .setUseWebSocket(false); // 如果需要 WebSocket,请改为 true + + mqttServer = MqttServer.create(vertx, options); + + // 指定 endpointHandler,处理客户端连接等 + mqttServer.endpointHandler(endpoint -> { + handleClientConnect(endpoint); + handleDisconnect(endpoint); + handleSubscribe(endpoint); + handleUnsubscribe(endpoint); + handlePublish(endpoint); + handlePing(endpoint); + }); + + // 启动监听 + mqttServer.listen(ar -> { + if (ar.succeeded()) { + log.info("MQTT server is listening on port {}", mqttServer.actualPort()); + } else { + log.error("Error on starting the server", ar.cause()); + } + }); + } + + /** + * 优雅关闭 MQTT 服务端 + */ + public Future stopMqttServer() { + if (mqttServer != null) { + return mqttServer.close().onComplete(ar -> { + if (ar.succeeded()) { + log.info("MQTT server closed."); + if (vertx != null) { + vertx.close(); + log.info("Vert.x instance closed."); + } + } else { + log.error("Failed to close MQTT server: {}", ar.cause().getMessage()); + } + }); + } + return Future.succeededFuture(); + } + + // ==================== 以下为官方示例中常见事件的处理封装 ==================== + + /** + * 处理客户端连接 (CONNECT) + */ + private void handleClientConnect(MqttEndpoint endpoint) { + // 打印 CONNECT 的主要信息 + log.info("MQTT client [{}] request to connect, clean session = {}", + endpoint.clientIdentifier(), endpoint.isCleanSession()); + + if (endpoint.auth() != null) { + log.info("[username = {}, password = {}]", endpoint.auth().getUsername(), endpoint.auth().getPassword()); + } + log.info("[properties = {}]", endpoint.connectProperties()); + + if (endpoint.will() != null) { + log.info("[will topic = {}, msg = {}, QoS = {}, isRetain = {}]", + endpoint.will().getWillTopic(), + new String(endpoint.will().getWillMessageBytes()), + endpoint.will().getWillQos(), + endpoint.will().isWillRetain()); + } + + log.info("[keep alive timeout = {}]", endpoint.keepAliveTimeSeconds()); + + // 接受远程客户端的连接 + endpoint.accept(false); + } + + /** + * 处理客户端主动断开 (DISCONNECT) + */ + private void handleDisconnect(MqttEndpoint endpoint) { + endpoint.disconnectMessageHandler((MqttDisconnectMessage disconnectMessage) -> { + log.info("Received disconnect from client [{}], reason code = {}", + endpoint.clientIdentifier(), disconnectMessage.code()); + }); + } + + /** + * 处理客户端订阅 (SUBSCRIBE) + */ + private void handleSubscribe(MqttEndpoint endpoint) { + endpoint.subscribeHandler((MqttSubscribeMessage subscribe) -> { + List reasonCodes = new ArrayList<>(); + for (MqttTopicSubscription s : subscribe.topicSubscriptions()) { + log.info("Subscription for {} with QoS {}", s.topicName(), s.qualityOfService()); + // 将客户端请求的 QoS 转换为返回给客户端的 reason code(可能是错误码或实际 granted QoS) + reasonCodes.add(MqttSubAckReasonCode.qosGranted(s.qualityOfService())); + } + // 回复 SUBACK,MQTT 5.0 时可指定 reasonCodes、properties + endpoint.subscribeAcknowledge(subscribe.messageId(), reasonCodes, MqttProperties.NO_PROPERTIES); + }); + } + + /** + * 处理客户端取消订阅 (UNSUBSCRIBE) + */ + private void handleUnsubscribe(MqttEndpoint endpoint) { + endpoint.unsubscribeHandler((MqttUnsubscribeMessage unsubscribe) -> { + for (String topic : unsubscribe.topics()) { + log.info("Unsubscription for {}", topic); + } + // 回复 UNSUBACK,MQTT 5.0 时可指定 reasonCodes、properties + endpoint.unsubscribeAcknowledge(unsubscribe.messageId()); + }); + } + + /** + * 处理客户端发布的消息 (PUBLISH) + */ + private void handlePublish(MqttEndpoint endpoint) { + // 接收 PUBLISH 消息 + endpoint.publishHandler((MqttPublishMessage message) -> { + String payload = message.payload().toString(Charset.defaultCharset()); + log.info("Received message [{}] on topic [{}] with QoS [{}]", + payload, message.topicName(), message.qosLevel()); + + // 根据不同 QoS,回复客户端 + if (message.qosLevel() == MqttQoS.AT_LEAST_ONCE) { + endpoint.publishAcknowledge(message.messageId()); + } else if (message.qosLevel() == MqttQoS.EXACTLY_ONCE) { + endpoint.publishReceived(message.messageId()); + } + }); + + // 如果 QoS = 2,需要处理 PUBREL + endpoint.publishReleaseHandler(messageId -> { + endpoint.publishComplete(messageId); + }); + } + + /** + * 处理客户端 PINGREQ + */ + private void handlePing(MqttEndpoint endpoint) { + endpoint.pingHandler(v -> { + // 这里仅做日志, PINGRESP 已自动发送 + log.info("Ping received from client [{}]", endpoint.clientIdentifier()); + }); + } + + // ==================== 如果需要服务端向客户端发布消息,可用以下示例 ==================== + + /** + * 服务端主动向已连接的某个 endpoint 发布消息的示例 + * 如果使用 MQTT 5.0,可以传递更多消息属性 + */ + public void publishToClient(MqttEndpoint endpoint, String topic, String content) { + endpoint.publish(topic, + Buffer.buffer(content), + MqttQoS.AT_LEAST_ONCE, // QoS 自行选择 + false, + false); + + // 处理 QoS 1 和 QoS 2 的 ACK + endpoint.publishAcknowledgeHandler(messageId -> { + log.info("Received PUBACK from client [{}] for messageId = {}", endpoint.clientIdentifier(), messageId); + }).publishReceivedHandler(messageId -> { + endpoint.publishRelease(messageId); + }).publishCompletionHandler(messageId -> { + log.info("Received PUBCOMP from client [{}] for messageId = {}", endpoint.clientIdentifier(), messageId); + }); + } + + // ==================== 如果需要多实例部署,用于多核扩展,可参考以下思路 ==================== + // 例如,在宿主应用或插件中循环启动多个 MqttServerExtension 实例,或使用 Vert.x 的 deployVerticle: + // DeploymentOptions options = new DeploymentOptions().setInstances(10); + // vertx.deployVerticle(() -> new MyMqttVerticle(), options); + +} -- libgit2 0.21.4