SpringBoot 整合MQTT發佈和訂閱消息處理

關於一些介紹接不多少了,都可以百度的到

第一:EMQ服務的安裝

集成mqtt少不了服務器,雖然有很多種的mqtt的服務器,這裏我選擇的是EMQ服務器
Windows下emq安裝:https://blog.csdn.net/qq_40821260/article/details/106020962

第二:成果圖

 

第三:代碼實現

1,pom文件

    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.68</version>
        </dependency>

        <!--mqtt依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-integration</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-stream</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-mqtt</artifactId>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

2,yml文件

server:
  port: 8023
spring:
  #給項目來個名字
  application:
    name: mqtt
  #MQTT-用戶名
  mqtt:
    username: admin
    #MQTT-密碼password: password
    password: public
    #MQTT-服務器連接地址,如果有多個,用逗號隔開,如:tcp://127.0.0.1:1883,tcp://192.168.2.133:1883
    url: tcp://127.0.0.1:1883
    #MQTT-連接服務器默認客戶端ID
    client:
      id: mqttId
    #MQTT-默認的消息推送主題,實際可在調用接口時指定
    default:
      topic: topic
      yihonWQM: YIHON_WQ_M
    #連接超時
    completionTimeout: 3000

3,MqttSenderAndReceiveConfig推送接受消息類

package com.zxk.mqtt.configuration;

import com.alibaba.fastjson.JSONObject;
import com.zxk.mqtt.handle.MqttReceiveHandle;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.IntegrationComponentScan;
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;

/**
 *  mqtt 推送and接收 消息類
 * **/
@Configuration
@IntegrationComponentScan
@Slf4j
public class MqttSenderAndReceiveConfig {

    private static final byte[] WILL_DATA;

    static {
        WILL_DATA = "offline".getBytes();
    }

    @Autowired
    private MqttReceiveHandle mqttReceiveHandle;

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

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

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

    @Value("${spring.mqtt.client.id}")
    private String clientId;

    @Value("${spring.mqtt.default.topic}")
    private String defaultTopic;
    //水質設備主題
    @Value("${spring.mqtt.default.yihonWQM}")
    private String yihonWQM;

    @Value("${spring.mqtt.completionTimeout}")
    private int completionTimeout;   //連接超時

    /**
     *  MQTT連接器選項
     * **/
    @Bean(value = "getMqttConnectOptions")
    public MqttConnectOptions getMqttConnectOptions1(){
        MqttConnectOptions mqttConnectOptions=new MqttConnectOptions();
        // 設置是否清空session,這裏如果設置爲false表示服務器會保留客戶端的連接記錄,這裏設置爲true表示每次連接到服務器都以新的身份連接
        mqttConnectOptions.setCleanSession(true);
        // 設置超時時間 單位爲秒
        mqttConnectOptions.setConnectionTimeout(10);
        mqttConnectOptions.setAutomaticReconnect(true);
        mqttConnectOptions.setUserName(username);
        mqttConnectOptions.setPassword(password.toCharArray());
        mqttConnectOptions.setServerURIs(new String[]{hostUrl});
        // 設置會話心跳時間 單位爲秒 服務器會每隔1.5*20秒的時間向客戶端發送心跳判斷客戶端是否在線,但這個方法並沒有重連的機制
        mqttConnectOptions.setKeepAliveInterval(10);
        // 設置“遺囑”消息的話題,若客戶端與服務器之間的連接意外中斷,服務器將發佈客戶端的“遺囑”消息。
        //mqttConnectOptions.setWill("willTopic", WILL_DATA, 2, false);
        return mqttConnectOptions;
    }

