mosquitto的简介
MQTT(MQ Telemetry Transport),消息队列遥测传输协议,轻量级的发布/订阅协议, 适用于一些条件比较苛刻的环境,进行低带宽、不可靠或间歇性的通信。目前已经是物联网消息通信事实上的标准协议了。值得一提的是mqtt提供三种不同质量的消息服务:
在工业上使用MQTT协议来进行物联网数据传输,主要看中了以下优点:
- 低协议开销。它的每消息标题可以短至 2 个字节。 容错性好。
- 物联网的网络环境往往比较恶劣,MQTT能从断开故障中恢复,并且不需要额外的编码(如果使用HTTP则需要实现重试代码)。
- 低功耗。MQTT专门为了低功耗的目标而设计
- 最多能接受百万级别的客户端。
Mosquitto就是这样一个MQTT协议的完整实现。
这里我工作中所用到了springBoot整合mosquitto,特此记录一下,有需要的小伙伴,希望能帮到你,这里是用maven构建的。
1. 引入jar包依赖
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
</dependency>
<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>
2. application.yml 配置文件
spring:
#mqtt配置
mqtt:
send:
#完成超时时间
completionTimeout: 3000
#通过mqtt发送消息验证所需用户名
username: test1
#通过mqtt发送消息验证所需密码
password: test1
#连接的mqtt地址
url: tcp: id:1883
#客户端id
clientId: clint1
#推送主题 后面跟着#是监控下面所有的话题
topic: topic
#topic: my-test
keepAliveInterval: 20
connectionTimeout: 3000
3. mqtt的配置文件(初始客户端,主题,发布,订阅等消息)
创建MqttConfig类
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
import org.springframework.util.StringUtils;
/**
* @program: mg_parse
* @description: TODO MQTT配置,生产者
* @author:
* @create:
**/
@Configuration
public class MqttConfig {
private static final byte[] WILL_DATA;
static {
WILL_DATA = "offline".getBytes();
}
/**
* mqtt订阅者使用信道名称
*/
public static final String CHANNEL_NAME_IN = "mqttInboundChannel";
/**
* mqtt发布者信道名称
*/
public static final String CHANNEL_NAME_OUT = "mqttOutboundChannel";
/**
* mqtt发送者用户名
*/
@Value("${spring.mqtt.send.username}")
private String username;
/**
* mqtt发送者密码
*/
@Value("${spring.mqtt.send.password}")
private String password;
/**
* mqtt发送者url
*/
@Value("${spring.mqtt.send.url}")
private String hostUrl;
/**
* mqtt发送者客户端id
*/
@Value("${spring.mqtt.send.clientId}")
private String clientId;
/**
* mqtt发送者主题
*/
@Value("${spring.mqtt.send.topic}")
private String msgTopic;
/**
* mqtt发送者超时时间
*/
@Value("${spring.mqtt.send.completionTimeout}")
private int completionTimeout ;
/**
* @author liujianfu
* @description
*/
@Value("${spring.mqtt.send.keepAliveInterval}")
private int keepAliveInterval;
/**
* @author liujianfu
* @description
*/
@Value("${spring.mqtt.send.connectionTimeout}")
private int connectionTimeout;
@Autowired
private MqttCallbackHandler mqttCallbackHandler;
/**
* @author liujianfu
* @description 新建MqttConnectionOptionsBean MQTT连接器选项
* @date 2021/8/17 10:34
* @param
* @return org.eclipse.paho.client.mqttv3.MqttConnectOptions
*/
@Bean
public MqttConnectOptions getSenderMqttConnectOptions(){
MqttConnectOptions options=new MqttConnectOptions();
// 设置连接的用户名
if(!username.trim().equals("")){
//将用户名去掉前后空格
options.setUserName(username);
}
// 设置连接的密码
options.setPassword(password.toCharArray());
// 转化连接的url地址
String[] uris={hostUrl};
// 设置连接的地址
options.setServerURIs(uris);
// 设置超时时间 单位为秒
options.setConnectionTimeout(completionTimeout);
// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线
// 但这个方法并没有重连的机制
options.setKeepAliveInterval(keepAliveInterval);
// 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
//设置超时时间
options.setConnectionTimeout(connectionTimeout);
options.setCleanSession(true);
options.setAutomaticReconnect(true);
return options;
}
/**
*创建MqttPathClientFactoryBean
*/
@Bean
public MqttPahoClientFactory senderMqttClientFactory() {
//创建mqtt客户端工厂
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
//设置mqtt的连接设置
factory.setConnectionOptions(getSenderMqttConnectOptions());
return factory;
}
/**
* 发布者-MQTT信息通道(生产者)
*/
@Bean(name = CHANNEL_NAME_OUT)
public MessageChannel mqttOutboundChannel() {
return new DirectChannel();
}
/**
* 发布者-MQTT消息处理器(生产者) 将channel绑定到MqttClientFactory上
*
* @return {@link org.springframework.messaging.MessageHandler}
*/
@Bean
@ServiceActivator(inputChannel = CHANNEL_NAME_OUT)
public MessageHandler mqttOutbound() {
//创建消息处理器
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(
clientId+"_pub",
senderMqttClientFactory());
//设置消息处理类型为异步
messageHandler.setAsync(true);
//设置消息的默认主题
messageHandler.setDefaultTopic(msgTopic);
messageHandler.setDefaultRetained(false);
//1.重新连接MQTT服务时,不需要接收该主题最新消息,设置retained为false;
//2.重新连接MQTT服务时,需要接收该主题最新消息,设置retained为true;
return messageHandler;
}
/************ 消费者,订阅者的消费信息 *****/
/**
* MQTT信息通道(消费者)
*
*/
@Bean(name = CHANNEL_NAME_IN)
public MessageChannel mqttInboundChannel() {
return new DirectChannel();
}
/**
* MQTT消息订阅绑定(消费者)
*
*/
@Bean
public MessageProducer inbound() {
System.out.println("topics:"+msgTopic);
// 可以同时消费(订阅)多个Topic
MqttPahoMessageDrivenChannelAdapter adapter =
new MqttPahoMessageDrivenChannelAdapter(
clientId+"_sub", senderMqttClientFactory(), msgTopic);
adapter.setCompletionTimeout(5000);
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setQos(0);
// 设置订阅通道
adapter.setOutputChannel(mqttInboundChannel());
return adapter;
}
/**
* MQTT消息处理器(消费者)
*
*/
@Bean
@ServiceActivator(inputChannel = CHANNEL_NAME_IN)
public MessageHandler handler() {
return message -> {
String topic = message.getHeaders().get("mqtt_receivedTopic").toString();
String payload = message.getPayload().toString();
mqttCallbackHandler.handle(topic,payload);
};
}
}
4. 发送接口网关MqSendMessageGateWay
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;
/**
* @program: mg_parse
* @description:
* @author:
* @create:
**/
@Component
@MessagingGateway(defaultRequestChannel = MqttConfig.CHANNEL_NAME_OUT)
public interface MqSendMessageGateWay {
/**
* 默认的消息机制
* @param data
*/
void sendToMqtt(String data);
/**
* 发送消息 向mqtt指定topic发送消息
* @param topic
* @param payload
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload);
/**
* 发送消息 向mqtt指定topic发送消息
* @param topic
* @param qos
* @param payload
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);
}
5. 消息订阅类MqttCallbackHandler
import org.springframework.stereotype.Service;
/**
* @program: mg_parse
* @description:
* @author:
* @create:
**/
@Service
public class MqttCallbackHandler {
public void handle(String topic, String payload){
// 根据topic分别进行消息处理。
System.out.println("MqttCallbackHandle:" + topic + "|"+ payload);
}
}
6. 发布生产,这里用controller层来测试
在生产中,启动监听以后,使用service层来发送主题
@Autowired
private MqSendMessageGateWay mqSendMessageGateWay;
@RequestMapping("/send")
@ResponseBody
private ResponseEntity<String> send(){
String data = "我是springboot发送的数据";
mqSendMessageGateWay.sendToMqtt(data);
// return R.ok("OK");
return new ResponseEntity<>("OK", HttpStatus.OK);
}
/**
* 动态增加主题
* @param
* @param
*/
@ResponseBody
@RequestMapping("/sendToTopic")
private ResponseEntity<String> sendToTopic(){
String topic = "sharjeck/ai/test/out";
String data = "这是出的主题";
mqSendMessageGateWay.sendToMqtt(topic,data);
return new ResponseEntity<>("OK", HttpStatus.OK);
}
7. 启动springboot启动类即可
8,SpringBoot连接MQTT进行发布消息时取消保留历史消息
在发布完消息后,另一个新的订阅者在开始订阅这个消息后会收到之前发布的历史消息,现在不需要使其收到历史消息,只需要收到即时消息
在进行发布消息时调用发布消息时
有一个参数叫retained。
Retained 消息是指在 PUBLISH 数据包中 Retain 标识设为 1 的消息,Broker 收到这样的 publish 包以后,将保存这个消息,当有一个新的订阅者订阅相应主
题的时候,Broker 会马上将这个消息发送给订阅者。
这里生产者,生产的时候把retained设置为flase的时候,便不会保留历史信息!
Qos的等级,可根据业务进行设定,到此,配置完成。有用帮忙点赞,谢谢!