springboot自动化配置mqtt,整合spring-integration-mqtt,连接多个mqtt,动态订阅主题

springboot自动化配置mqtt,整合spring-integration-mqtt,连接多个mqtt 

  • mqtt整合
    • 添加依赖
    • 添加配置
    • 工具类说明
    • 订阅消息
    • 发送消息

      mqtt整合
      最近有一个业务,要求连接多个非集群不同的mqtt服务,于是乎写了一个可根据配置动态配置的工具。starter-integration-mqtt整合了spring-integration-mqtt,只需添加配置,并实现消息订阅接口即可。可以实现订阅多个mqtt。
      github源码:https://github.com/aLiang-xyl/integration-mqtt

      添加依赖

      <dependency>
          <groupId>cn.xyliang</groupId>
      	<artifactId>integration-mqtt-starter</artifactId>
      	<version>0.0.2</version>
      </dependency>

      添加配置

    • mqtt:
        config: 
          channel1:                                          #通道名称,可自定义,订阅消息时需要该名称
            url: [tcp://host1:1883, tcp://host1:1883]        #mqtt的url
            topics: [topic1, topic2]                         #监听的主题,和qos一一对应
            qos: [1, 0]                                      #监听主题的qos,和主题一一对应
            username: admin                                  #用户名
            password: public                                 #密码
            timeout: 60                                      #连接超时时间,单位:秒
            kep-alive-interval: 60                           #心跳时间,单位:秒
            async: true                                      #发送消息时是否异步发送
            client-id-append-ip: true                        #是否在clientId后面追加本机ip,因为clientid是唯一值,集群环境下不能使用相同的clientid,追加ip可解决该问题
            consumer-client-id: consumer_client_test1        #consumer client id配置
            producer-client-id: producer_client_test1        #producer client id配置
            consumer-will:                                   #consumer遗嘱消息配置
              qos: 1                                         #遗嘱qos
              topic: will_topic                              #遗嘱主题
              payload: '{"id": "consumer_client_test1"}'     #遗嘱内容
              retained: false                                #是否发送保留消息
            producer-will:                                   #producer遗嘱消息配置
              qos: 1                                         #遗嘱qos
              topic: will_topic                              #遗嘱主题
              payload: '{"id": "producer_client_test1"}'     #遗嘱内容
              retained: false                                #是否发送保留消息
          channel2:                                          #通道名称,第二个配置
            url: [tcp://host1:1883, tcp://host1:1883]
            topics: [topic1, topic2]
            qos: [1, 0]
            username: admin
            password: public
            timeout: 60
            kep-alive-interval: 60
            async: true
            consumer-client-id: consumer_client_test2
            producer-client-id: producer_client_test2
            consumer-will: 
              qos: 1
              topic: will_topic
              payload: '{"id": "consumer_client_test2"}'
              retained: false
            producer-will: 
              qos: 1
              topic: will_topic
              payload: '{"id": "producer_client_test2"}'
              retained: false
      

      工具类说明

      MqttUtils工具类,用来发送mqtt消息

    • package cn.xyliang.mqtt.utils;
      
      import java.util.Collection;
      import java.util.HashMap;
      import java.util.Iterator;
      import java.util.Map;
      
      import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
      import org.springframework.integration.mqtt.support.MqttHeaders;
      import org.springframework.integration.support.MessageBuilder;
      import org.springframework.messaging.Message;
      
      import lombok.extern.log4j.Log4j2;
      
      /**
       * <p>
       * 描述: mqtt工具类,可以根据通道名称发送消息
       * </p>
       * 
       * @author xingyl
       * @date 2020-04-01 10:16:35
       */
      @Log4j2
      public class MqttUtils {
      
      	/**
      	 * qos 0
      	 */
      	public static final int QOS_0 = 0;
      	/**
      	 * qos 1
      	 */
      	public static final int QOS_1 = 1;
      	/**
      	 * qos 2
      	 */
      	public static final int QOS_2 = 2;
      
      	private final static Map<String, MqttPahoMessageHandler> HANDLER_MAP = new HashMap<>(16);
      	public final static String CHANNEL_NAME_SUFFIX = "MqttPahoMessageHandler";
      
      	/**
      	 * 存放handler
      	 * 
      	 * @param channelName
      	 * @param handler
      	 */
      	public static void put(String channelName, MqttPahoMessageHandler handler) {
      		HANDLER_MAP.put(channelName + CHANNEL_NAME_SUFFIX, handler);
      	}
      
      	/**
      	 * 发送消息
      	 * 
      	 * @param topic       要发送的主题
      	 * @param message     消息内容
      	 * @param qos         qos级别
      	 * @param channelName 发送到指定的通道
      	 */
      	public static void sendMessage(String topic, String message, int qos, String channelName) {
      		MqttPahoMessageHandler handler = getHandler(channelName);
      		Message<String> mqttMessage = MessageBuilder.withPayload(message).setHeader(MqttHeaders.TOPIC, topic)
      				.setHeader(MqttHeaders.QOS, qos).build();
      		handler.handleMessage(mqttMessage);
      	}
      
      	/**
      	 * 发送消息,默认qos级别为1
      	 * 
      	 * @param topic       要发送的主题
      	 * @param message     消息内容
      	 * @param channelName 发送到指定的通道
      	 */
      	public static void sendMessage(String topic, String message, String channelName) {
      		MqttPahoMessageHandler handler = getHandler(channelName);
      		Message<String> mqttMessage = MessageBuilder.withPayload(message).setHeader(MqttHeaders.TOPIC, topic)
      				.setHeader(MqttHeaders.QOS, QOS_1).build();
      		handler.handleMessage(mqttMessage);
      	}
      
      	/**
      	 * 发送消息
      	 * 
      	 * @param mqttMessage 消息
      	 * @param channelName 发送到指定的通道
      	 */
      	public static void sendMessage(Message<String> mqttMessage, String channelName) {
      		MqttPahoMessageHandler handler = getHandler(channelName);
      		handler.handleMessage(mqttMessage);
      	}
      
      	/**
      	 * 如果只有一个通道将使用该通道发送消息
      	 * 
      	 * @param topic
      	 * @param message
      	 * @param qos
      	 */
      	public static void sendMessage(String topic, String message, int qos) {
      		MqttPahoMessageHandler handler = getDefaultHeadler();
      		Message<String> mqttMessage = MessageBuilder.withPayload(message).setHeader(MqttHeaders.TOPIC, topic)
      				.setHeader(MqttHeaders.QOS, qos).build();
      		handler.handleMessage(mqttMessage);
      	}
      
      	/**
      	 * 如果只有一个通道将使用该通道发送消息,默认qos级别为1
      	 * 
      	 * @param topic
      	 * @param message
      	 */
      	public static void sendMessage(String topic, String message) {
      		MqttPahoMessageHandler handler = getDefaultHeadler();
      		Message<String> mqttMessage = MessageBuilder.withPayload(message).setHeader(MqttHeaders.TOPIC, topic)
      				.setHeader(MqttHeaders.QOS, QOS_1).build();
      		handler.handleMessage(mqttMessage);
      	}
      
      	/**
      	 * 如果只有一个通道将使用该通道发送消息,默认qos级别为1
      	 * 
      	 * @param mqttMessage 消息信息
      	 */
      	public static void sendMessage(Message<String> mqttMessage) {
      		MqttPahoMessageHandler handler = getDefaultHeadler();
      		handler.handleMessage(mqttMessage);
      	}
      
      	/**
      	 * 获取默认的handler
      	 * 
      	 * @return
      	 */
      	private static MqttPahoMessageHandler getDefaultHeadler() {
      		Collection<MqttPahoMessageHandler> values = HANDLER_MAP.values();
      		Iterator<MqttPahoMessageHandler> iterator = values.iterator();
      		MqttPahoMessageHandler handler = iterator.next();
      		if (handler == null) {
      			log.error("发送消息失败,无可用的headler");
      			throw new RuntimeException("发送消息失败,无可用的headler");
      		}
      		return handler;
      	}
      
      	/**
      	 * 根据通道获取handler
      	 * 
      	 * @param channelName
      	 * @return
      	 */
      	private static MqttPahoMessageHandler getHandler(String channelName) {
      		MqttPahoMessageHandler handler = HANDLER_MAP.get(channelName + CHANNEL_NAME_SUFFIX);
      		if (handler == null) {
      			log.error("未查询到相应通道{}的handler,存在的通道名称{}", channelName, HANDLER_MAP.keySet());
      			throw new IllegalArgumentException("未查询到相应通道" + channelName + "的handler");
      		}
      		return handler;
      	}
      }
      
      
      

      订阅消息

      订阅消息需要实现MessageHandler接口
      注意:@ServiceActivator(inputChannel = "channel1")中的配置必须和yml配置文件里的channel保持一致,一个channel配置对应一个MessageHandler接口实现。

    • import org.springframework.integration.annotation.ServiceActivator;
      import org.springframework.messaging.Message;
      import org.springframework.messaging.MessageHandler;
      import org.springframework.messaging.MessagingException;
      import org.springframework.stereotype.Component;
      
      import lombok.extern.log4j.Log4j2;
      
      /**
       * <p>描述:配置channel1消息处理 </p>
       * 
       * @author xingyl
       * @date 2020年3月27日 下午6:33:35
       */
      @Log4j2
      @Component
      public class MqttMessageHandler implements MessageHandler {
      	
      	@ServiceActivator(inputChannel = "channel1")
      	@Override
      	public void handleMessage(Message<?> message) throws MessagingException {
      		log.info("收到消息---{}", message);
      	}
      
      }
      

      配置中每一个channel对应一个MessageHandler实现

      发送消息

      MqttUtils工具类中封装了多个发送消息的方法

      github源码:https://github.com/aLiang-xyl/integration-mqtt

      ————————————————
      版权声明:本文为CSDN博主「阿良~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
      原文链接:https://blog.csdn.net/qq_20280007/article/details/105250986

Spring Boot 应用程序中集成 Spring Integration MQTT 的步骤与在普通的 Spring 应用程序中类似。下面是一个示例代码,演示了如何在 Spring Boot 应用程序中使用 MQTT 子协议实现多个主题订阅。 首先,需要在 `application.properties` 文件中配置 MQTT 连接信息和要订阅主题列表: ``` mqtt.url=tcp://localhost:1883 mqtt.username=user mqtt.password=pass mqtt.topics=topic1,topic2,topic3 mqtt.qos=2 ``` 接下来,可以在 Spring Boot 应用程序中定义一个 MQTT 输入通道和一个消息处理器: ```java @Configuration @EnableIntegration public class MqttIntegrationConfig { @Value("${mqtt.url}") private String mqttUrl; @Value("${mqtt.username}") private String mqttUsername; @Value("${mqtt.password}") private String mqttPassword; @Value("${mqtt.topics}") private String mqttTopics; @Value("${mqtt.qos}") private int mqttQos; @Bean public MqttPahoClientFactory mqttClientFactory() { DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); factory.setServerURIs(mqttUrl); factory.setUserName(mqttUsername); factory.setPassword(mqttPassword); return factory; } @Bean public MessageChannel mqttInputChannel() { return new DirectChannel(); } @Bean public MessageProducer inbound() { MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter("mqttInbound", mqttClientFactory(), mqttTopics.split(",")); adapter.setCompletionTimeout(5000); adapter.setConverter(new DefaultPahoMessageConverter()); adapter.setQos(mqttQos); return adapter; } @Bean public MessageHandler mqttMessageHandler() { return new MqttMessageHandler(); } public class MqttMessageHandler implements MessageHandler { @Override public void handleMessage(Message<?> message) throws MessagingException { // 处理接收到的消息 } } } ``` 在这个示例中,我们定义了一个 MQTT 客户端工厂 `mqttClientFactory()`,用于创建 MQTT 连接,根据配置文件中的 `mqtt.url`、`mqtt.username` 和 `mqtt.password` 属性来设置 MQTT 服务器的 URL、用户名和密码。`mqttInputChannel()` 是一个直接通道,用于接收 MQTT 消息。`inbound()` 是一个消息驱动的通道适配器,用于从 MQTT 代理服务器接收消息。`mqttTopics` 属性设置了要订阅主题列表,`mqttQos` 属性设置了消息的服务质量。`mqttMessageHandler()` 是一个消息处理器,用于处理接收到的 MQTT 消息。 最后,在 `MqttMessageHandler` 类中实现 `handleMessage()` 方法,用于处理接收到的消息。 总之,以上是一个简单的示例,演示了如何在 Spring Boot 应用程序中使用 MQTT 子协议实现多个主题订阅。需要注意的是,要在 `@Configuration` 类上使用 `@EnableIntegration` 注解,以启用 Spring Integration
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值