SpringBoot集成RabbitMQ实现MQTT协议通讯

1、前言

RabbitMQ有两种协议,我们平时接触的消息队列是用的AMQP协议,而用在智能硬件中的是MQTT协议;本文中主要介绍MQTT实现。

2、依赖引用
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-mqtt</artifactId>
    <version>5.5.1</version>
</dependency>
<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>1.2.0</version>
</dependency>
3、application.yml配置
mqtt:
    username: admin
    password: Abc123!@#
    url: tcp://127.0.0.1:1883
    producer:
      topic: topic1
      clientId: clientId-001
    listener:
      clientId: listenerClientId-001
      topic: topic2
4、MQTT连接配置类
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;

/**
 * @Author: lizj
 * @CreateTime: 2024-01-29  13:43
 * @Description: TODO
 */
@Configuration
public class MqttConfig {
    @Value("${spring.mqtt.username}")
    private String username;

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

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


    @Bean
    public MqttConnectOptions getMqttConnectOptions() {
        MqttConnectOptions options = new MqttConnectOptions();
        // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,
        // 这里设置为true表示每次连接到服务器都以新的身份连接
        options.setCleanSession(true);
        // 设置连接的用户名
        options.setUserName(username);
        // 设置连接的密码
        options.setPassword(password.toCharArray());
        options.setServerURIs(new String[]{hostUrl});
        // 设置超时时间 单位为秒
        options.setConnectionTimeout(10);
        // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线,但这个方法并没有重连的机制
        options.setKeepAliveInterval(20);
        // 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
//        options.setWill("willTopic", WILL_DATA, 2, false);

        return options;
    }

    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        factory.setConnectionOptions(getMqttConnectOptions());
        return factory;
    }
}
5、生产者配置类
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.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;

/**
 * mqtt服务类
 * 一种基于发布/订阅(publish/subscribe)模式的轻量级通讯协议,通过订阅相应的主题来获取消息,
 * 是物联网(Internet of Thing)中的一个标准传输协议
 * @Author: lizj
 * @CreateTime: 2024-01-29  13:45
 * @Description: TODO
 */
@Configuration
public class MqttProducerConfig {

    public static final String CHANNEL_NAME_OUT = "mqttOutboundChannel";
    @Value("${spring.mqtt.producer.clientId}")
    private String ClientId;

    @Value("${spring.mqtt.producer.topic}")
    private String Topic;


    @Autowired
    MqttPahoClientFactory mqttClientFactory;

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

    /**
     * MQTT消息处理器(生产者)
     */
    @Bean
    @ServiceActivator(inputChannel = CHANNEL_NAME_OUT)
    public MessageHandler mqttOutbound() {
        MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(ClientId, mqttClientFactory);
        //设置默认的qos级别
        messageHandler.setDefaultQos(1);
        //保留标志的默认值。如果没有mqtt_retained找到标题,则使用它。如果提供了自定义,则不使用它converter。这里不启用
        messageHandler.setDefaultRetained(false);
        //设置发布的主题
        messageHandler.setDefaultTopic(Topic);
        //当 时true,调用者不会阻塞。相反,它在发送消息时等待传递确认。默认值为false(在确认交付之前发送阻止)。
        messageHandler.setAsync(false);
        //当 async 和 async-events 都为 true 时,会发出 MqttMessageSentEvent(请参阅事件)。它包含消息、主题、客户端库生成的messageId、clientId和clientInstance(每次连接客户端时递增)。当客户端库确认交付时,会发出 MqttMessageDeliveredEvent。它包含 messageId、clientId 和 clientInstance,使传递与发送相关联。任何 ApplicationListener 或事件入站通道适配器都可以接收这些事件。请注意,有可能在 MqttMessageSentEvent 之前接收到 MqttMessageDeliveredEvent。默认值为false。
        messageHandler.setAsyncEvents(false);
        return messageHandler;
    }
}
6、监听器配置类
import lombok.extern.slf4j.Slf4j;
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.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;

/**
 * ClientId是MQTT客户端的标识。MQTT服务端用该标识来识别客户端。因此ClientId必须是独立的。
 * clientID需为全局唯一。如果不同的设备使用相同的clientID同时连接物联网平台,那么先连接的那个设备会被强制断开。
 * @Author: lizj
 * @CreateTime: 2024-01-29  13:47
 * @Description: TODO
 */
