springboot集成mqtt

SpringBoot集成MQTT(简单版)

一、docker安装emqx环境(Linux系统)

emqx:mqtt服务器(broker)

version: '3'
services:
  emqx:
    image: emqx/emqx
    container_name: emqx
    restart: always
    ports:
      - 8001:18083
      - 8002:1883
      - 8003:8083
      - 8004:8084
      - 8005:8883

端口介绍:

1883 MQTT TCP 协议端口,发送报文就是走的这个端口
8883 MQTT/TCP SSL 端口
8083 MQTT/WebSocket 端口
8084 MQTT/WebSocket with SSL 端口
8080 MQTT执行引擎HTTP API 端口
18083 EMQX Dashboard 管理控制台端口

二、Java代码

1、配置文件
# MQTT配置信息
mqtt:
  # MQTT服务端地址,端口默认为1883,如果有多个,用逗号隔开
  url: tcp://ip:1883
  # 默认的用户名
  username: admin
  # 默认的密码
  password: public
  # 客户端id(不能重复)
  consumerClientId: consumer-13579
  providerClientId: provider-24680
  # MQTT默认的消息推送主题,实际可在调用接口时指定
  defaultTopic: topic1111111
2、配置类
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;


@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "mqtt")
@EnableConfigurationProperties(value = MqttProperties.class)
@Primary
public class MqttProperties {

    private String username;

    private String password;

    private String url;

    private String providerClientId;

    private String consumerClientId;

    private String defaultTopic;
}

3、MQTT客户端启动配置
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

@Configuration
@Slf4j
public class MqttConfig {

    @Resource
    private MqttProperties properties;

    @Resource
    private MqttConsumerCallBack consumerCallBack;

    /**
     * 客户端对象
     */
    private MqttClient providerClient;
    private MqttClient consumerClient;

    /**
     * 在bean初始化后连接到服务器
     */
    @PostConstruct
    public void init(){
        connectProvider();
        connectConsumer();
    }

    /**
     * 生产客户端连接服务端
     */
    public void connectProvider(){
//        try{
//            // 创建MQTT客户端对象-发布者
//            providerClient = new MqttClient(properties.getUrl(), properties.getProviderClientId(), new MemoryPersistence());
//            MqttConnectOptions options = getMqttConnectOptions();
//            // 服务器每次连接重新保存信息
//            options.setCleanSession(true);
//            // 设置回调
//            providerClient.setCallback(new MqttProviderCallBack());
//            providerClient.connect(options);
//        } catch(MqttException e){
//            log.error("mqtt发布端连接服务器失败", e);
//        }
    }

    /**
     * 消费客户端连接服务端
     */
    public void connectConsumer(){
        try {
            // 创建MQTT客户端对象-订阅者
            consumerClient = new MqttClient(properties.getUrl(), properties.getConsumerClientId(), new MemoryPersistence());
            MqttConnectOptions options = getMqttConnectOptions();
            // 服务器每次连接重新保存信息
            options.setCleanSession(true);
            // 设置回调,new的对象在spring中拿bean麻烦,这里直接初始化
            consumerClient.setCallback(consumerCallBack);
            // 设置自动重新连接,因为异常原因断开连接后进行重连
            options.setAutomaticReconnect(true);
            consumerClient.connect(options);
            // 订阅主题,消息等级,和主题数组一一对应,服务端将按照指定等级给订阅了主题的客户端推送消息
            consumerClient.subscribe(TopicDetails.topics, TopicDetails.qos);
            log.info("mqtt消费端与服务器连接成功");
        } catch (MqttException e) {
            log.error("mqtt消费端连接服务器失败", e);
        }
    }

