SpringBoot整合MQTT
环境:
jdk:1.8
一、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
二、添加配置
com:
mqtt:
url: tcp://broker.emqx.io:1883
clientId: mqttx_fd53fddgvkusg1389 # id必须在当前服务器上唯一
topic: dreamstudio/#
username:
password:
timeout: 10
keepalive: 20
三、配置类
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "com.mqtt") //对应yml文件中的com下的mqtt文件配置
public class MqttConfiguration {
private String url;
private String clientId;
private String topic;
private String username;
private String password;
private String timeout;
private String keepalive;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getTopic() {
return topic;
}
public void setTopic(String topics) {
this.topic = topics;
}
public String getTimeout() {
return timeout;
}
public void setTimeout(String timeout) {
this.timeout = timeout;
}
public String getKeepalive() {
return keepalive;
}
public void setKeepalive(String keepalive) {
this.keepalive = keepalive;
}
@Bean
public MyMQTTClient myMQTTClient() {
MyMQTTClient myMQTTClient = new MyMQTTClient(url, username, password, clientId, Integer.parseInt(timeout), Integer.parseInt(keepalive));
for (int i = 0; i < 10; i++) {
try {
myMQTTClient.connect();
//不同的主题
myMQTTClient.subscribe(topic, 1);
return myMQTTClient;
} catch (MqttException e) {
log.error("MQTT connect exception,connect time = " + i);
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
return myMQTTClient;
}
}
四、MQTT客户端
@Slf4j
public class MyMQTTClient {
private static MqttClient client;
private String url;
private String username;
private String password;
private String clientId;
private int timeout;
private int keepalive;
public MyMQTTClient(String url, String username, String password, String clientId, int timeOut, int keepAlive) {
this.url = url;
this.username = username;
this.password = password;
this.clientId = clientId;
this.timeout = timeOut;
this.keepalive = keepAlive;
}
public static MqttClient getClient() {
return client;
}
public static void setClient(MqttClient client) {
MyMQTTClient.client = client;
}
public MqttConnectOptions setMqttConnectOptions(String username, String password, int timeout, int keepalive) {
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;
}
public void connect() throws MqttException {
if (client == null) {
client = new MqttClient(url, clientId, new MemoryPersistence());
client.setCallback(new MyMQTTCallback(MyMQTTClient.this));
}
MqttConnectOptions mqttConnectOptions = setMqttConnectOptions(username, password, timeout, keepalive);
if (!client.isConnected()) {
client.connect(mqttConnectOptions);
} else {
client.disconnect();
client.connect(mqttConnectOptions);
}
log.info("MQTT connect success");
}
public void publish(String pushMessage, String topic) {
publish(pushMessage, topic, 0, false);
}
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 = MyMQTTClient.getClient().getTopic(topic);
if (null == mqttTopic) {
log.error("topic is not exist");
}
MqttDeliveryToken token;
synchronized (this) {
try {
assert mqttTopic != null;
token = mqttTopic.publish(message);
token.waitForCompletion(1000L);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
public void subscribe(String topic, int qos) {
try {
MyMQTTClient.getClient().subscribe(topic, qos);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
五、MQTT回调
@Slf4j
@Configuration
public class MyMQTTCallback implements MqttCallback {
private MyMQTTClient myMQTTClient;
public MyMQTTCallback(MyMQTTClient myMQTTClient) {
this.myMQTTClient = myMQTTClient;
}
@Override
public void connectionLost(Throwable throwable) {
log.error("mqtt connectionLost 连接断开,5S之后尝试重连: {}", throwable.getMessage());
long reconnectTimes = 1;
while (true) {
try {
if (MyMQTTClient.getClient().isConnected()) {
log.warn("mqtt reconnect success end");
return;
}
log.warn("mqtt reconnect times = {} try again...", reconnectTimes++);
MyMQTTClient.getClient().reconnect();
} catch (MqttException e) {
log.error(e.toString());
}
try {
Thread.sleep(5000);
} catch (InterruptedException ignored) {
}
}
}
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) {
try {
String msg = new String(mqttMessage.getPayload());
log.info("接收消息主题 : {},接收消息内容 : {}", topic, msg);
MqttMessageHandler.receive(topic, msg); //业务
} catch (Exception e) {
log.error(e.toString());
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
log.info("==========deliveryComplete={}==========", iMqttDeliveryToken.isComplete());
}
// @Component
// public static class SaveData {
// @Autowired
// private WebSocket webSocket;
//
// private static SaveData saveData;
// @PostConstruct
// public void init() {
// saveData = this;
// saveData.webSocket = webSocket;
// }
// }
}
主要是实现MqttCallback接口,该接口有三个需要实现的方法:
public interface MqttCallback {
void connectionLost(Throwable cause);
void messageArrived(String topic, MqttMessage message) throws Exception;
void deliveryComplete(IMqttDeliveryToken token);
}
第一个方法会在断开连接时调用
第二个方法会在接收消息时调用
第三个方法会在发送消息成功时调用
注意:
- 必须将messageArrived中的异常 try-catch掉 不然会莫名奇妙重连,并且连不上。
- 该类中无法注入ioc容器中的Bean,若是要注入,则需要像注释掉的静态内部类一样操作。