Commit dc1f9338f153d2351d3c473d08a582c00842745b

Authored by 安浩浩
1 parent 24a660b5

【功能完善】IoT: 添加 MQTT 插件支持,重构插件管理,新增获取运行状态插件信息接口,优化插件信息存储逻辑,移除不必要的 Spring 注解。

plugins/enabled.txt
1 http-plugin 1 http-plugin
2 -http-plugin@0.0.1  
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInfoMapper.java
@@ -4,6 +4,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -4,6 +4,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
6 import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; 6 import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO;
  7 +
  8 +import java.util.List;
  9 +
7 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
8 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.*; 11 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.*;
9 12
@@ -22,4 +25,10 @@ public interface PluginInfoMapper extends BaseMapperX<PluginInfoDO> { @@ -22,4 +25,10 @@ public interface PluginInfoMapper extends BaseMapperX<PluginInfoDO> {
22 .orderByDesc(PluginInfoDO::getId)); 25 .orderByDesc(PluginInfoDO::getId));
23 } 26 }
24 27
  28 + default List<PluginInfoDO> selectListByStatus(Integer status) {
  29 + return selectList(new LambdaQueryWrapperX<PluginInfoDO>()
  30 + .eq(PluginInfoDO::getStatus, status)
  31 + .orderByAsc(PluginInfoDO::getId));
  32 + }
  33 +
