概念:
MQTT是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。MQTT是专门针对物联网开发的轻量级传输协议。MQTT协议针对低带宽网络,低计算能力的设备,做了特殊的优化,使得其能适应各种物联网应用场景。目前MQTT拥有各种平台和设备上的客户端,已经形成了初步的生态系统。
1、MQTT更加简单
MQTT是一种消息队列协议,使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合,相对于其他协议,开发更简单;
2、MQTT网络更加稳定
工作在TCP/IP协议上;由TCP/IP协议提供稳定的网络连接;
3、轻量级
小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量;适合低带宽,数据量较小的应用;
4、易于实现
MQTT协议的服务端程序已经非常成熟,PHP,JAVA,Python,C,C#等系统语言都可以来向MQTT发送相关消息;
5、开放性
源代码开放,都可以用,也进一步推动了MQTT的发展,百度云、阿里云、中国移动onenet等几乎所有的开放性物联网平台都支持MQTT;
以上都是复制粘贴!!!
下文直接上代码!!!
StringBoot集成MQTT步骤:
一、引入pom依赖
<!-- mqtt 配置 -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
二、加入配置
application.yml
spring:
mqtt:
username: taida
password: taida123456
hostUrl: tcp://192.168.0.1:1883
clientId: ${random.value} #客户端ID
topic: xxx/data #默认的TOPIC
completionTimeout: 5000 #超时时间,单位是秒
timeout: 20 #超时时间 单位s
keepAlive: 20 #心跳的间隔
三、加入代码
MqttGateway(发送消息)
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
public interface MqttGateway {
/**
* 发送信息到MQTT服务器
*
* @param data 发送的文本
*/
void sendToMqtt(String data);
/**
* 发送信息到MQTT服务器
*
* @param topic 主题
* @param payload 消息主体
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic,
String payload);
/**
* 发送信息到MQTT服务器
*
* @param topic 主题
* @param qos 对消息处理的几种机制。
* 0 表示的是订阅者没收到消息不会再次发送,消息会丢失。
* 1 表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息。
* 2 多了一次去重的动作,确保订阅者收到的消息有一次。
* @param payload 消息主体
*/
MqttDeliveryToken sendToMqtt(@Header(MqttHeaders.TOPIC) String topic,
@Header(MqttHeaders.QOS) int qos,
String payload);
}
MqttConfig(mqtt 推送and接收 消息类)
import java.util.Objects;
import javax.annotation.PostConstruct;
import lombok.Data;
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.IntegrationComponentScan;
import org.springframework.beans.factory.annotation.Value;
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.core.MqttPahoClientFactory;
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;
/**
* mqtt 推送and接收 消息类
**/
@Slf4j
@Configuration
@IntegrationComponentScan
@Data
public class MqttConfig {
private static final byte[] WILL_DATA;
static {
WILL_DATA = "offline".getBytes();
}
//
public static final String SUB_TOPICS = "taidai,taidai/sub";
@Value("${spring.mqtt.hostUrl}")
private String hostUrl;
@Value("${spring.mqtt.username}")
private String username;
@Value("${spring.mqtt.password}")
private String password;
@Value("${spring.mqtt.clientId}")
private String clientId;
@Value("${spring.mqtt.timeout}")
private int timeOut;
@Value("${spring.mqtt.keepalive}")
private int keepAlive;
@Value("${spring.mqtt.topic}")
private String defaultTopic;
@PostConstruct
public void init() {
log.debug("username:{} password:{} hostUrl:{} clientId :{} ",
this.username, this.password, this.hostUrl, this.clientId, this.defaultTopic);
}
/**
* MQTT 工厂
* @return
*/
@Bean
public MqttPahoClientFactory clientFactory() {
final MqttConnectOptions options = new MqttConnectOptions();
options.setServerURIs(new String[]{hostUrl});
options.setUserName(username);
options.setPassword(password.toCharArray());
options.setCleanSession(true);
options.setConnectionTimeout(10);
options.setConnectionTimeout(3000);
options.setKeepAliveInterval(2);
options.setWill("willTopic", WILL_DATA, 2, false);
final DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
factory.setConnectionOptions(options);
return factory;
}
/**
* MQTT信息通道(生产者)
* @return
*/
@Bean(value = "mqttOutboundChannel")
public MessageChannel mqttOutboundChannel() {
return new DirectChannel();
}
/**
* MQTT消息处理器(生产者)
* @return
*/
@Bean
@ServiceActivator(inputChannel = "mqttOutboundChannel")
public MessageHandler mqttOutbound() {
//clientId
final MqttPahoMessageHandler handler = new MqttPahoMessageHandler(clientId, clientFactory());
handler.setDefaultQos(1);
handler.setDefaultRetained(false);
handler.setDefaultTopic(defaultTopic);
handler.setAsync(false);
handler.setAsyncEvents(false);
return handler;
}
/**
* MQTT消息接收处理
*/
//接收通道
@Bean
public MessageChannel mqttInputChannel() {
return new DirectChannel();
}
//配置client,监听的topic
@Bean
public MessageProducer inbound() {
MqttPahoMessageDrivenChannelAdapter adapter =
new MqttPahoMessageDrivenChannelAdapter(
clientId + "_inbound", clientFactory(), SUB_TOPICS.split(","));
adapter.setCompletionTimeout(3000);
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setQos(0);
adapter.setOutputChannel(mqttInputChannel());
return adapter;
}
//通过通道获取数据
@Bean
@ServiceActivator(inputChannel = "mqttInputChannel")
public MessageHandler handler() {
return message -> {
String topic = Objects.requireNonNull(message.getHeaders().get("mqtt_receivedTopic")).toString();
log.info("topic: {}", topic);
String[] topics = SUB_TOPICS.split(",");
for (String t : topics) {
if (t.equals(topic)) {
log.info("payload: {}", message.getPayload().toString());
}
}
};
}
}
MqttConsumerCallback(消费者消息回调)
import java.util.Arrays;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttMessage;
@Slf4j
public class MqttConsumerCallback implements MqttCallbackExtended {
private MqttClient client;
private MqttConnectOptions options;
private String[] topic;
private int[] qos;
public MqttConsumerCallback(MqttClient client, MqttConnectOptions options, String[] topic, int[] qos) {
this.client = client;
this.options = options;
this.topic = topic;
this.qos = qos;
}
/**
* mqtt连接后订阅主题
*/
@Override
public void connectComplete(boolean b, String s) {
try {
if (null != topic && null != qos) {
if (client.isConnected()) {
client.subscribe(topic, qos);
log.debug("mqtt连接成功,客户端ID:{}",topic );
log.debug("--订阅主题::{}" ,Arrays.toString(topic));
} else {
log.error("mqtt连接失败,客户端ID:{}",topic);
}
}
} catch (Exception e) {
log.error("mqtt订阅主题异常:{}" , e);
}
}
/**
* 断开重连
*/
@Override
public void connectionLost(Throwable throwable) {
System.out.println("MQTT连接断开,发起重连......");
try {
if (null != client && !client.isConnected()) {
client.reconnect();
log.debug("尝试重新连接");
} else {
client.connect(options);
log.debug("尝试建立新连接");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 消息处理
*/
@Override
public void messageArrived(String s, MqttMessage message) throws Exception {
try {
String msg = new String(message.getPayload());
log.debug("收到topic:{} 消息:{}",topic ,msg);
log.debug("收到消息后执行具体的业务逻辑操作,比如将消息存储进数据库");
} catch (Exception e) {
log.error("处理mqtt消息异常:{}" , e);
}
}
/**
* 接收到消息调用令牌中调用
*/
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
log.debug("deliveryComplete---------{}" ,Arrays.toString(topic));
}
}
测试:
打开MTQQ的Dashboard 或者 MQTTX
我用的是Dashboard