参考spring官方提供的教程:spring集成MQTT官方文档
以下代码均由自己封装,可能存在误差或遗漏,还望大佬指教。
环境版本
spring-boot 版本 2.4.3
spring-integration的版本为:5.4.3
Spring Integration提供了入站适配器和出站适配器以支持MQTT协议。
你需要在你的项目中加入spring-integration-mqtt依赖:
Maven:
<!-- https://mvnrepository.com/artifact/org.springframework.integration/spring-integration-mqtt -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-mqtt</artifactId> <version>5.4.3</version>
</dependency>
application.yml:
spring:
mqtt:
username:
password:
url: tcp://ip:port
clientId: clientId
topic: default
completionTimeout: 2000
核心代码
启动类
@SpringBootApplication @EnableCaching public class MqttApplication { public static void main(String[] args) { SpringApplication.run(MqttApplication.class, args); } }
配置项
@Data @Configuration @ConfigurationProperties(prefix = "spring.mqtt") public class MqttConfiguration { private String username; private String password; private String url; private String clientId; private String topic = "TOPIC_DEFAULT"; private Integer completionTimeout = 2000; /** * 注册MQTT客户端工厂 * @return */ @Bean public MqttPahoClientFactory mqttClientFactory(){ DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); MqttConnectOptions options = new MqttConnectOptions(); //如果设置为 false,客户端和服务器将在客户端、服务器和连接重新启动时保持状态。随着状态的保持: // 即使客户端、服务器或连接重新启动,消息传递也将可靠地满足指定的 QOS。服务器将订阅视为持久的。 // 如果设置为 true,客户端和服务器将不会在客户端、服务器或连接重新启动时保持状态。 options.setCleanSession(true); //该值以秒为单位,必须>0,定义了客户端等待与 MQTT 服务器建立网络连接的最大时间间隔。 // 默认超时为 30 秒。值 0 禁用超时处理,这意味着客户端将等待直到网络连接成功或失败。 options.setConnectionTimeout(0); //此值以秒为单位,定义发送或接收消息之间的最大时间间隔,必须>0 options.setKeepAliveInterval(90); //自动重新连接 options.setAutomaticReconnect(true); options.setUserName(this.getUsername()); options.setPassword(this.getPassword().toCharArray()); options.setServerURIs(new String[]{this.getUrl()}); factory.setConnectionOptions(options); return factory; } }
InboundConfiguration
/** * @author Jackpot * @version jdk1.8 * @date 2021/9/7 12:12 下午 * @description */ @Slf4j @AllArgsConstructor @Configuration @IntegrationComponentScan public class MqttInboundConfiguration { private MqttConfiguration mqttConfig; private MqttPahoClientFactory factory; private MqttMessageReceiver mqttMessageReceiver; /** * 此处可以使用其他消息通道 * Spring Integration默认的消息通道,它允许将消息发送给一个订阅者,然后阻碍发送直到消息被接收。 * * @return */ @Bean public MessageChannel mqttInBoundChannel() { return new DirectChannel(); } /** * 适配器, 两个topic共用一个adapter * 客户端作为消费者,订阅主题,消费消息 * * @param * @param * @return */ @Bean public MessageProducerSupport mqttInbound() { MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(mqttConfig.getClientId()+"-"+System.currentTimeMillis(), factory, mqttConfig.getTopic()); adapter.setCompletionTimeout(60000); adapter.setConverter(new DefaultPahoMessageConverter()); adapter.setRecoveryInterval(10000); adapter.setQos(0); adapter.setOutputChannel(mqttInBoundChannel()); return adapter; } /** * mqtt入站消息处理工具,对于指定消息入站通道接收到生产者生产的消息后处理消息的工具。 * * @return */ @Bean @ServiceActivator(inputChannel = "mqttInBoundChannel") public MessageHandler mqttMessageHandler() { return this.mqttMessageReceiver; } }
Receiver
@Slf4j @AllArgsConstructor @Component public class MqttMessageReceiver implements MessageHandler { @Override public void handleMessage(Message<?> message) throws MessagingException { try { MessageHeaders headers = message.getHeaders(); //获取消息Topic String receivedTopic = (String) headers.get(MqttHeaders.RECEIVED_TOPIC); log.info("[获取到的消息的topic :]{} ", receivedTopic); //获取消息体 String payload = (String) message.getPayload(); log.info("[获取到的消息的payload :]{} ", payload); //todo .... } catch (Exception e) { e.printStackTrace(); } } }
OutboundConfiguration
@Slf4j @AllArgsConstructor @Configuration public class MqttOutboundConfiguration { private MqttConfiguration mqttConfig; private MqttPahoClientFactory factory; @Bean public MessageChannel mqttOutboundChannel() { return new DirectChannel(); } @Bean @ServiceActivator(inputChannel = "mqttOutboundChannel") public MessageHandler mqttOutbound() { MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler( mqttConfig.getClientId()+"-"+System.currentTimeMillis() + System.currentTimeMillis(), factory); messageHandler.setDefaultQos(0); //开启异步 messageHandler.setAsync(true); messageHandler.setDefaultTopic(mqttConfig.getTopic()); return messageHandler; } }
Gateway
@Component @MessagingGateway(defaultRequestChannel = "mqttOutboundChannel") public interface MqttGateway { /** * 发送mqtt消息 * @param topic 主题 * @param payload 内容 * @return void * @author Jackpot * @date 2021/9/7 12:20 下午 */ void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload); /** * 发送包含qos的消息 * @param topic 主题 * @param qos 对消息处理的几种机制。 * * 0 表示的是订阅者没收到消息不会再次发送,消息会丢失。<br> * * 1 表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息。<br> * * 2 多了一次去重的动作,确保订阅者收到的消息有一次。 * @param payload 消息体 * @return void * @author Jackpot * @date 2021/9/7 12:21 下午 */ void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload); /** * 发送包含qos的消息 * @param topic 主题 * @param qos 对消息处理的几种机制。 * * 0 表示的是订阅者没收到消息不会再次发送,消息会丢失。<br> * * 1 表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息。<br> * * 2 多了一次去重的动作,确保订阅者收到的消息有一次。 * @param payload 消息体 * @return void * @author Jackpot * @date 2021/9/7 12:21 下午 */ void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, byte[] payload); }
sender
@Component @AllArgsConstructor public class MqttMessageSender { private MqttGateway mqttGateway; /** * 发送mqtt消息 * @param topic 主题 * @param message 内容 * @return void * @author Jackpot * @date 2021/9/7 12:20 下午 */ public void send(String topic, String message) { mqttGateway.sendToMqtt(topic, message); } /** * 发送包含qos的消息 * @param topic 主题 * @param qos 质量 * @param messageBody 消息体 * @return void * @author Jackpot * @date 2021/9/7 12:21 下午 */ public void send(String topic, int qos, JSONObject messageBody){ mqttGateway.sendToMqtt(topic, qos, messageBody.toString()); } /** * 发送包含qos的消息 * @param topic 主题 * @param qos 质量 * @param message 消息体 * @return void * @author Jackpot * @date 2021/9/7 12:21 下午 */ public void send(String topic, int qos, byte[] message){ mqttGateway.sendToMqtt(topic, qos, message); } }