MQTT接收字串(1/2)

獵手家園發表於2022-04-25

我們現在所使用的通訊硬體大多數都是以UTF-8字元和ASCII的編碼格式進行訊息收發。

MQTT測試工具,請檢視上一篇內容。

 

一、配置pom的maven依賴

<dependency>
    <groupId>org.fusesource.hawtbuf</groupId>
    <artifactId>hawtbuf</artifactId>
    <version>1.11</version>
</dependency>
<dependency>
    <groupId>org.fusesource.hawtdispatch</groupId>
    <artifactId>hawtdispatch</artifactId>
    <version>1.22</version>
</dependency>
<dependency>
    <groupId>org.fusesource.hawtdispatch</groupId>
    <artifactId>hawtdispatch-transport</artifactId>
    <version>1.22</version>
</dependency>
<dependency>
    <groupId>org.fusesource.mqtt-client</groupId>
    <artifactId>mqtt-client</artifactId>
    <version>1.16</version>
</dependency>

 

為了程式碼的可閱讀性,我將以下程式碼按照功能封裝到不同的類當中。

 

二、MQTT資料接收類

package com.xxxx.controller.Server.MQTT;

import com.xxxx.common.utils.PropertyUtils;
import com.xxxx.worker.controller.Server.Execute.MessageExecute;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @title: MQTT訊息訂閱(接收字串)
 * @author: hunttown
 * @date: 2021年10月17日 9:10
 * @description: 當前類用bean注入,不要使用註解注入,因為下面要將其配置到worker裡
 */
public class MQTTSubscribe implements MqttCallback {

    //伺服器地址
    private String serverUrl = "你的伺服器IP:埠";

    //客戶端唯一標識
    private String clientid = "隨便起個名字";

    //訂閱主題
    private String subtopic = "你的訂閱主題";

    //使用者名稱
    private String username = "使用者名稱";

    //密碼
    private String password = "密碼";

    //傳輸質量:0至多一次;1至少一次;2確保只有一次。
    private int qos = 0;

    private MqttClient client;
    private MqttConnectOptions options;

    private MessageExecute messageExecute = new MessageExecute();

    //斷線重連,每10秒檢測一次
    void startReconnect() {
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new Runnable() {
            public void run() {
                if (!client.isConnected()) {
                    try {
                        client.connect(options);
                        System.out.println("我已斷線重連......");

                    } catch (MqttException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, 3 * 1000, 10 * 1000, TimeUnit.MILLISECONDS);
    }

    Boolean start() {
        try {
            client = new MqttClient(serverUrl, clientid, new MemoryPersistence());
            options = new MqttConnectOptions();
            options.setCleanSession(false);
            options.setUserName(username);
            options.setPassword(password.toCharArray());
            options.setConnectionTimeout(10);
            options.setKeepAliveInterval(20);
            options.setAutomaticReconnect(true);
            client.setCallback(this);
            client.connect(options);
            client.subscribe(subtopic, qos);

            System.out.println("MQTT訂閱設定初始化完畢!");
            return true;

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("MQTT訂閱設定初始化失敗!");
            return false;
        }
    }

    public void connectionLost(Throwable cause) {
        System.out.println("------------ mqtt connection lost. ------------");
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        try {
            System.out.println("------------ delivery complete ------------" + token.isComplete());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        String msg = new String(message.getPayload());
        System.out.println("------------ 已接收到資訊: ------------" + msg);
        
        //這裡開始處理你的業務
        //1、如果數量較大,可使用中介軟體暫存資訊,如:MQ
        //2、如果數量較小,可以使用非同步處理
        //TODO
    }
}

 

三、執行緒類

package com.xxxx.worker.controller.Server.MQTT;

/**
 * @title: 啟動一個執行緒
 * @author: hunttown
 * @date: 2020年10月17日 15:55
 * @description: 同樣要使用bean注入
 */
public class MQTTStrThread extends Thread {

    private static MQTTSubscribe mqttSubscribe;

    public void run() {

        //訂閱任務是否啟動
        boolean isStart = false;

        while (!isStart) {

            //啟動,如果執行緒先於伺服器啟動,是讀不到配置檔案的,這裡會報錯,那麼休眠60秒繼續。
            isStart = mqttSubscribe.start();

            //啟動成功
            if (isStart) {
                mqttSubscribe.startReconnect();
                System.out.println("MQTT訂閱任務啟動成功!");

            } else {
                System.out.println("MQTT訂閱任務啟動失敗,1分鐘後繼續重試!");

                try {
                    Thread.sleep(60 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static MQTTSubscribe getMqttSubscribe() {
        return mqttSubscribe;
    }

    public static void setMqttSubscribe(MQTTSubscribe mqttSubscribe) {
        MQTTStrThread.mqttSubscribe = mqttSubscribe;
    }
}

 

四、監聽類

package com.xxxx.worker.controller.TaskListener;

import com.xxxx.worker.controller.Server.MQTT.MQTTStrThread;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpServlet;

/**
 * @title: MQTT訊息監聽類
 * @author: wangjunfu
 * @date: 2020年10月17日 18:36
 * @description: 同樣是bean注入
 */
public class MQTTStrListener extends HttpServlet implements ServletContextListener {
    public void contextInitialized(ServletContextEvent arg0) {

        System.out.println("----------------- MQTT:String執行緒已啟動 --------------------------");

        MQTTStrThread thread = new MQTTStrThread();
        thread.setDaemon(true); //設定執行緒為後臺執行緒
        thread.start();
    }

    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO
    }
}

 

五、將監聽類配置到web.xml中

<listener>
    <!-- MQTT:接收String資料 -->
    <listener-class>com.xxxx.worker.controller.TaskListener.MQTTStrListener</listener-class>
</listener>

 

完畢! 

相關文章