基于Spring Boot注解实现mqtt消息监听

一.注解定义

package 包名

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MqttListener {


    String topic();

    int qos() default 0;
}

 这里注解定义了订阅的主题topic,和qos级别;

qos有三个级别:

0  最多一次

  MQTT 中最简单的交付等级。在 QoS 0 下,消息发布后,对消息的投递没有任何确认或重传机制。这意味着消息可能会有丢失或传输失败的风险。适用于不需要可靠性且网络开销小的。

1 最少一次 

消息发布后,至少会被传递一次,但可能存在重复传递的情况。

2 仅一次

消息发布后,只会被传递一次,不会发生重复传递的情况。名字虽然是仅一次,但是却是网络开销最大的。

topic:

1.普通订阅

   格式为topic/subtopic格式,其中有#和+两个通配符,'+': 表示通配一个层级,例如 a/+,匹配 a/x, a/y。'#': 表示通配多个层级。例如 a/#,匹配 a/x, a/b/c/d

2.共享订阅

以 $share/<group-name> 为前缀的共享订阅是带群组的共享订阅:

group-name 可以为任意字符串,属于同一个群组内部的订阅者将以负载均衡接收消息,但 EMQX 会向不同群组广播消息。

例如,假设订阅者 s1,s2,s3 属于群组 g1,订阅者 s4,s5 属于群组 g2。那么当 EMQX 向这个主题发布消息 msg1 的时候:

  • EMQX 会向两个群组 g1 和 g2 同时发送 msg1

  • s1,s2,s3 中只有一个会收到 msg1

  • s4,s5 中只有一个会收到 msg1

示例前缀真实主题名
$share/abc/t/1$share/abc/t/1

其他的一些mqtt高级特性例如遗嘱消息,保留消息,主题重写可以参考文档

保留消息 | EMQX 5.0 文档

MQTT 最全教程:从入门到精通 | EMQ

二.创建连接

1.引入依赖

        <dependency>
            <groupId>org.eclipse.paho</groupId>
            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
            <version>1.2.5</version>
        </dependency>

 2.增加配置

mqtt:
  broker: ${MQTT_BROKER:地址}
  userName: ${MQTT_USERNAME:用户名}
  password: ${MQTT_PASSWORD:密码}
  caDir: ${MQTT_CA_DIR:ca证书}

 3.创建连接



import com.nis.mqtt.utils.SSLUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MqttConfig {

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

    @Value("${mqtt.userName:}")
    private String userName;

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

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

    @Bean
    public MqttClient init()
    {
        String clientId = MqttClient.generateClientId();
        // 持久化
        MemoryPersistence persistence = new MemoryPersistence();
        // MQTT 连接选项
        MqttConnectOptions connOpts = new MqttConnectOptions();
        // 设置认证信息
        connOpts.setUserName(userName);
        connOpts.setPassword(password.toCharArray());
        // 设置CA证书
        // 证书文件可以通过其他管理
        MqttClient client = null;
        try {
            connOpts.setSocketFactory(SSLUtils.getSingleSocketFactory(caDir));
            client = new MqttClient(broker, clientId, persistence);
            client.connect(connOpts);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return client;
    }
}

三.扫描自动订阅



import com.nis.mqtt.aspect.annotion.MqttListener;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;

@Configuration
public class MqttBeanProcessor implements BeanPostProcessor {

    @Autowired
    private MqttClient mqttClient;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> beanClass = bean.getClass();
        for (Method method : beanClass.getDeclaredMethods()) {
            if (method.isAnnotationPresent(MqttListener.class)) {
                MqttListener mqttListener = method.getAnnotation(MqttListener.class);
                String topic = mqttListener.topic();
                try {
                    mqttClient.subscribe(topic, mqttListener.qos(), (topic1, message) -> {
                        try {
                            method.invoke(bean, topic1, message);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
                } catch (MqttException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }
}

 四.如何使用

    @MqttListener(topic = "$share/g1/test/spring")
    public void onMessage(String topic, MqttMessage message) {
       // 实现逻辑
    }

五.写在最后

  如果只是学习开发,可以使用EMQX:用于物联网、车联网和工业物联网的企业级 MQTT 平台,服务器有免费额度可用。当然也有开源社区版自己部署。GitHub - emqx/emqx: The most scalable open-source MQTT broker for IoT, IIoT, and connected vehicles

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Integration提供了基于MQTT的适配器,可以很方便地集成MQTT协议到Spring应用程序中。下面是基于spring-integration-mqtt在生产环境中使用的步骤: 1. 添加依赖 在项目的pom.xml文件中,添加spring-integration-mqtt依赖: ```xml <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-mqtt</artifactId> <version>5.5.0</version> </dependency> ``` 2. 配置MQTT连接参数 在项目的配置文件中,添加MQTT连接参数: ```yaml spring: mqtt: url: tcp://localhost:1883 username: test password: test ``` 3. 配置MQTT消息通道 在Spring Integration中,可以使用`MessageChannel`来定义消息通道,下面是一个基本的MQTT消息通道配置: ```xml <int-mqtt:message-driven-channel-adapter id="mqttInboundAdapter" client-id="test" url="${spring.mqtt.url}" topics="test/topic" qos="1" channel="mqttInputChannel"> <int:poller fixed-delay="1000"/> </int-mqtt:message-driven-channel-adapter> <int:channel id="mqttInputChannel"/> ``` 4. 处理MQTT消息 在处理MQTT消息的地方,可以使用`@ServiceActivator`注解和`MessageHandler`接口来处理消息: ```java @Service public class MqttMessageHandler implements MessageHandler { @Override @ServiceActivator(inputChannel = "mqttInputChannel") public void handleMessage(Message<?> message) { String topic = message.getHeaders().get(MqttHeaders.TOPIC, String.class); String payload = message.getPayload().toString(); System.out.println("Received message - Topic: " + topic + ", Payload: " + payload); } } ``` 5. 发布MQTT消息 在需要发送MQTT消息的地方,可以使用`MessageChannel`来发送消息: ```java @Autowired private MessageChannel mqttOutputChannel; public void sendMessage() { mqttOutputChannel.send(MessageBuilder.withPayload("hello").setHeader(MqttHeaders.TOPIC, "test/topic").build()); } ``` 以上就是基于spring-integration-mqtt在生产环境中使用的步骤。需要注意的是,本文只是介绍了基本的MQTT使用方法,实际应用中还需要考虑消息质量、消息持久化等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值