    /**
     * 发布消息
     * @param qos
     * @param retained
     * @param topic
     * @param message
     */
    public void publish(int qos,boolean retained,String topic,String message){
        try {
            MqttMessage mqttMessage = new MqttMessage();
            mqttMessage.setQos(qos);
            mqttMessage.setRetained(retained);
            mqttMessage.setPayload(message.getBytes());
            // 主题的目的地,用于发布/订阅信息
            MqttTopic mqttTopic = providerClient.getTopic(topic);
            // 提供一种机制来跟踪消息的传递进度
            // 用于在以非阻塞方式(在后台运行)执行发布是跟踪消息的传递进度
            MqttDeliveryToken token;
            // 将指定消息发布到主题,但不等待消息传递完成,返回的token可用于跟踪消息的传递状态
            // 一旦此方法干净地返回,消息就已被客户端接受发布,当连接可用,将在后台完成消息传递。
            token = mqttTopic.publish(mqttMessage);
            token.waitForCompletion();
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取mqtt连接
     * @return
     */
    public MqttConnectOptions getMqttConnectOptions(){
        // 连接设置
        MqttConnectOptions options = new MqttConnectOptions();
        // 是否清空session,设置false表示服务器会保留客户端的连接记录(订阅主题,qos),客户端重连之后能获取到服务器在客户端断开连接期间推送的消息
        // 设置为true表示每次连接服务器都是以新的身份
        options.setCleanSession(true);
        // 设置连接用户名
        options.setUserName(properties.getUsername());
        // 设置连接密码
        options.setPassword(properties.getPassword().toCharArray());
        // 设置超时时间,单位为秒
        options.setConnectionTimeout(100);
        // 设置心跳时间 单位为秒,表示服务器每隔 1.5*20秒的时间向客户端发送心跳判断客户端是否在线
        options.setKeepAliveInterval(20);
        // 设置遗嘱消息的话题,若客户端和服务器之间的连接意外断开,服务器将发布客户端的遗嘱信息
        options.setWill("willTopic",(properties.getProviderClientId() + "与服务器断开连接").getBytes(),0,false);
        return options;
    }
}

/**
 * mqtt主题
 */
public class TopicDetails {

    public static final String[] topics = new String[]{
            // 此处添加topic,需要在下面的 qos 属性里面也要对应加一个
//            "topic_3/+/test",
            "topic_1",
            "topic_2"
    };

    public static final int[] qos = new int[]{
            // 此处数量保持和 topics 一致
            1,
            1
    };

    /**
     * 判断当前主题是否为我们需要的主题
     * @param topic
     * @return
     */
    public static boolean checkTopic(String topic){
        for (String s : topics) {
            if(s.equals(topic)){
                return true;
            }
        }
        return false;
    }

}

4、消费数据回调
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * mqtt数据消费回调
 */
@Component
@Slf4j
public class MqttConsumerCallBack implements MqttCallback{

	// 业务代码
    @Resource
    private IMqttService mqttService;
    @Resource
    private MqttConfig mqttConfig;

    /**
     * 客户端断开连接的回调
     */
    @Override
    public void connectionLost(Throwable throwable) {
        log.error("mqtt消费端与服务器断开连接:{}", throwable.getMessage());
        mqttConfig.connectConsumer();
    }

    /**
     * 消息到达的回调
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        String content = new String(message.getPayload());
        log.info("接收消息主题:{},接收消息内容:{}", topic, content);
//        System.out.println(String.format("接收消息主题 : %s",topic));
//        System.out.println(String.format("接收消息Qos : %d",message.getQos()));
//        System.out.println(String.format("接收消息内容 : %s",new String(message.getPayload())));
//        System.out.println(String.format("接收消息retained : %b",message.isRetained()));
        // 数据存储
        mqttService.senMessage(topic, content);
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        // 消息发布成功的回调,消费端无
    }
}

5、生产数据回调
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;

/**
 * mqtt生产发布消息回调
 */
@Slf4j
public class MqttProviderCallBack implements MqttCallback{

    /**
     * 客户端断开连接的回调
     */
    @Override
    public void connectionLost(Throwable throwable) {
        log.error("mqtt生产端与服务器断开连接,可重连");
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        // 消息到达的回调,发布端无
    }

    /**
     * 消息发布成功的回调
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        log.info(String.format("接收消息成功"));
    }
}

三、测试工具

推荐使用:MQTT.fx

posted @ 2024-01-30 18:44  窃窃私语QAQ  阅读(33)  评论(0编辑  收藏  举报