Springboot 集成 MQTT —— web 服務端實現(apollo 客戶端)

基於 MQTT 可以實現很多場景,例如現在使用比較多的物聯網,還有消息的實時推送。聯網的設備連接上 apollo 服務器以後,一直監聽 apollo 推送過來的信令/消息即可。
在這裏插入圖片描述

1、web 服務端向聯網的設備推送信令/消息,上述截圖的流程(1.1-1.2)。

1.1、web 服務端向 apollo 服務器發送信令/消息。
1.2、聯網的設備通過訂閱的主題,收到 web 服務端推送的信令/消息。

2、聯網的設備 1 向聯網的設備 2 發送信令/消息,上述截圖的流程(2.1-2.4)。

2.1、設備 1 向 apollo 服務器發送接收方爲設備 2 的消息/信令。
2.2、設備 2 向 web 服務端發起登錄。
2.3、設備 2 在 web 服務端登錄成功後,設備 2 與 apollo 服務器建立長連接。
2.4、設備 2 通過訂閱的主題,收到設備 1 推送的信令/消息。

現在,整體結構已經比較明顯了,接下來就會介紹 web 服務端的實現

基於 MQTT 長連接的 web 端實現

基於《Springboot 集成 MQTT —— 搭建 apollo 服務器(Windows)》 一文中搭建的 apollo 服務器,web 端需要配置 apollo 的連接。
在這裏插入圖片描述
標記部分的內容如下

# 用戶名
mqtt.username=admin
# 密碼
mqtt.password=password
mqtt.url=tcp://127.0.0.1:61613
# 生產者客戶端 ID
mqtt.send.clientId=mqttSendClient
# 消費者客戶端 ID
mqtt.recv.clientId=mqttRecvClient

添加上述配置的時候,應該會發現,有些內容不會自動提示,我們需要手動的將上述配置信息配置到 MQTT 客戶端的實例中。新增 MqttConfig 類。

import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;

@Configuration
public class MqttConfig {
    private static final Logger LOGGER = LoggerFactory.getLogger(MqttConfig.class);

    public static final String CHANNEL_RECV = "recvMsgChannel"; // 訂閱消息的信道
    public static final String CHANNEL_SEND = "sendMsgChannel"; // 發佈消息的信道
    public static final String TOPIC = "topic";

    @Value("${mqtt.username}")
    private String username;

    @Value("${mqtt.password}")
    private String password;

    @Value("${mqtt.url}")
    private String url;

    @Value("${mqtt.send.clientId}")
    private String senderClientId;

    @Value("${mqtt.recv.clientId}")
    private String recverClientId;


    // MQTT 客戶端的連接器哦誒之
    @Bean
    public MqttConnectOptions getMqttConnectOptions() {
        MqttConnectOptions options = new MqttConnectOptions();
        // 是否清空 session。false:服務器會保留客戶端的連接記錄,true:每次連接服務器都以新身份連接
        options.setCleanSession(true);
        options.setUserName(username); // 連接用戶
        options.setPassword(password.toCharArray()); // 連接密碼
        options.setServerURIs(url.split(","));  // 連接的服務器 url
        options.setConnectionTimeout(10); // 超時時間(單位:s)
        options.setKeepAliveInterval(20); // 保活心跳(單位:s),此方法沒有重連機制
        return options;
    }

    // 構造 MQTT 客戶端
    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        factory.setConnectionOptions(getMqttConnectOptions());
        return factory;
    }

    // MQTT 生產者客戶端
    @Bean
    @ServiceActivator(inputChannel = CHANNEL_SEND)
    public MessageHandler mqttMsgSend() {
        MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(senderClientId, mqttClientFactory());
        messageHandler.setAsync(true);
        return messageHandler;
    }

    // MQTT 消息訂閱綁定(消費者)
    @Bean
    public MessageProducer mqttMsgRecv() {
        // 可以訂閱多個 Topic 的消息
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
                recverClientId, mqttClientFactory(), TOPIC.split(","));
        adapter.setCompletionTimeout(5000);
        adapter.setConverter(new DefaultPahoMessageConverter());
        adapter.setQos(2);
        adapter.setOutputChannel(mqttInboundChannel()); // 設置訂閱通道
        return adapter;
    }

    // MQTT信息通道(消費者)
    @Bean(name = CHANNEL_RECV)
    public MessageChannel mqttInboundChannel() {
        return new DirectChannel();
    }

    // MQTT消息處理器(消費者,用於服務端自發自收的測試)
    @Bean
    @ServiceActivator(inputChannel = CHANNEL_RECV)
    public MessageHandler handler() {
        return new MessageHandler() {
            @Override
            public void handleMessage(Message<?> message) throws MessagingException {
                LOGGER.error("msg:{}", message.getPayload());
            }
        };
    }
}

新增一個消息發送接口 IMqttSender

import com.hosh.tech.config.MqttConfig;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

/**
 * MQTT生產者消息發送接口
 * MessagingGateway要指定生產者的通道名稱
 */
@Component
@MessagingGateway(defaultRequestChannel = MqttConfig.CHANNEL_SEND)
public interface IMqttSender {

    /**
     * 發送信息到MQTT服務器(實現發送全用戶消息)
     * @param data 消息內容
     */
    void sendToMqtt(String data);

    /**
     * 發送信息到 MQTT 服務器(實現發送公告類消息——P2M)
     * @param topic 主題
     * @param payload 消息內容
     */
    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic,
                    String payload);

    /**
     * 發送信息到 MQTT 服務器(實現發送點對點的消息)
     * @param topic 主題
     * @param qos 對消息處理的幾種機制
     * 0 表示的是訂閱者沒收到消息不會再次發送,消息會丟失
     * 1 表示的是會嘗試重試,一直到接收到消息,但這種情況可能導致訂閱者收到多次重複消息
     * 2 多了一次去重的動作,確保訂閱者收到的消息有一次
     * @param payload 消息內容
     */
    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic,
                    @Header(MqttHeaders.QOS) int qos,
                    String payload);
}

測試 web 服務端的推送

web 服務端的發送消息的實現
在這裏插入圖片描述
爲了方便測試,消息爲自發自收,收消息的實現已經在 MqttConfig 中給出
在這裏插入圖片描述
通過 http 請求觸發自發自收的過程,可以看到如下的打印信息
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章