Commit 603649d2485ec36f30b77ae2a17957fb4bf28100
1 parent
dc1f9338
【功能完善】IoT: 新增 MQTT RPC 支持,包含请求和响应模型、序列化工具、MQTT 配置及客户端/服务器实现,提供示例服务和控制器接口,优化插件结构以支持 HTTP 插件的集成。
Showing
15 changed files
with
471 additions
and
12 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mqttrpc.common; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Builder; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.NoArgsConstructor; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * MQTT RPC 请求 | |
| 10 | + * | |
| 11 | + */ | |
| 12 | +@Data | |
| 13 | +@Builder | |
| 14 | +@NoArgsConstructor | |
| 15 | +@AllArgsConstructor | |
| 16 | +public class RpcRequest { | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 方法名 | |
| 20 | + */ | |
| 21 | + private String method; | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 参数 | |
| 25 | + */ | |
| 26 | + private Object[] params; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 关联 ID | |
| 30 | + */ | |
| 31 | + private String correlationId; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 回复地址 | |
| 35 | + */ | |
| 36 | + private String replyTo; | |
| 37 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mqttrpc.common; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Builder; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.NoArgsConstructor; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * MQTT RPC 响应 | |
| 10 | + * | |
| 11 | + */ | |
| 12 | +@Data | |
| 13 | +@Builder | |
| 14 | +@NoArgsConstructor | |
| 15 | +@AllArgsConstructor | |
| 16 | +public class RpcResponse { | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 关联 ID | |
| 20 | + */ | |
| 21 | + private String correlationId; | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 结果 | |
| 25 | + */ | |
| 26 | + private Object result; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 错误 | |
| 30 | + */ | |
| 31 | + private String error; | |
| 32 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mqttrpc.common; | |
| 2 | + | |
| 3 | +import cn.hutool.json.JSONUtil; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 序列化工具类 | |
| 7 | + * | |
| 8 | + */ | |
| 9 | +public class SerializationUtils { | |
| 10 | + | |
| 11 | + public static String serialize(Object obj) { | |
| 12 | + return JSONUtil.toJsonStr(obj); | |
| 13 | + } | |
| 14 | + | |
| 15 | + public static <T> T deserialize(String json, Class<T> clazz) { | |
| 16 | + return JSONUtil.toBean(json, clazz); | |
| 17 | + } | |
| 18 | +} | |
| 0 | 19 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mqttrpc.config; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | +import org.springframework.boot.context.properties.ConfigurationProperties; | |
| 5 | +import org.springframework.context.annotation.Configuration; | |
| 6 | + | |
| 7 | +@Data | |
| 8 | +@Configuration | |
| 9 | +@ConfigurationProperties(prefix = "mqtt") | |
| 10 | +public class MqttConfig { | |
| 11 | + /** | |
| 12 | + * MQTT 代理地址 | |
| 13 | + */ | |
| 14 | + private String broker; | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * MQTT 用户名 | |
| 18 | + */ | |
| 19 | + private String username; | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * MQTT 密码 | |
| 23 | + */ | |
| 24 | + private String password; | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * MQTT 客户端 ID | |
| 28 | + */ | |
| 29 | + private String clientId; | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * MQTT 请求主题 | |
| 33 | + */ | |
| 34 | + private String requestTopic; | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * MQTT 响应主题前缀 | |
| 38 | + */ | |
| 39 | + private String responseTopicPrefix; | |
| 40 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mqttrpc.server; | |
| 2 | + | |
| 3 | +import cn.hutool.core.lang.UUID; | |
| 4 | +import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest; | |
| 5 | +import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse; | |
| 6 | +import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils; | |
| 7 | +import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig; | |
| 8 | +import lombok.extern.slf4j.Slf4j; | |
| 9 | +import org.eclipse.paho.client.mqttv3.*; | |
| 10 | +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; | |
| 11 | +import org.springframework.stereotype.Service; | |
| 12 | + | |
| 13 | +import javax.annotation.PostConstruct; | |
| 14 | +import javax.annotation.PreDestroy; | |
| 15 | +import java.util.HashMap; | |
| 16 | +import java.util.Map; | |
| 17 | + | |
| 18 | +@Service | |
| 19 | +@Slf4j | |
| 20 | +public class RpcServer { | |
| 21 | + | |
| 22 | + private final MqttConfig mqttConfig; | |
| 23 | + private final MqttClient mqttClient; | |
| 24 | + private final Map<String, MethodInvoker> methodRegistry = new HashMap<>(); | |
| 25 | + | |
| 26 | + public RpcServer(MqttConfig mqttConfig) throws MqttException { | |
| 27 | + this.mqttConfig = mqttConfig; | |
| 28 | + this.mqttClient = new MqttClient(mqttConfig.getBroker(), "rpc-server-" + UUID.randomUUID(), new MemoryPersistence()); | |
| 29 | + MqttConnectOptions options = new MqttConnectOptions(); | |
| 30 | + options.setAutomaticReconnect(true); | |
| 31 | + options.setCleanSession(true); | |
| 32 | + options.setUserName(mqttConfig.getUsername()); | |
| 33 | + options.setPassword(mqttConfig.getPassword().toCharArray()); | |
| 34 | + this.mqttClient.connect(options); | |
| 35 | + } | |
| 36 | + | |
| 37 | + @PostConstruct | |
| 38 | + public void init() throws MqttException { | |
| 39 | + mqttClient.subscribe(mqttConfig.getRequestTopic(), this::handleRequest); | |
| 40 | + log.info("RPC Server subscribed to topic: {}", mqttConfig.getRequestTopic()); | |
| 41 | + } | |
| 42 | + | |
| 43 | + private void handleRequest(String topic, MqttMessage message) { | |
| 44 | + RpcRequest request = SerializationUtils.deserialize(new String(message.getPayload()), RpcRequest.class); | |
| 45 | + RpcResponse response = new RpcResponse(); | |
| 46 | + response.setCorrelationId(request.getCorrelationId()); | |
| 47 | + | |
| 48 | + try { | |
| 49 | + MethodInvoker invoker = methodRegistry.get(request.getMethod()); | |
| 50 | + if (invoker == null) { | |
| 51 | + throw new NoSuchMethodException("Unknown method: " + request.getMethod()); | |
| 52 | + } | |
| 53 | + Object result = invoker.invoke(request.getParams()); | |
| 54 | + response.setResult(result); | |
| 55 | + } catch (Exception e) { | |
| 56 | + response.setError(e.getMessage()); | |
| 57 | + log.error("Error processing RPC request: {}", e.getMessage(), e); | |
| 58 | + } | |
| 59 | + | |
| 60 | + String replyPayload = SerializationUtils.serialize(response); | |
| 61 | + MqttMessage replyMessage = new MqttMessage(replyPayload.getBytes()); | |
| 62 | + replyMessage.setQos(1); | |
| 63 | + try { | |
| 64 | + mqttClient.publish(request.getReplyTo(), replyMessage); | |
| 65 | + log.info("Published response to {}", request.getReplyTo()); | |
| 66 | + } catch (MqttException e) { | |
| 67 | + log.error("Failed to publish response: {}", e.getMessage(), e); | |
| 68 | + } | |
| 69 | + } | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * 注册可调用的方法 | |
| 73 | + * | |
| 74 | + * @param methodName 方法名称 | |
| 75 | + * @param invoker 方法调用器 | |
| 76 | + */ | |
| 77 | + public void registerMethod(String methodName, MethodInvoker invoker) { | |
| 78 | + methodRegistry.put(methodName, invoker); | |
| 79 | + log.info("Registered method: {}", methodName); | |
| 80 | + } | |
| 81 | + | |
| 82 | + @PreDestroy | |
| 83 | + public void cleanup() throws MqttException { | |
| 84 | + mqttClient.disconnect(); | |
| 85 | + log.info("RPC Server disconnected"); | |
| 86 | + } | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * 方法调用器接口 | |
| 90 | + */ | |
| 91 | + @FunctionalInterface | |
| 92 | + public interface MethodInvoker { | |
| 93 | + Object invoke(Object[] params) throws Exception; | |
| 94 | + } | |
| 95 | +} | |
| 0 | 96 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.plugin; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.iot.mqttrpc.server.RpcServer; | |
| 4 | +import lombok.RequiredArgsConstructor; | |
| 5 | +import org.springframework.stereotype.Service; | |
| 6 | + | |
| 7 | +import javax.annotation.PostConstruct; | |
| 8 | + | |
| 9 | +@Service | |
| 10 | +@RequiredArgsConstructor | |
| 11 | +public class ExampleService { | |
| 12 | + | |
| 13 | + private final RpcServer rpcServer; | |
| 14 | + | |
| 15 | + @PostConstruct | |
| 16 | + public void registerMethods() { | |
| 17 | + rpcServer.registerMethod("add", params -> { | |
| 18 | + if (params.length != 2) { | |
| 19 | + throw new IllegalArgumentException("add方法需要两个参数"); | |
| 20 | + } | |
| 21 | + int a = ((Number) params[0]).intValue(); | |
| 22 | + int b = ((Number) params[1]).intValue(); | |
| 23 | + return add(a, b); | |
| 24 | + }); | |
| 25 | + | |
| 26 | + rpcServer.registerMethod("concat", params -> { | |
| 27 | + if (params.length != 2) { | |
| 28 | + throw new IllegalArgumentException("concat方法需要两个参数"); | |
| 29 | + } | |
| 30 | + String str1 = params[0].toString(); | |
| 31 | + String str2 = params[1].toString(); | |
| 32 | + return concat(str1, str2); | |
| 33 | + }); | |
| 34 | + } | |
| 35 | + | |
| 36 | + private int add(int a, int b) { | |
| 37 | + return a + b; | |
| 38 | + } | |
| 39 | + | |
| 40 | + private String concat(String a, String b) { | |
| 41 | + return a + b; | |
| 42 | + } | |
| 43 | +} | |
| 0 | 44 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java
| ... | ... | @@ -18,7 +18,6 @@ import org.springframework.stereotype.Service; |
| 18 | 18 | import org.springframework.validation.annotation.Validated; |
| 19 | 19 | import org.springframework.web.multipart.MultipartFile; |
| 20 | 20 | |
| 21 | -import javax.annotation.PostConstruct; | |
| 22 | 21 | import java.io.File; |
| 23 | 22 | import java.io.IOException; |
| 24 | 23 | import java.nio.file.*; | ... | ... |
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml
| ... | ... | @@ -150,5 +150,10 @@ |
| 150 | 150 | <artifactId>netty-all</artifactId> |
| 151 | 151 | <version>4.1.63.Final</version> <!-- 版本可根据需要调整 --> |
| 152 | 152 | </dependency> |
| 153 | + <!-- MQTT --> | |
| 154 | + <dependency> | |
| 155 | + <groupId>org.eclipse.paho</groupId> | |
| 156 | + <artifactId>org.eclipse.paho.client.mqttv3</artifactId> | |
| 157 | + </dependency> | |
| 153 | 158 | </dependencies> |
| 154 | 159 | </project> |
| 155 | 160 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot; | |
| 2 | + | |
| 3 | +import org.springframework.boot.SpringApplication; | |
| 4 | +import org.springframework.boot.autoconfigure.SpringBootApplication; | |
| 5 | + | |
| 6 | +@SpringBootApplication | |
| 7 | +public class HttpPluginSpringbootApplication { | |
| 8 | + public static void main(String[] args) { | |
| 9 | + SpringApplication.run(HttpPluginSpringbootApplication.class, args); | |
| 10 | + } | |
| 11 | +} | |
| 0 | 12 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java
0 → 100644
| 1 | + | |
| 2 | +package cn.iocoder.yudao.module.iot.controller; | |
| 3 | + | |
| 4 | +import cn.iocoder.yudao.module.iot.mqttrpc.client.RpcClient; | |
| 5 | +import lombok.RequiredArgsConstructor; | |
| 6 | +import org.springframework.web.bind.annotation.PostMapping; | |
| 7 | +import org.springframework.web.bind.annotation.RequestMapping; | |
| 8 | +import org.springframework.web.bind.annotation.RequestParam; | |
| 9 | +import org.springframework.web.bind.annotation.RestController; | |
| 10 | + | |
| 11 | +import javax.annotation.Resource; | |
| 12 | +import java.util.concurrent.CompletableFuture; | |
| 13 | + | |
| 14 | +@RestController | |
| 15 | +@RequestMapping("/rpc") | |
| 16 | +@RequiredArgsConstructor | |
| 17 | +public class RpcController { | |
| 18 | + | |
| 19 | + @Resource | |
| 20 | + private RpcClient rpcClient; | |
| 21 | + | |
| 22 | + @PostMapping("/add") | |
| 23 | + public CompletableFuture<Object> add(@RequestParam int a, @RequestParam int b) throws Exception { | |
| 24 | + return rpcClient.call("add", new Object[]{a, b}, 10); | |
| 25 | + } | |
| 26 | + | |
| 27 | + @PostMapping("/concat") | |
| 28 | + public CompletableFuture<Object> concat(@RequestParam String str1, @RequestParam String str2) throws Exception { | |
| 29 | + return rpcClient.call("concat", new Object[]{str1, str2}, 10); | |
| 30 | + } | |
| 31 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mqttrpc.client; | |
| 2 | + | |
| 3 | +import java.util.concurrent.CompletableFuture; | |
| 4 | +import java.util.concurrent.ConcurrentHashMap; | |
| 5 | +import java.util.concurrent.ConcurrentMap; | |
| 6 | +import java.util.concurrent.Executors; | |
| 7 | +import java.util.concurrent.ScheduledExecutorService; | |
| 8 | +import java.util.concurrent.TimeUnit; | |
| 9 | +import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest; | |
| 10 | +import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse; | |
| 11 | +import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils; | |
| 12 | +import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig; | |
| 13 | +import lombok.extern.slf4j.Slf4j; | |
| 14 | +import org.eclipse.paho.client.mqttv3.*; | |
| 15 | +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; | |
| 16 | +import org.springframework.stereotype.Service; | |
| 17 | + | |
| 18 | +import javax.annotation.PostConstruct; | |
| 19 | +import javax.annotation.PreDestroy; | |
| 20 | +import java.util.UUID; | |
| 21 | +import java.util.concurrent.*; | |
| 22 | + | |
| 23 | +@Service | |
| 24 | +@Slf4j | |
| 25 | +public class RpcClient { | |
| 26 | + | |
| 27 | + private final MqttConfig mqttConfig; | |
| 28 | + private final MqttClient mqttClient; | |
| 29 | + private final ConcurrentMap<String, CompletableFuture<RpcResponse>> pendingRequests = new ConcurrentHashMap<>(); | |
| 30 | + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); | |
| 31 | + | |
| 32 | + public RpcClient(MqttConfig mqttConfig) throws MqttException { | |
| 33 | + this.mqttConfig = mqttConfig; | |
| 34 | + this.mqttClient = new MqttClient(mqttConfig.getBroker(), mqttConfig.getClientId(), new MemoryPersistence()); | |
| 35 | + MqttConnectOptions options = new MqttConnectOptions(); | |
| 36 | + options.setAutomaticReconnect(true); | |
| 37 | + options.setCleanSession(true); | |
| 38 | + options.setUserName(mqttConfig.getUsername()); | |
| 39 | + options.setPassword(mqttConfig.getPassword().toCharArray()); | |
| 40 | + this.mqttClient.connect(options); | |
| 41 | + } | |
| 42 | + | |
| 43 | + @PostConstruct | |
| 44 | + public void init() throws MqttException { | |
| 45 | + mqttClient.subscribe(mqttConfig.getResponseTopicPrefix() + "#", this::handleResponse); | |
| 46 | + log.info("RPC Client subscribed to topics: {}", mqttConfig.getResponseTopicPrefix() + "#"); | |
| 47 | + } | |
| 48 | + | |
| 49 | + private void handleResponse(String topic, MqttMessage message) { | |
| 50 | + String correlationId = topic.substring(mqttConfig.getResponseTopicPrefix().length()); | |
| 51 | + RpcResponse response = SerializationUtils.deserialize(new String(message.getPayload()), RpcResponse.class); | |
| 52 | + CompletableFuture<RpcResponse> future = pendingRequests.remove(correlationId); | |
| 53 | + if (future != null) { | |
| 54 | + if (response.getError() != null) { | |
| 55 | + future.completeExceptionally(new RuntimeException(response.getError())); | |
| 56 | + } else { | |
| 57 | + future.complete(response); | |
| 58 | + } | |
| 59 | + } else { | |
| 60 | + log.warn("Received response for unknown correlationId: {}", correlationId); | |
| 61 | + } | |
| 62 | + } | |
| 63 | + | |
| 64 | + public CompletableFuture<Object> call(String method, Object[] params, int timeoutSeconds) throws MqttException { | |
| 65 | + String correlationId = UUID.randomUUID().toString(); | |
| 66 | + String replyTo = mqttConfig.getResponseTopicPrefix() + correlationId; | |
| 67 | + | |
| 68 | + RpcRequest request = new RpcRequest(method, params, correlationId, replyTo); | |
| 69 | + String payload = SerializationUtils.serialize(request); | |
| 70 | + MqttMessage message = new MqttMessage(payload.getBytes()); | |
| 71 | + message.setQos(1); | |
| 72 | + mqttClient.publish(mqttConfig.getRequestTopic(), message); | |
| 73 | + | |
| 74 | + CompletableFuture<RpcResponse> futureResponse = new CompletableFuture<>(); | |
| 75 | + pendingRequests.put(correlationId, futureResponse); | |
| 76 | + | |
| 77 | + // 设置超时 | |
| 78 | + scheduler.schedule(() -> { | |
| 79 | + CompletableFuture<RpcResponse> removed = pendingRequests.remove(correlationId); | |
| 80 | + if (removed != null) { | |
| 81 | + removed.completeExceptionally(new TimeoutException("RPC call timed out")); | |
| 82 | + } | |
| 83 | + }, timeoutSeconds, TimeUnit.SECONDS); | |
| 84 | + | |
| 85 | + // 返回最终的结果 | |
| 86 | + return futureResponse.thenApply(RpcResponse::getResult); | |
| 87 | + } | |
| 88 | + | |
| 89 | + @PreDestroy | |
| 90 | + public void cleanup() throws MqttException { | |
| 91 | + mqttClient.disconnect(); | |
| 92 | + scheduler.shutdown(); | |
| 93 | + log.info("RPC Client disconnected"); | |
| 94 | + } | |
| 95 | +} | |
| 0 | 96 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mqttrpc.config; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | +import org.springframework.boot.context.properties.ConfigurationProperties; | |
| 5 | +import org.springframework.context.annotation.Configuration; | |
| 6 | + | |
| 7 | +@Data | |
| 8 | +@Configuration | |
| 9 | +@ConfigurationProperties(prefix = "mqtt") | |
| 10 | +public class MqttConfig { | |
| 11 | + | |
| 12 | + /** | |
| 13 | + * MQTT 代理地址 | |
| 14 | + */ | |
| 15 | + private String broker; | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * MQTT 用户名 | |
| 19 | + */ | |
| 20 | + private String username; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * MQTT 密码 | |
| 24 | + */ | |
| 25 | + private String password; | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * MQTT 客户端 ID | |
| 29 | + */ | |
| 30 | + private String clientId; | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * MQTT 请求主题 | |
| 34 | + */ | |
| 35 | + private String requestTopic; | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * MQTT 响应主题前缀 | |
| 39 | + */ | |
| 40 | + private String responseTopicPrefix; | |
| 41 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml
0 → 100644
| 1 | +server: | |
| 2 | + port: 8092 | |
| 3 | + | |
| 4 | +spring: | |
| 5 | + application: | |
| 6 | + name: yudao-module-iot-http-plugin | |
| 7 | + | |
| 8 | +# MQTT-RPC 配置 | |
| 9 | +mqtt: | |
| 10 | + broker: tcp://chaojiniu.top:1883 | |
| 11 | + username: haohao | |
| 12 | + password: ahh@123456 | |
| 13 | + clientId: mqtt-rpc-client-${random.int} | |
| 14 | + requestTopic: rpc/request | |
| 15 | + responseTopicPrefix: rpc/response/ | ... | ... |
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml
| ... | ... | @@ -145,10 +145,10 @@ |
| 145 | 145 | <version>${lombok.version}</version> |
| 146 | 146 | <scope>provided</scope> |
| 147 | 147 | </dependency> |
| 148 | + <!-- MQTT --> | |
| 148 | 149 | <dependency> |
| 149 | - <groupId>io.netty</groupId> | |
| 150 | - <artifactId>netty-all</artifactId> | |
| 151 | - <version>4.1.63.Final</version> <!-- 版本可根据需要调整 --> | |
| 150 | + <groupId>org.eclipse.paho</groupId> | |
| 151 | + <artifactId>org.eclipse.paho.client.mqttv3</artifactId> | |
| 152 | 152 | </dependency> |
| 153 | 153 | </dependencies> |
| 154 | 154 | </project> |
| 155 | 155 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.plugin; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | |
| 4 | 3 | import cn.iocoder.yudao.module.iot.api.ServiceRegistry; |
| 4 | +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; | |
| 5 | 5 | import lombok.extern.slf4j.Slf4j; |
| 6 | -import org.pf4j.PluginWrapper; | |
| 7 | 6 | import org.pf4j.Plugin; |
| 7 | +import org.pf4j.PluginWrapper; | |
| 8 | 8 | |
| 9 | +import javax.annotation.Resource; | |
| 9 | 10 | import java.util.concurrent.ExecutorService; |
| 10 | 11 | import java.util.concurrent.Executors; |
| 11 | 12 | |
| ... | ... | @@ -13,11 +14,11 @@ import java.util.concurrent.Executors; |
| 13 | 14 | public class MqttPlugin extends Plugin { |
| 14 | 15 | |
| 15 | 16 | private ExecutorService executorService; |
| 17 | + @Resource | |
| 16 | 18 | private DeviceDataApi deviceDataApi; |
| 17 | 19 | |
| 18 | 20 | public MqttPlugin(PluginWrapper wrapper) { |
| 19 | 21 | super(wrapper); |
| 20 | - // 初始化线程池 | |
| 21 | 22 | this.executorService = Executors.newSingleThreadExecutor(); |
| 22 | 23 | } |
| 23 | 24 | |
| ... | ... | @@ -25,24 +26,20 @@ public class MqttPlugin extends Plugin { |
| 25 | 26 | public void start() { |
| 26 | 27 | log.info("MqttPlugin.start()"); |
| 27 | 28 | |
| 28 | - // 重新初始化线程池,确保它是活跃的 | |
| 29 | 29 | if (executorService.isShutdown() || executorService.isTerminated()) { |
| 30 | 30 | executorService = Executors.newSingleThreadExecutor(); |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | - // 从 ServiceRegistry 中获取主程序暴露的 DeviceDataApi 接口实例 | |
| 34 | 33 | deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); |
| 35 | 34 | if (deviceDataApi == null) { |
| 36 | 35 | log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); |
| 37 | 36 | return; |
| 38 | 37 | } |
| 38 | + | |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | @Override |
| 42 | 42 | public void stop() { |
| 43 | 43 | log.info("MqttPlugin.stop()"); |
| 44 | - // 停止线程池 | |
| 45 | - executorService.shutdownNow(); | |
| 46 | 44 | } |
| 47 | - | |
| 48 | 45 | } |
| 49 | 46 | \ No newline at end of file | ... | ... |