关于spring boot集成MQTT的一写新人问题

这几天弄了下mqtt ,发现有很多问题,网上搜不到什么解决办法,所以自己记录下来,也让初识mqtt的人少走一些坑,关于我写的不对的也希望看到的人能指出来互相学习下

安装

说到mqtt,首先肯定要安装了,安装什么的地址:http://activemq.apache.org/ap...
我本地是Windows的环境,所以装的是Windows版本,这里是第一个注意的地方,因为后面使用的时候windows和linux的有一些不同

下载完成之后就是解压安装了,这里解压完成之后进入bin目录下,自己用cmd或者直接进去在此处打开命令窗口也行,然后运行apollo.cmd 创建一个服务实例我的实例名称是mybroker所以命令是 apollo.cmd create mybroker,这个名称自己可以随便指定

创建完实例后发现bin 目录下多了一个文件夹,这个文件夹就是你实例名称,进入文件夹运行
.apollo-broker.cmd run 命令
clipboard.png
这样就启动成功了

启动成功可以去http://localhost:61680/console/index.html看看,登录账号和密码在mybrokeretcusers.properties文件中找到输入就可以进去了

clipboard.png

页面上有连接信息和订阅主题的一些对应信息,有兴趣的自己看下,后面也会讲到的

使用

安装成功接下来就是使用了,首先创建一个maven工程,引入配置

    <!--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>

由于我们后面处理订阅消息的消费者打印的日志是用了slf4j为了方便也引入了lombok的配置 :

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

引入完成以后就可以开始准备开始使用mqtt了
这里为了方便维护和配置我把一些配置参数放在了properties文件里面:

#MQTT配置信息

spring.mqtt.username=admin

spring.mqtt.password=password

spring.mqtt.url=tcp://localhost:61613

spring.mqtt.client.id=clientId

spring.mqtt.server.id=serverId

spring.mqtt.default.topic=topic

这里我遇到了一个坑,专门注释了,就是订阅端订阅消息的id 和 发布端发布消息的id 一定不能一样,这样会导致mqtt识别到两个一样的id,消息一发就断开连接了,订阅端总是收不到消息,这个问题我找了好长时间都不知道问题出在哪,刚接触的很容易搞错,第二个问题就是mqtt的服务器连接地址,在Windows和linux下tcp的端口是不一样的,在启动的apollo的日志中可以看出来
clipboard.png

监听的tcp端口是61613,看别人很多的demo上都是1883,如果一直连不上,原因可能是因为这个

接下来就是spring.mqtt.default.topic 配置了,这个是mqtt订阅和推送的消息主题,既然你想发消息那么订阅消息的主题和发布消息的主题一致才能收到消息,和rabbitmq一样

然后就是客户端

@Configuration
@IntegrationComponentScan
@Slf4j
public class MqttSenderConfig {

    @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;

    @Bean
    public MqttConnectOptions getMqttConnectOptions(){
        MqttConnectOptions mqttConnectOptions=new MqttConnectOptions();
        mqttConnectOptions.setUserName(username);
        mqttConnectOptions.setPassword(password.toCharArray());
        mqttConnectOptions.setServerURIs(new String[]{hostUrl});
        mqttConnectOptions.setKeepAliveInterval(2);
        return mqttConnectOptions;
    }

    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        factory.setConnectionOptions(getMqttConnectOptions());
        return factory;
    }

    @Bean
    @ServiceActivator(inputChannel = "mqttOutboundChannel")
    public MessageHandler mqttOutbound() {
        MqttPahoMessageHandler messageHandler =  new MqttPahoMessageHandler(clientId, mqttClientFactory());
        messageHandler.setAsync(true);
        messageHandler.setDefaultTopic(defaultTopic);
        return messageHandler;
    }

    @Bean
    public MessageChannel mqttOutboundChannel() {
        return new DirectChannel();
    }
  }  
  

这里有点问题,如果你是复制我的代码的话MessageHandler 这个类是没有的需要自己手动导包,看了源码发现这里需要的是一个消息处理的handler需要是org.springframework.messaging.MessageHandler的实现,直接导入这个包就行了

@Component
@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
public interface MsgWriter {

    void sendToMqtt(String data);
    void sendToMqtt(String payload,@Header(MqttHeaders.TOPIC) String topic);
    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);

}

这个是消息发送接口,需要发送消息的时候直接调用就行了,提供了几个重载方法payload或者data是发送消息的内容
topic是消息发送的主题,这里可以自己灵活定义,也可以使用默认的主题,就是配置文件的主题,qos是mqtt 对消息处理的几种机制分为0,1,2 其中0表示的是订阅者没收到消息不会再次发送,消息会丢失,1表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息,2相比多了一次去重的动作,确保订阅者收到的消息有一次
当然,这三种模式下的性能肯定也不一样,qos=0是最好的,2是最差的 ,有兴趣的可以去详细了解我在这不多赘述

