|
@@ -0,0 +1,227 @@
|
|
|
+package com.ruoyi.web.controller.mqtt;
|
|
|
+
|
|
|
+import com.ruoyi.common.model.MqttMessage;
|
|
|
+import com.ruoyi.common.utils.mqtt.MqttService;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.eclipse.paho.client.mqttv3.MqttException;
|
|
|
+import org.springframework.http.HttpStatus;
|
|
|
+import org.springframework.http.ResponseEntity;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
+import java.util.concurrent.ExecutionException;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.concurrent.TimeoutException;
|
|
|
+
|
|
|
+/**
|
|
|
+ * MQTT控制器
|
|
|
+ *
|
|
|
+ * <p>提供MQTT相关操作的REST API接口,包括消息发布、主题订阅和连接管理等,
|
|
|
+ * 方便通过HTTP请求操作MQTT客户端。</p>
|
|
|
+ *
|
|
|
+ * @author andy
|
|
|
+ * @version 1.0.0
|
|
|
+ * @since 2025-06-17
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@RestController
|
|
|
+@RequiredArgsConstructor
|
|
|
+@RequestMapping("/mqtt")
|
|
|
+public class MqttController {
|
|
|
+
|
|
|
+ private final MqttService mqttService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取MQTT连接状态
|
|
|
+ *
|
|
|
+ * @return 连接状态信息
|
|
|
+ */
|
|
|
+ @GetMapping("/status")
|
|
|
+ public ResponseEntity<Map<String, Object>> getStatus() {
|
|
|
+ Map<String, Object> status = new HashMap<>();
|
|
|
+ status.put("connected", mqttService.isConnected());
|
|
|
+ status.put("timestamp", System.currentTimeMillis());
|
|
|
+
|
|
|
+ return ResponseEntity.ok(status);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 重新连接MQTT服务器
|
|
|
+ *
|
|
|
+ * @return 重连结果
|
|
|
+ */
|
|
|
+ @PostMapping("/reconnect")
|
|
|
+ public ResponseEntity<Map<String, Object>> reconnect() {
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+
|
|
|
+ try {
|
|
|
+ CompletableFuture<Void> future = mqttService.reconnect();
|
|
|
+ future.get(10, TimeUnit.SECONDS);
|
|
|
+
|
|
|
+ result.put("success", true);
|
|
|
+ result.put("message", "已成功重新连接到MQTT服务器");
|
|
|
+ return ResponseEntity.ok(result);
|
|
|
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
|
|
|
+ log.error("重连MQTT服务器失败: {}", e.getMessage(), e);
|
|
|
+
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "重连MQTT服务器失败: " + e.getMessage());
|
|
|
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发布MQTT消息
|
|
|
+ *
|
|
|
+ * @param message MQTT消息对象
|
|
|
+ * @return 发布结果
|
|
|
+ */
|
|
|
+ @PostMapping("/publish")
|
|
|
+ public ResponseEntity<Map<String, Object>> publishMessage(@RequestBody MqttMessage message) {
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+
|
|
|
+ if (message.getTopic() == null || message.getTopic().isEmpty()) {
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "消息主题不能为空");
|
|
|
+ return ResponseEntity.badRequest().body(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (message.getPayload() == null) {
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "消息内容不能为空");
|
|
|
+ return ResponseEntity.badRequest().body(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ CompletableFuture<Void> future = mqttService.publish(message);
|
|
|
+ future.get(10, TimeUnit.SECONDS);
|
|
|
+
|
|
|
+ result.put("success", true);
|
|
|
+ result.put("message", "消息发布成功");
|
|
|
+ result.put("topic", message.getTopic());
|
|
|
+ return ResponseEntity.ok(result);
|
|
|
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
|
|
|
+ log.error("发布消息失败: {}", e.getMessage(), e);
|
|
|
+
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "发布消息失败: " + e.getMessage());
|
|
|
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 简化版发布消息接口
|
|
|
+ *
|
|
|
+ * @param topic 消息主题
|
|
|
+ * @param payload 消息内容
|
|
|
+ * @return 发布结果
|
|
|
+ */
|
|
|
+ @RequestMapping("/publish/simple")
|
|
|
+ public ResponseEntity<Map<String, Object>> publishSimpleMessage(
|
|
|
+ @RequestParam String topic,
|
|
|
+ @RequestParam String payload) {
|
|
|
+
|
|
|
+ MqttMessage message = new MqttMessage(topic, payload);
|
|
|
+ return publishMessage(message);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 订阅主题
|
|
|
+ *
|
|
|
+ * @param topic 要订阅的主题
|
|
|
+ * @return 订阅结果
|
|
|
+ */
|
|
|
+ @RequestMapping("/subscribe")
|
|
|
+ public ResponseEntity<Map<String, Object>> subscribeTopic(@RequestParam String topic) {
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+
|
|
|
+ if (topic == null || topic.isEmpty()) {
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "订阅主题不能为空");
|
|
|
+ return ResponseEntity.badRequest().body(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ String subscribedTopic = mqttService.subscribe(topic);
|
|
|
+
|
|
|
+ result.put("success", true);
|
|
|
+ result.put("message", "主题订阅成功");
|
|
|
+ result.put("topic", subscribedTopic);
|
|
|
+ return ResponseEntity.ok(result);
|
|
|
+ } catch (MqttException e) {
|
|
|
+ log.error("订阅主题失败: {}", e.getMessage(), e);
|
|
|
+
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "订阅主题失败: " + e.getMessage());
|
|
|
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量订阅主题
|
|
|
+ *
|
|
|
+ * @param topics 要订阅的主题列表
|
|
|
+ * @return 订阅结果
|
|
|
+ */
|
|
|
+ @PostMapping("/subscribe/batch")
|
|
|
+ public ResponseEntity<Map<String, Object>> subscribeTopics(@RequestBody List<String> topics) {
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+
|
|
|
+ if (topics == null || topics.isEmpty()) {
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "订阅主题列表不能为空");
|
|
|
+ return ResponseEntity.badRequest().body(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ List<String> subscribedTopics = mqttService.subscribe(topics);
|
|
|
+
|
|
|
+ result.put("success", true);
|
|
|
+ result.put("message", "批量主题订阅成功");
|
|
|
+ result.put("topics", subscribedTopics);
|
|
|
+ return ResponseEntity.ok(result);
|
|
|
+ } catch (MqttException e) {
|
|
|
+ log.error("批量订阅主题失败: {}", e.getMessage(), e);
|
|
|
+
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "批量订阅主题失败: " + e.getMessage());
|
|
|
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取消订阅主题
|
|
|
+ *
|
|
|
+ * @param topic 要取消订阅的主题
|
|
|
+ * @return 取消订阅结果
|
|
|
+ */
|
|
|
+ @PostMapping("/unsubscribe")
|
|
|
+ public ResponseEntity<Map<String, Object>> unsubscribeTopic(@RequestParam String topic) {
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+
|
|
|
+ if (topic == null || topic.isEmpty()) {
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "取消订阅的主题不能为空");
|
|
|
+ return ResponseEntity.badRequest().body(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ mqttService.unsubscribe(topic);
|
|
|
+
|
|
|
+ result.put("success", true);
|
|
|
+ result.put("message", "主题取消订阅成功");
|
|
|
+ result.put("topic", topic);
|
|
|
+ return ResponseEntity.ok(result);
|
|
|
+ } catch (MqttException e) {
|
|
|
+ log.error("取消订阅主题失败: {}", e.getMessage(), e);
|
|
|
+
|
|
|
+ result.put("success", false);
|
|
|
+ result.put("message", "取消订阅主题失败: " + e.getMessage());
|
|
|
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|