25 } 34 }
26 \ No newline at end of file 35 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java
@@ -17,7 +17,7 @@ import org.springframework.stereotype.Component; @@ -17,7 +17,7 @@ import org.springframework.stereotype.Component;
17 * @author ahh 17 * @author ahh
18 */ 18 */
19 @Slf4j 19 @Slf4j
20 -@Component 20 +//@Component
21 public class EmqxCallback implements MqttCallbackExtended { 21 public class EmqxCallback implements MqttCallbackExtended {
22 22
23 @Lazy 23 @Lazy
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java
@@ -19,7 +19,7 @@ import org.springframework.stereotype.Component; @@ -19,7 +19,7 @@ import org.springframework.stereotype.Component;
19 */ 19 */
20 @Slf4j 20 @Slf4j
21 @Data 21 @Data
22 -@Component 22 +//@Component
23 public class EmqxClient { 23 public class EmqxClient {
24 24
25 @Resource 25 @Resource
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java
@@ -12,8 +12,8 @@ import org.springframework.stereotype.Component; @@ -12,8 +12,8 @@ import org.springframework.stereotype.Component;
12 * @author ahh 12 * @author ahh
13 */ 13 */
14 @Data 14 @Data
15 -@Component  
16 -@ConfigurationProperties("iot.emq") 15 +//@Component
  16 +//@ConfigurationProperties("iot.emq")
17 public class MqttConfig { 17 public class MqttConfig {
18 18
19 /** 19 /**
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
@@ -16,7 +16,7 @@ import org.springframework.stereotype.Service; @@ -16,7 +16,7 @@ import org.springframework.stereotype.Service;
16 * @author ahh 16 * @author ahh
17 */ 17 */
18 @Slf4j 18 @Slf4j
19 -@Service 19 +//@Service
20 public class EmqxServiceImpl implements EmqxService { 20 public class EmqxServiceImpl implements EmqxService {
21 21
22 @Resource 22 @Resource
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java
@@ -13,7 +13,7 @@ import org.springframework.stereotype.Component; @@ -13,7 +13,7 @@ import org.springframework.stereotype.Component;
13 * 13 *
14 * @author ahh 14 * @author ahh
15 */ 15 */
16 -@Component 16 +//@Component
17 public class EmqxStart implements ApplicationRunner { 17 public class EmqxStart implements ApplicationRunner {
18 18
19 @Resource 19 @Resource
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java
@@ -76,4 +76,11 @@ public interface PluginInfoService { @@ -76,4 +76,11 @@ public interface PluginInfoService {
76 * @return 插件信息列表 76 * @return 插件信息列表
77 */ 77 */
78 List<PluginInfoDO> getPluginInfoList(); 78 List<PluginInfoDO> getPluginInfoList();
79 -}  
80 \ No newline at end of file 79 \ No newline at end of file
  80 +
  81 + /**
  82 + * 获得运行状态的插件信息列表
  83 + *
  84 + * @return 运行状态的插件信息列表
  85 + */
  86 + List<PluginInfoDO> getRunningPluginInfoList();
  87 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java
@@ -18,6 +18,7 @@ import org.springframework.stereotype.Service; @@ -18,6 +18,7 @@ import org.springframework.stereotype.Service;
18 import org.springframework.validation.annotation.Validated; 18 import org.springframework.validation.annotation.Validated;
19 import org.springframework.web.multipart.MultipartFile; 19 import org.springframework.web.multipart.MultipartFile;
20 20
  21 +import javax.annotation.PostConstruct;
21 import java.io.File; 22 import java.io.File;
22 import java.io.IOException; 23 import java.io.IOException;
23 import java.nio.file.*; 24 import java.nio.file.*;
@@ -186,20 +187,19 @@ public class PluginInfoServiceImpl implements PluginInfoService { @@ -186,20 +187,19 @@ public class PluginInfoServiceImpl implements PluginInfoService {
186 if (pluginWrapper == null) { 187 if (pluginWrapper == null) {
187 throw exception(PLUGIN_INSTALL_FAILED); 188 throw exception(PLUGIN_INSTALL_FAILED);
188 } 189 }
189 - String pluginInfo = pluginKeyNew + "@" + pluginWrapper.getDescriptor().getVersion();  
190 List<String> targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) 190 List<String> targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath)
191 : new ArrayList<>(); 191 : new ArrayList<>();
192 List<String> oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) 192 List<String> oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath)
193 : new ArrayList<>(); 193 : new ArrayList<>();
194 194
195 - if (!targetLines.contains(pluginInfo)) {  
196 - targetLines.add(pluginInfo); 195 + if (!targetLines.contains(pluginKeyNew)) {
  196 + targetLines.add(pluginKeyNew);
197 Files.write(targetFilePath, targetLines, StandardOpenOption.CREATE, 197 Files.write(targetFilePath, targetLines, StandardOpenOption.CREATE,
198 StandardOpenOption.TRUNCATE_EXISTING); 198 StandardOpenOption.TRUNCATE_EXISTING);
199 } 199 }
200 200
201 - if (oppositeLines.contains(pluginInfo)) {  
202 - oppositeLines.remove(pluginInfo); 201 + if (oppositeLines.contains(pluginKeyNew)) {
  202 + oppositeLines.remove(pluginKeyNew);
203 Files.write(oppositeFilePath, oppositeLines, StandardOpenOption.CREATE, 203 Files.write(oppositeFilePath, oppositeLines, StandardOpenOption.CREATE,
204 StandardOpenOption.TRUNCATE_EXISTING); 204 StandardOpenOption.TRUNCATE_EXISTING);
205 } 205 }
@@ -267,4 +267,8 @@ public class PluginInfoServiceImpl implements PluginInfoService { @@ -267,4 +267,8 @@ public class PluginInfoServiceImpl implements PluginInfoService {
267 return pluginInfoMapper.selectList(null); 267 return pluginInfoMapper.selectList(null);
268 } 268 }
269 269
  270 + @Override
  271 + public List<PluginInfoDO> getRunningPluginInfoList() {
  272 + return pluginInfoMapper.selectListByStatus(IotPluginStatusEnum.RUNNING.getStatus());
  273 + }
270 } 274 }
271 \ No newline at end of file 275 \ No newline at end of file
yudao-module-iot/yudao-module-iot-plugin/pom.xml
@@ -2,11 +2,6 @@ @@ -2,11 +2,6 @@
2 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns="http://maven.apache.org/POM/4.0.0"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 -<!-- <modelVersion>4.0.0</modelVersion>-->  
6 -<!-- <groupId>cn.iocoder.boot</groupId>-->  
7 -<!-- <artifactId>yudao-module-iot-plugin</artifactId>-->  
8 -<!-- <version>0.0.1</version>-->  
9 -<!-- <packaging>pom</packaging>-->  
10 <parent> 5 <parent>
11 <artifactId>yudao-module-iot</artifactId> 6 <artifactId>yudao-module-iot</artifactId>
12 <groupId>cn.iocoder.boot</groupId> 7 <groupId>cn.iocoder.boot</groupId>
@@ -15,6 +10,7 @@ @@ -15,6 +10,7 @@
15 <modules> 10 <modules>
16 <module>yudao-module-iot-demo-plugin</module> 11 <module>yudao-module-iot-demo-plugin</module>
17 <module>yudao-module-iot-http-plugin</module> 12 <module>yudao-module-iot-http-plugin</module>
  13 + <module>yudao-module-iot-mqtt-plugin</module>
18 </modules> 14 </modules>
19 15
20 <modelVersion>4.0.0</modelVersion> 16 <modelVersion>4.0.0</modelVersion>
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties 0 → 100644
  1 +plugin.id=mqtt-plugin
  2 +plugin.class=cn.iocoder.yudao.module.iot.plugin.MqttPlugin
  3 +plugin.version=0.0.1
  4 +plugin.provider=ahh
  5 +plugin.dependencies=
  6 +plugin.description=mqtt-plugin-0.0.1
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3 + xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="
  4 + http://maven.apache.org/POM/4.0.0
  5 + http://maven.apache.org/xsd/maven-4.0.0.xsd">
  6 + <parent>
  7 + <artifactId>yudao-module-iot-plugin</artifactId>
  8 + <groupId>cn.iocoder.boot</groupId>
  9 + <version>${revision}</version>
  10 + </parent>
  11 + <modelVersion>4.0.0</modelVersion>
  12 + <packaging>jar</packaging>
  13 +
  14 + <artifactId>yudao-module-iot-mqtt-plugin</artifactId>
  15 +
  16 + <name>${project.artifactId}</name>
  17 + <description>
  18 + 物联网 插件模块 - mqtt 插件
  19 + </description>
  20 +
  21 + <properties>
  22 + <!-- 插件相关 -->
  23 + <plugin.id>mqtt-plugin</plugin.id>
  24 + <plugin.class>cn.iocoder.yudao.module.iot.plugin.MqttPlugin</plugin.class>
  25 + <plugin.version>0.0.1</plugin.version>
  26 + <plugin.provider>ahh</plugin.provider>
  27 + <plugin.description>mqtt-plugin-0.0.1</plugin.description>
  28 + <plugin.dependencies/>
  29 + </properties>
  30 +
  31 + <build>
  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 + <plugin>
  55 + <groupId>org.apache.maven.plugins</groupId>
  56 + <artifactId>maven-antrun-plugin</artifactId>
  57 + <version>1.6</version>
  58 + <executions>
  59 + <execution>
  60 + <id>unzip jar file</id>
  61 + <phase>package</phase>
  62 + <configuration>
  63 + <target>
  64 + <unzip src="target/${project.artifactId}-${project.version}.${project.packaging}"
  65 + dest="target/plugin-classes"/>
  66 + </target>
  67 + </configuration>
  68 + <goals>
  69 + <goal>run</goal>
  70 + </goals>
  71 + </execution>
  72 + </executions>
  73 + </plugin>
  74 +
  75 + <plugin>
  76 + <artifactId>maven-assembly-plugin</artifactId>
  77 + <version>2.3</version>
  78 + <configuration>
  79 + <descriptors>
  80 + <descriptor>
  81 + src/main/assembly/assembly.xml
  82 + </descriptor>
  83 + </descriptors>
  84 + <appendAssemblyId>false</appendAssemblyId>
  85 + </configuration>
  86 + <executions>
  87 + <execution>
  88 + <id>make-assembly</id>
  89 + <phase>package</phase>
  90 + <goals>
  91 + <goal>attached</goal>
  92 + </goals>
  93 + </execution>
  94 + </executions>
  95 + </plugin>
  96 +
  97 + <plugin>
  98 + <groupId>org.apache.maven.plugins</groupId>
  99 + <artifactId>maven-jar-plugin</artifactId>
  100 + <version>2.4</version>
  101 + <configuration>
  102 + <archive>
  103 + <manifestEntries>
  104 + <Plugin-Id>${plugin.id}</Plugin-Id>
  105 + <Plugin-Class>${plugin.class}</Plugin-Class>
  106 + <Plugin-Version>${plugin.version}</Plugin-Version>
  107 + <Plugin-Provider>${plugin.provider}</Plugin-Provider>
  108 + <Plugin-Description>${plugin.description}</Plugin-Description>
  109 + <Plugin-Dependencies>${plugin.dependencies}</Plugin-Dependencies>
  110 + </manifestEntries>
  111 + </archive>
  112 + </configuration>
  113 + </plugin>
  114 +
  115 + <plugin>
  116 + <artifactId>maven-deploy-plugin</artifactId>
  117 + <configuration>
  118 + <skip>true</skip>
  119 + </configuration>
  120 + </plugin>
  121 + </plugins>
  122 + </build>
  123 +
  124 + <dependencies>
  125 + <!-- 其他依赖项 -->
  126 + <dependency>
  127 + <groupId>org.springframework.boot</groupId>
  128 + <artifactId>spring-boot-starter-web</artifactId>
  129 + </dependency>
  130 + <!-- PF4J Spring 集成 -->
  131 + <dependency>
  132 + <groupId>org.pf4j</groupId>
  133 + <artifactId>pf4j-spring</artifactId>
  134 + <scope>provided</scope>
  135 + </dependency>
  136 + <!-- 项目依赖 -->
  137 + <dependency>
  138 + <groupId>cn.iocoder.boot</groupId>
  139 + <artifactId>yudao-module-iot-api</artifactId>
  140 + <version>${revision}</version>
  141 + </dependency>
  142 + <dependency>
  143 + <groupId>org.projectlombok</groupId>
  144 + <artifactId>lombok</artifactId>
  145 + <version>${lombok.version}</version>
  146 + <scope>provided</scope>
  147 + </dependency>
  148 + <dependency>
  149 + <groupId>io.netty</groupId>
  150 + <artifactId>netty-all</artifactId>
  151 + <version>4.1.63.Final</version> <!-- 版本可根据需要调整 -->
  152 + </dependency>
  153 + </dependencies>
  154 +</project>
0 \ No newline at end of file 155 \ No newline at end of file
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/assembly/assembly.xml 0 → 100644
  1 +<assembly>
  2 + <id>plugin</id>
  3 + <formats>
  4 + <format>zip</format>
  5 + </formats>
  6 + <includeBaseDirectory>false</includeBaseDirectory>
  7 + <dependencySets>
  8 + <dependencySet>
  9 + <useProjectArtifact>false</useProjectArtifact>
  10 + <scope>runtime</scope>
  11 + <outputDirectory>lib</outputDirectory>
  12 + <includes>
  13 + <include>*:jar:*</include>
  14 + </includes>
  15 + </dependencySet>
  16 + </dependencySets>
  17 + <!--
  18 + <fileSets>
  19 + <fileSet>
  20 + <directory>target/classes</directory>
  21 + <outputDirectory>classes</outputDirectory>
  22 + </fileSet>
  23 + </fileSets>
  24 + -->
  25 + <fileSets>
  26 + <fileSet>
  27 + <directory>target/plugin-classes</directory>
  28 + <outputDirectory>classes</outputDirectory>
  29 + </fileSet>
  30 + </fileSets>
  31 +</assembly>
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java 0 → 100644
  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 lombok.extern.slf4j.Slf4j;
  6 +import org.pf4j.PluginWrapper;
  7 +import org.pf4j.Plugin;
  8 +
  9 +import java.util.concurrent.ExecutorService;
  10 +import java.util.concurrent.Executors;
  11 +
  12 +@Slf4j
  13 +public class MqttPlugin extends Plugin {
  14 +
  15 + private ExecutorService executorService;
  16 + private DeviceDataApi deviceDataApi;
  17 +
  18 + public MqttPlugin(PluginWrapper wrapper) {
  19 + super(wrapper);
  20 + // 初始化线程池
  21 + this.executorService = Executors.newSingleThreadExecutor();
  22 + }
  23 +
  24 + @Override
  25 + public void start() {
  26 + log.info("MqttPlugin.start()");
  27 +
  28 + // 重新初始化线程池,确保它是活跃的
  29 + if (executorService.isShutdown() || executorService.isTerminated()) {
  30 + executorService = Executors.newSingleThreadExecutor();
  31 + }
  32 +
  33 + // 从 ServiceRegistry 中获取主程序暴露的 DeviceDataApi 接口实例
  34 + deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class);
  35 + if (deviceDataApi == null) {
  36 + log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!");
  37 + return;
  38 + }
  39 + }
  40 +
  41 + @Override
  42 + public void stop() {
  43 + log.info("MqttPlugin.stop()");
  44 + // 停止线程池
  45 + executorService.shutdownNow();
  46 + }
  47 +
  48 +}
0 \ No newline at end of file 49 \ No newline at end of file