@Configuration
@Slf4j
public class MqttListener {

    public static final String CHANNEL_NAME_IN = "mqttInboundChannel";

    @Value("${spring.mqtt.listener.clientId}")
    private String ClientId;

    @Value("${spring.mqtt.listener.topic}")
    private String ListenTopic;

    @Autowired
    MqttPahoClientFactory mqttClientFactory;

    /**
     * MQTT消息通道(消费者)
     */
    @Bean(name = CHANNEL_NAME_IN)
    public MessageChannel mqttInboundChannel() {
        return new DirectChannel();
    }

    /**
     * MQTT消息订阅绑定(消费者)
     */
    @Bean
    public MessageProducer inbound() {
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(ClientId, mqttClientFactory, ListenTopic);
        adapter.setCompletionTimeout(5000);
        adapter.setConverter(new DefaultPahoMessageConverter());
        adapter.setQos(1);
        adapter.setOutputChannel(mqttInboundChannel());
        return adapter;
    }

    /**
     * MQTT消息监听器(消费者)
     * MessageHandler: org.springframework:spring-messaging
     */
    @Bean
    @ServiceActivator(inputChannel = CHANNEL_NAME_IN)
    public MessageHandler handlerTest() {

        return message -> {
            try {
                String string = message.getPayload().toString();
                log.debug("接收到消息:" + string);
            } catch (MessagingException e) {
                e.printStackTrace();
                //logger.info(e.getMessage());
            }
        };
    }
}
7、消息发送接口
import com.ccse.semiphysical.config.MqttProducerConfig;
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;

/**
 * @Author: lizj
 * @CreateTime: 2024-01-29  13:48
 * @Description: TODO
 */
@Component
@MessagingGateway(defaultRequestChannel = MqttProducerConfig.CHANNEL_NAME_OUT)
public interface MqttSenderService {

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

    /**
     * 发送信息到MQTT服务器
     *
     * @param topic   主题
     * @param payload 消息主体
     */
    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload);

    /**
     * 发送信息到MQTT服务器
     *
     * qos:
     * 0 至多一次,数据可能丢失
     * 1 至少一次,数据可能重复
     * 2 只有一次,且仅有一次,最耗性能
     *
     * @param topic   主题
     * @param qos     服务质量
     * @param payload 消息主体
     */
    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);
}
8、MQTT控制器调用
import com.alibaba.fastjson2.JSONObject;
import com.ccse.semiphysical.service.MqttSenderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * @Author: lizj
 * @CreateTime: 2024-01-29  13:51
 * @Description: TODO
 */
@Slf4j
@RestController
public class MqttController {
    @Autowired
    private MqttSenderService iMqttSender;


    /**
     * 发送MQTT消息
     *
     * @param message 消息内容
     * @return 返回
     */
    @PostMapping(value = "/mqtt", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> sendMqtt(@RequestBody Map message) {
        log.debug("================生产MQTT消息================" + message);
        iMqttSender.sendToMqtt(JSONObject.toJSONString(message));
        return new ResponseEntity<>("OK", HttpStatus.OK);
    }


    /**
     * 发送MQTT消息
     *
     * @param message 消息内容
     * @return 返回
     */
    @PostMapping(value = "/mqttqos", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> sendMqtt2(@RequestBody Map message) {
        String topic = message.getOrDefault("topic", "").toString();
        log.debug("================生产MQTT消息================" + message);
        iMqttSender.sendToMqtt(topic, 2,JSONObject.toJSONString(message));
        return new ResponseEntity<>("OK", HttpStatus.OK);
    }
}
9、调用示例

10:55:37.212 [http-nio-9204-exec-1] DEBUG c.c.s.c.MqttController - [sendMqtt2,52] - ================生产MQTT消息================{topic=topic1, topic1=topic123123123}
10:55:37.676 [MQTT Call: listenerClientId-002] DEBUG c.c.c.j.c.MqttListener - [lambda$handlerTest$0,70] - 接收到消息JOB:{"topic":"topic1","topic1":"topic123123123"}

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值