上面就完成了消息的发送,可以去http://localhost:61680/console/index.html看看消息的记录,这里我写了一个接口调用sendToMqtt方法发送一条消息

clipboard.png

会看到收到有两个主题,我的是因为我订阅了两个主题所以上面显示的是两个,我的刚才发布消息的主题是too所以打开会看到too有消息送达过来

clipboard.png

如果你还没写订阅方的话consumers是没有的,现在显示我发了7条消息,证明发送成功了

接下来就是订阅方,为了方便我就直接写在启动类上了,没有用到所有的配置

@SpringBootApplication
@EnableAutoConfiguration
public class MytestApplication {

    public static void main(String[] args) {
        SpringApplication.run(MytestApplication.class, args);
    }


    @Value("${spring.mqtt.server.id}")
    private String serverId;

    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        factory.setServerURIs("tcp://localhost:61613");
        factory.setUserName("admin");
        factory.setPassword("password");
        return factory;
    }

//     consumer 订阅者监听消息

    @Bean
    public IntegrationFlow mqttInFlow() {
        return IntegrationFlows.from(mqttInbound())
                .transform(p -> p + ", received from MQTT")
                .handle(logger())
                .get();
    }

    private LoggingHandler logger() {
        LoggingHandler loggingHandler = new LoggingHandler("INFO");
        loggingHandler.setLoggerName("siSample");
        return loggingHandler;
    }

    @Bean
    public MessageProducerSupport mqttInbound() {
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(serverId,
                mqttClientFactory(), "too");
        adapter.setCompletionTimeout(5000);
        adapter.setConverter(new DefaultPahoMessageConverter());
        adapter.setQos(1);
        return adapter;
    }

}

这里订阅的主题可以指定,我订阅的是刚才发的too主题,还有订阅方的id 别和发送方的id 一样
重新启动项目,发送消息,会发现控制台已经打印出消息

clipboard.png

代表订阅方已经成功收到消息,同时

clipboard.png

也显示消息订阅方和记录,至此一个完整的消息发送和订阅完成,比较简单,但是一不留神很容易出现问题,希望能帮助到新入门的人

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot集成MQTT可以通过使用 Eclipse Paho MQTT 客户端库来实现。以下是一个基本的步骤: 1. 添加依赖:在项目的 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>org.eclipse.paho</groupId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId> <version>1.2.5</version> </dependency> ``` 2. 创建MQTT配置:创建一个配置类,用于配置MQTT连接参数,例如服务器地址、端口号、客户端ID等。可以使用 Spring Boot 的配置文件来设置这些参数。 ```java @Configuration public class MqttConfig { @Value("${mqtt.broker}") private String broker; @Value("${mqtt.clientId}") private String clientId; @Bean public MqttClient mqttClient() throws MqttException { MqttClient mqttClient = new MqttClient(broker, clientId); return mqttClient; } } ``` 3. 创建MQTT消息处理类:创建一个消息处理类,用于定义收到消息时的处理逻辑。 ```java @Component public class MqttMessageHandler implements MqttCallback { // 处理收到的消息 @Override public void messageArrived(String topic, MqttMessage message) throws Exception { // 处理收到的消息逻辑 System.out.println("Received message: " + new String(message.getPayload())); } // 其他回调方法省略... } ``` 4. 创建MQTT消息订阅者:创建一个订阅者类,用于订阅特定的主题,并设置消息处理类。 ```java @Component public class MqttSubscriber { @Autowired private MqttClient mqttClient; @Autowired private MqttMessageHandler messageHandler; public void subscribe(String topic) throws MqttException { mqttClient.setCallback(messageHandler); mqttClient.connect(); mqttClient.subscribe(topic); } } ``` 5. 启动订阅:在Spring Boot应用的入口类中,注入订阅者类,并调用订阅方法启动消息订阅。 ```java @SpringBootApplication public class MyApplication implements CommandLineRunner { @Autowired private MqttSubscriber mqttSubscriber; public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } @Override public void run(String... args) throws Exception { mqttSubscriber.subscribe("my/topic"); } } ``` 这样,当有消息发布到 "my/topic" 主题时,消息处理类中的 `messageArrived` 方法将会被调用,你可以在其中编写自己的处理逻辑。 请确保在配置文件中正确设置了MQTT服务器地址、端口号、客户端ID等参数。另外,还需要处理MQTT连接、异常等的错误情况。以上只是一个简单的示例,你可以根据自己的需求进行进一步的扩展和定制。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值