application-iot.yml
mqtt:
# MQTT服务器地址,可以是多个地址
services: ssl://192.168.10.31:8883
# mqtt用户名,默认无
user: b
# mqtt密码,默认无
password: b1
# 是否自动重联,默认 false
isAutomaticReconnect: true
# 设置重连时间间隔(自动重连执行时最大延迟) 默认 128000
maxReconnectDelay: 120
# 连接超时时间 默认 30
connectionTimeout: 30
# 心跳间隔时间,默认 60 单位为秒,服务器定时向客户端发送请求来判断是否在线
keepAliveInterval: 60
# 消费超时时间 默认 30000L
completionTimeout: 30000
# 配置 最大传输中数,v3的数据类型为int默认值10,v5的数据类型为Integer默认值为null, qos!=0 时生效。 表示允许同时在传输中的最大消息数量
# MQTT 协议规定,在未收到 ACK 确认之前,客户端只能同时传输一定数量的消息。MaxInflight 指标用来控制该数量,以避免网络拥塞
maxInflight: 1000
# 通信质量,用了int的默认值 0
qos: 1
v3:
# v3 cleanSession是否清除会话 默认为true = 清除会话
# v3 Management -> Cluster Settings -> MQTT Settings -> Session 标签选项卡 可以设置 Session Expiry Interval
# ture =客户端和服务器必须丢弃任何先前的会话并创建一个新会话。该会话的生命周期将和网络连接保持一致,其会话状态一定不能被之后的任何会话重用。
# false = 避免客户端掉线重连后消息的丢失 ,消息的持久化,会导致服务器资源的浪费
isCleanSession: false
# 恢复时间的间隔 用了int的默认值 0
recoveryInterval: 10000
# 生产者——Id
producerId: v3_producer_outbound_01
# 消费者——Id
consumerId: v3_consumer_inbound_01
# 发布与订阅的默认主题
defaultTopic: v3/subscribe/test
v5:
# V5 cleanStart是否清除会话 默认为true = 清除会话
# true = 客户端和服务器必须丢弃任何先前的会话并创建一个新会话。该会话的生命周期将和网络连接保持一致,其会话状态一定不能被之后的任何会话重用。
# false = 避免客户端掉线重连后消息的丢失 ,消息的持久化,会导致服务器资源的浪费
isCleanStart: false
# V5 当cleanStart=false保留会话时,会话保留的时间 86400秒 = 1天
sessionExpiryInterval: 86400
# v5 自动重连执行时使用的最小延迟 默认 1
automaticReconnectMinDelay: 1
# v5 自动重连执行时使用的最大延迟 默认 120
automaticReconnectMaxDelay: 120
# 生产者——Id
producerId: v5_producer_outbound_01
# 消费者——Id
consumerId: v5_consumer_inbound_01
# 发布与订阅的默认主题
defaultTopic: v5/subscribe/test
MqttConfig.java
package com.lc.iot.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
@Data
public class MqttConfig {
@Value("${mqtt.services}")
private String[] services;
@Value("${mqtt.user}")
private String user;
@Value("${mqtt.password}")
private String password;
@Value("${mqtt.isAutomaticReconnect}")
private boolean isAutomaticReconnect;
@Value("${mqtt.maxReconnectDelay}")
private int maxReconnectDelay;
@Value("${mqtt.connectionTimeout}")
private int connectionTimeout;
@Value("${mqtt.keepAliveInterval}")
private int keepAliveInterval;
@Value("${mqtt.completionTimeout}")
private long completionTimeout;
@Value("${mqtt.maxInflight}")
private int maxInflight;
@Value("${mqtt.qos}")
private int qos;
@Value("${mqtt.v3.isCleanSession}")
private boolean isV3CleanSession;
@Value("${mqtt.v3.recoveryInterval}")
private int v3RecoveryInterval;
@Value("${mqtt.v3.producerId}")
private String v3ProducerId;
@Value("${mqtt.v3.consumerId}")
private String v3ConsumerId;
@Value("${mqtt.v3.defaultTopic}")
private String v3DefaultTopic;
@Value("${mqtt.v5.isCleanStart}")
private boolean isV5CleanStart;
@Value("${mqtt.v5.sessionExpiryInterval}")
private long v5SessionExpiryInterval;
@Value("${mqtt.v5.automaticReconnectMinDelay}")
private int v5AutomaticReconnectMinDelay;
@Value("${mqtt.v5.automaticReconnectMaxDelay}")
private int v5AutomaticReconnectMaxDelay;
@Value("${mqtt.v5.producerId}")
private String v5ProducerId;
@Value("${mqtt.v5.consumerId}")
private String v5ConsumerId;
@Value("${mqtt.v5.defaultTopic}")
private String v5DefaultTopic;
}
Mqtt3Client
package com.lc.iot.mqttv3;
import cn.hutool.core.util.IdUtil;
import com.lc.iot.config.MqttConfig;
import com.lc.iot.utils.SSLUtils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import javax.annotation.Resource;
@Configuration
@Slf4j
public class Mqtt3Client {
@Resource
private MqttConfig mc;
@Resource
private SSLUtils sslUtils;
@Resource
private Mqtt3MessageReceiver mqttMessageReceiver;
/**
* (生产者) mqtt消息出站通道,用于发送出站消息
* @return
*/
@Bean
public MessageChannel mqttOutputChannel3() {
return new DirectChannel();
}
/**
* (消费者) mqtt消息入站通道,订阅消息后消息进入的通道。
* @return
*/
@Bean
public MessageChannel mqttInputChannel3() {
return new DirectChannel();
}
public MqttConnectOptions getOptions() {
MqttConnectOptions options = new MqttConnectOptions();
options.setServerURIs(mc.getServices());
options.setUserName(mc.getUser());
options.setPassword(mc.getPassword().toCharArray());
options.setMaxInflight(mc.getMaxInflight());
options.setKeepAliveInterval(mc.getKeepAliveInterval());
// 重连设置
options.setAutomaticReconnect(mc.isAutomaticReconnect());
options.setMaxReconnectDelay(mc.getMaxReconnectDelay());
// options.setAutomaticReconnectDelay(automaticReconnectMinDelay, automaticReconnectMaxDelay);
// 会话设置
options.setCleanSession(mc.isV3CleanSession());
// 超时设置
options.setConnectionTimeout(mc.getConnectionTimeout());
// 设置遗嘱消息 qos 默认为 1 retained 默认为 false
options.setWill("willTopic","与服务器断开连接".getBytes(),0,false);
try {
options.setSocketFactory(sslUtils.getSocketFactory(
"classpath:ca.pem",
"classpath:client.pem",
"classpath:client.key",
""));
} catch (Exception e) {
e.printStackTrace();
}
return options;
}
/**
* 生产者
* @return
*/
@Bean
@ServiceActivator(inputChannel = "mqttOutputChannel3")
public MessageHandler mqttOutbound3() {
String clientId = mc.getV3ProducerId() + "_" + IdUtil.getSnowflakeNextId();
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory() ;
factory.setConnectionOptions(getOptions());
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(clientId, factory);
// 设置异步不阻塞
messageHandler.setAsync(true);
// 设置Qos
messageHandler.setDefaultQos(mc.getQos());
return messageHandler;
}
/**
* MQTT消息订阅绑定(消费者)
* @return
*/
@Bean
public MessageProducer channelInbound3(MessageChannel mqttInputChannel3) {
String clientId = mc.getV3ConsumerId() + "_" + IdUtil.getSnowflakeNextId();;
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
factory.setConnectionOptions(getOptions());
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(clientId, factory, mc.getV3DefaultTopic());
adapter.setCompletionTimeout(mc.getCompletionTimeout());
adapter.setRecoveryInterval(mc.getV3RecoveryInterval());
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setQos(mc.getQos());
adapter.setOutputChannel(mqttInputChannel3);
return adapter;
}
/**
* MQTT消息处理器(消费者)
* @return
*/
@Bean
@ServiceActivator(inputChannel = "mqttInputChannel3")
public MessageHandler mqttMessageHandler3() {
return mqttMessageReceiver;
}
}
Mqtt3Gateway
package com.lc.iot.mqttv3;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
@Component
@MessagingGateway(defaultRequestChannel = "mqttOutputChannel3")
public interface Mqtt3Gateway {
/**
* 定义重载方法,用于消息发送
* @param payload
*/
void sendToMqtt(String payload);
/**
* 指定topic进行消息发送
* @param topic
* @param payload
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload);
/**
* 指定topic进行消息发送
* @param topic
* @param qos
* @param payload
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);
/**
* 指定topic和消息保留时间进行消息发送
* @param topic
* @param qos
* @param messageExpiryInterval
* @param payload
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos,@Header(MqttHeaders.MESSAGE_EXPIRY_INTERVAL) Long messageExpiryInterval, String payload);
/**
* 指定topic进行消息发送
* @param topic
* @param qos
* @param payload
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, byte[] payload);
}
Mqtt3MessageReceiver
package com.lc.iot.mqttv3;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class Mqtt3MessageReceiver implements MessageHandler {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
String topic = String.valueOf(message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC));
String payload = String.valueOf(message.getPayload());
log.info("Mqtt3接收的消息: topic:{}, 消息体: {}", topic, message);
}
}