大家好, 我是Open, 是一位新进的掘金作家, 今天我带来的是MQTT的配置教程, 如果大家感觉我写的不错可以点点赞👍, 好了我们废话不多说, 直接开始操作。
本次使用的版本如下:
- SpringBoot: 2.7.14
- Spring-MQTT:5.5.18
1: 读取YML配置
#MQTT
mqtt:
host:
userName:
passWord:
qos: 1
clientId:
timeout: 10
keepalive: 20
topic1:
topic2:
topic3:
package com.ruoyi.factory.mqtt.properties;
import lombok.Data;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
1. @author WXY
2. @date 2022/6/29 20:42
*/
@Data
@Configuration
public class MqttProperties {
@Value("${mqtt.host}")
private String host;
@Value("${mqtt.username}")
private String username;
@Value("${mqtt.password}")
private String password;
@Value("${mqtt.clientId}")
private String clientId;
@Value("${mqtt.timeout}")
private int timeOut;
@Value("${mqtt.keepalive}")
private int keepAlive;
@Value("${mqtt.topic1}")
private String topic1;
@Value("${mqtt.topic2}")
private String topic2;
/**
* 设置mqtt连接参数
*
* @return
*/
public MqttConnectOptions setMqttConnectOptions() {
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(username);
options.setPassword(password.toCharArray());
options.setConnectionTimeout(timeOut);
options.setKeepAliveInterval(keepAlive);
options.setCleanSession(true);
options.setAutomaticReconnect(true);
return options;
}
}
2: 更新自带的Bean、设置回调、一些回调配置
- newClient(MqttProperties config)中的cofig会自带yml中的配置
- 回调工厂可以新增自己的内容, 具体像是@Resource中注入,在放进Factory
- MqttConnectOptions,Mqtt的连接配置在上方的pro中,可以自己选择将其他config放入yml
- 所有的内容都需要从该配置中注入到工厂中使用
package com.ruoyi.factory.config;
import com.ruoyi.factory.mqtt.MqttCallbackFactory;
import com.ruoyi.factory.mqtt.MqttServer;
import com.ruoyi.factory.mqtt.properties.MqttProperties;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.annotation.Resource;
/**
* @author OpenACloud
* @create 2024/3/20 14:12
*/
@Configuration
public class MqttConfig {
@Resource
private MqttServer server;
@Bean
@Primary
public MqttClient newClient(MqttProperties config) throws MqttException {
MqttClient mqttClient = new MqttClient(config.getHost(), config.getClientId(), new MemoryPersistence());
MqttCallbackFactory callbackFactory =
new MqttCallbackFactory(mqttClient, 100L, config, server)
.reconnectConfig(2500L, 2L)
.completeConfig(true);
mqttClient.setCallback(callbackFactory);
MqttConnectOptions mqttConnectOptions = config.setMqttConnectOptions();
if(mqttClient.isConnected()) {
mqttClient.disconnect();
}
mqttClient.connect(mqttConnectOptions);
return mqttClient;
}
}
3: 回调工厂的演示
- 需要什么自己去改,这个地方可以扩展开来, 其次在message中需要去做自己的消息类型体
package com.ruoyi.factory.mqtt;
import cn.hutool.core.util.CharsetUtil;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.factory.mqtt.properties.MqttProperties;
import org.eclipse.paho.client.mqttv3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
*
* @author OpenACloud
* @create 2024/3/20 14:29
*/
public class MqttCallbackFactory implements MqttCallbackExtended {
/**
* Lost reconnect
*/
private Long speed = 1000L;
private Long speedMultiple = 1L;
private Long sleepTime = speed * speedMultiple;
/**
* Complete Log
*/
private boolean completeLog;
protected Long connectCount;
protected MqttClient mqttClient;
protected MqttServer mqttServer;
protected MqttProperties mqttConfiguration;
private static final Logger log = LoggerFactory.getLogger(MqttCallbackFactory.class);
@Override
public void connectionLost(Throwable throwable) {
Long nowCount = 1L;
log.warn("连接以断开, 错误原因[ reason: {} ]", throwable.getMessage());
log.warn("正在尝试重新连接, 本次连接最大限度为[ count: {}]", connectCount);
while (nowCount <= connectCount) {
if(mqttClient.isConnected()) {
log.warn("本次重连结束, 本次重连次数[ count: {}]", nowCount);
return;
}else {
try {
mqttClient.connect();
}catch (MqttException exception) {
log.warn("重连失败, 当前连接次数[ count: {}]", nowCount);
}
}
try {
Thread.sleep(sleepTime);
}catch (InterruptedException e) {
log.warn("重连睡眠失败-------------------------> , 暂无引发原因, 请管理员排查");
}
nowCount++;
}
}
/**
*
* 重新连接后 主题也需要再次订阅 将重新订阅主题放在连接成功后的回调 比较合理
*
* @param connectType
* @param serverURI
*/
@Override
public void connectComplete(boolean connectType, String serverURI) {
log.info("MQTT连接成功,连接方式:{}", connectType ? "重连" : "直连");
}
/**
* subscribe后得到的消息会执行到这里面
*
* @param topic
* @param mqttMessage
* @throws Exception
*/
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
log.info("接收消息主题:{},接收消息内容:{}", topic, new String(mqttMessage.getPayload()));
}
/**
* publish后,配送完成后回调的方法
*
* @param iMqttDeliveryToken
*/
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
if(completeLog) {
try {
log.info("Complete: {}, Msg: {}", iMqttDeliveryToken.isComplete(), iMqttDeliveryToken.getMessage());
} catch (MqttException e) {
throw new RuntimeException(e);
}
}
}
/**
* 初始化连接信息
*
* @param mqttClient 客户端
* @param connectCount 最大重连次数
* @param mqttConfiguration 配置
* @param mqttServer 服务
*/
public MqttCallbackFactory(MqttClient mqttClient, Long connectCount, MqttProperties mqttConfiguration, MqttServer mqttServer)
{
this.mqttClient = mqttClient;
this.mqttServer = mqttServer;
this.connectCount = connectCount;
this.mqttConfiguration = mqttConfiguration;
}
/**
* 如果你还想对其他配置进行初始化, 请在这里配置
*
* @param speed 速度
* @param speedMultiple 加成
* 速度 * 加成 等于所需的睡眠时间, 请您在初始化时调整合适大小
*/
public MqttCallbackFactory reconnectConfig(Long speed, Long speedMultiple)
{
this.speed = speed;
this.speedMultiple = speedMultiple;
this.sleepTime = speed * speedMultiple;
return this;
}
/**
* 如果你还想对其他配置进行初始化, 请在这里配置
*
* @param completeLog 是否打印日志
*/
public MqttCallbackFactory completeConfig(Boolean completeLog)
{
this.completeLog = completeLog;
return this;
}
}
4: 订阅跟发布
package com.ruoyi.factory.mqtt;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author OpenACloud
* @create 2024/3/20 14:34
*/
@Component
public class MqttPublish {
@Resource
private MqttClient mqttClient;
/**
* 发布,默认qos为0,非持久化
*
* @param pushMessage
* @param topic
*/
public void publish(String pushMessage, String topic) {
publish(pushMessage, topic, 0, false);
}
/**
* 发布消息
*
* @param pushMessage
* @param topic
* @param qos
* @param retained:留存
*/
public void publish(String pushMessage, String topic, int qos, boolean retained) {
MqttMessage message = new MqttMessage();
message.setPayload(pushMessage.getBytes());
message.setQos(qos);
message.setRetained(retained);
MqttTopic mqttTopic = mqttClient.getTopic(topic);
MqttDeliveryToken token;//Delivery:配送
synchronized (this) {//注意:这里一定要同步,否则,在多线程publish的情况下,线程会发生死锁,分析见文章最后补充
try {
token = mqttTopic.publish(message);//也是发送到执行队列中,等待执行线程执行,将消息发送到消息中间件
token.waitForCompletion(1000L);
} catch (MqttPersistenceException e) {
e.printStackTrace();
} catch (MqttException e) {
e.printStackTrace();
}
}
}
}
package com.ruoyi.factory.mqtt;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author OpenACloud
* @create 2024/3/20 15:05
*/
@Component
public class MqttSubscribe {
@Resource
private MqttClient client;
/**
* 订阅某个主题
*
* @param topic
* @param qos
*/
public void subscribe(String topic, int qos) {
try {
client.subscribe(topic, qos);
} catch (MqttException e) {
e.printStackTrace();
}
}
/**
* 取消订阅主题
*
* @param topic 主题名称
*/
public void cleanTopic(String topic) {
if (client != null && client.isConnected()) {
try {
client.unsubscribe(topic);
} catch (MqttException e) {
e.printStackTrace();
}
} else {
System.out.println("取消订阅失败!");
}
}
}
OK, 代码内容就是以上内容啦 本次代码不提供太多的,大部分内容都是对Config方面进行扩展, 如果需要对数据接入方面,请在Factory内容的Msg方法下进行添加即可, 如果要插入数据库, 请将需要的插入信息在MqttConfig的目录下以Autowire或Resoure的方式注入, 在放入Factory中即可 本次的内容不多,如果喜欢请多多点赞~