代码改变世界

MQTT接收字符串(1/2)

2022-04-25 10:17  猎手家园  阅读(406)  评论(0编辑  收藏  举报

我们现在所使用的通讯硬件大多数都是以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>

 

完毕!