springboot基于Spring Integration集成mqtt

之前springboot用传统连接的方法集成的mqtt,又当生成者又当消费者,经常出现等待来自服务器的响应时超时然后断开后重连也连不上,还出现订阅多个Topic有些Topic消息收不到,用以下方法集成后解决问题

1.依赖

<dependency>
	<groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-mqtt</artifactId>
</dependency>

2.配置

mqtt:
  host: tcp://192.168.0.2:1883
  username: admin
  password: 123456
  topics: mqtt/test/+/Ack,mqtt/test/basic
  qos: 0,0

3.配置类

@Data
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "mqtt")
public class MqttConfig {

    /**
     * 订阅的bean名称
     */
    public static final String CHANNEL_NAME_IN = "mqttInboundChannel";
    /**
     * 发布的bean名称
     */
    public static final String CHANNEL_NAME_OUT = "mqttOutboundChannel";

    /**
     * mqtt地址
     */
    private String host;

    /**
     * mqtt用户名
     */
    private String username;

    /**
     * mqtt密码
     */
    private String password;

    /**
     * 订阅
     */
    private String[] topics;

    private int[] qos;

    /**
     * 客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息
     */
    private static final byte[] WILL_DATA = "offline".getBytes();

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

    /**
     * MQTT客户端
     */
    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        factory.setConnectionOptions(getMqttConnectOptions());
        return factory;
    }

    /**
     * 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(
                MqttConstant.CLIENT_SUFFIX_PRODUCERS + IdUtils.fastSimpleUUID(),
                mqttClientFactory());
        //设置默认发送的topic
        //messageHandler.setDefaultTopic("mqtt/default");
        //messageHandler.setDefaultQos(1);        
        //异步发送消息
        messageHandler.setAsync(true);
        return messageHandler;
    }

    /**
     * MQTT消息订阅绑定(消费者)
     */
    @Bean
    public MessageProducer inbound() {
        // 可以同时消费(订阅)多个Topic
        MqttPahoMessageDrivenChannelAdapter adapter =
                new MqttPahoMessageDrivenChannelAdapter(
                        MqttConstant.CLIENT_SUFFIX_CONSUMERS + IdUtils.fastSimpleUUID(), mqttClientFactory(),
                        topics);
        adapter.setCompletionTimeout(5000);
        adapter.setConverter(new DefaultPahoMessageConverter());
        adapter.setQos(qos);
        // 设置订阅通道
        adapter.setOutputChannel(mqttInboundChannel());
        return adapter;
    }

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

    /**
     * MQTT消息处理器(消费者)
     */
    @Bean
    @ServiceActivator(inputChannel = CHANNEL_NAME_IN)
    public MessageHandler handler() {
        return new MqttMessageReceiver();
    }

4.常量类

public class MqttConstant {
    /**
     * 客户端id消费者后缀
     */
    public static final String CLIENT_SUFFIX_CONSUMERS = "consumers_";

    /**
     * 客户端id生产者后缀
     */
    public static final String CLIENT_SUFFIX_PRODUCERS = "producers_";
}

5.消费处理器

public class MqttMessageReceiver implements MessageHandler {

    /**
     * 消息处理
     *
     * @param message 消息
     * @throws MessagingException 消息异常
     */
    @Override
    public void handleMessage(Message<?> message) throws MessagingException {
        // 获取消息Topic
        MessageHeaders headers = message.getHeaders();
        String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString();
        log.info("[获取到的消息的topic]:{} ", topic);
        //当客户端接收到订阅的消息时
        String payload = (String) message.getPayload();
    }
}

6.生产者消息发送接口

@Component
@MessagingGateway(defaultRequestChannel = MqttConfig.CHANNEL_NAME_OUT)
public interface IMqttSender {
    /**
     * 发送信息到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);

}

7.其他事件

从Spring 4.2.2开始,当适配器成功订阅到主题了,MqttSubscribedEvent事件就会被触发。当连接失败触发MqttConnectionFailedEvent事件。这两个事件都能够被一个Bean通过实现ApplicationListener而接收到。另外,名为recoveryInterval的新属性控制适配器在失败后尝试重新连接的时间间隔。默认为10000毫秒(10秒)。

@Component
@Slf4j
public class MQTTSubscribedListener implements ApplicationListener<MqttSubscribedEvent> {
 
    @Override
    public void onApplicationEvent(MqttSubscribedEvent event) {
        log.debug("Subscribed Success: " + event.getMessage());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迷图羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值