    /**
     * MQTT工廠
     * **/
    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        factory.setConnectionOptions(getMqttConnectOptions1());
        return factory;
    }

    /**
     * MQTT信息通道(生產者)
     * **/
    @Bean
    public MessageChannel mqttOutboundChannel() {
        return new DirectChannel();
    }

    /**
     * MQTT消息處理器(生產者)
     * **/
    @Bean
    @ServiceActivator(inputChannel = "mqttOutboundChannel")
    public MessageHandler mqttOutbound() {
        MqttPahoMessageHandler messageHandler =  new MqttPahoMessageHandler(clientId, mqttClientFactory());
        messageHandler.setAsync(true);
        messageHandler.setDefaultTopic(defaultTopic);
        return messageHandler;
    }

    /**
     * 配置client,監聽的topic
     * MQTT消息訂閱綁定(消費者)
     * **/
    @Bean
    public MessageProducer inbound() {
        MqttPahoMessageDrivenChannelAdapter adapter =
                new MqttPahoMessageDrivenChannelAdapter(clientId + "_inbound1", mqttClientFactory(),
                        defaultTopic,yihonWQM);
        adapter.setCompletionTimeout(completionTimeout);
        adapter.setConverter(new DefaultPahoMessageConverter());
        adapter.setQos(2);
        adapter.setOutputChannel(mqttInputChannel());
        return adapter;
    }
    /**
     * MQTT信息通道(消費者)
     * **/
    @Bean
    public MessageChannel mqttInputChannel() {
        return new DirectChannel();
    }
    /**
     * MQTT消息處理器(消費者)
     * **/
    @Bean
    @ServiceActivator(inputChannel = "mqttInputChannel")
    public MessageHandler handler() {
        return new MessageHandler() {
            @Override
            public void handleMessage(Message<?> message) throws MessagingException {
                //處理接收消息
                mqttReceiveHandle.handle(message);
            }
        };
    }
}

4,MqttGateway發送消息類

package com.zxk.mqtt.configuration;

import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;

/**
 * mqtt發送消息
 * (defaultRequestChannel = "mqttOutboundChannel" 對應config配置)
 * **/
@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
public interface MqttGateway {

    /**
     * 發送信息到MQTT服務器
     *
     * @param data 發送的文本
     */
    void sendToMqtt(String data);

    /**
     * 發送信息到MQTT服務器
     *
     * @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);
}

5,Controller控制

package com.zxk.mqtt.controller;


import com.zxk.mqtt.configuration.MqttGateway;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@RequestMapping("/test")
public class MqttTestController {

    @Resource
    private MqttGateway mqttGateway;

    /**
     * sendData 消息
     * topic 訂閱主題
     * **/
    @RequestMapping("/sendMqtt1")
    public String sendMqtt(String sendData, String topic){


        mqttGateway.sendToMqtt(topic, sendData);
        return "OK";
    }

    /**
     * sendData 消息
     * qos 消息級別 (對應QOS0、QOS1,QOS2)
     * topic 訂閱主題
     * **/
    @RequestMapping("/sendMqtt2")
    public String sendMqtt(String  sendData, int qos, String topic){


        mqttGateway.sendToMqtt(topic, qos, sendData);
        return "OK";
    }
}

6,mqtt客戶端消息處理類

package com.zxk.mqtt.handle;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;

/**
 * mqtt客戶端消息處理類
 * **/
@Slf4j
@Component
public class MqttReceiveHandle {

    public void handle(Message<?> message){
        log.info("主題:{},QOS:{},消息接收到的數據:{}", message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC), message.getHeaders().get(MqttHeaders.RECEIVED_QOS), message.getPayload());
    }
}

7,測試發送 接受消息 (由於本推送和接受消息 是寫在一起的,所以推送和接收是可以同時看到的)

 

 

至此mqtt推送消息端和客戶端編寫完畢。

 

mqtt常用的客戶端測試工具:

通信貓調試助手:http://www.tongxinmao.com/Topic/Detail/id/6

 

MQTT.fx 是目前主流的mqtt客戶端:

官網:http://mqttfx.jensd.de/index.php/download

國內鏡像:http://mqttfx.bceapp.com/

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