初次尝试MQTT,参考了这位大哥的帖子:《spring-boot集成mqtt传输协议,以及数据持久化(很详细,附源码)》;不经思索直接copy了他的代码,然鹅,项目需要同时收发消息,即上线之后先pub一个通知告诉大家“我来了”,然后订阅一个topic静静等通知。就发现各种失败连不上,但是用客户端MQTTX就好好的。
然后另外一个大哥提点道:“看下是不是有多个连接,理论上pub和sub应该用一个connection”。
遂大彻大悟,重写了代码,成功!特附上代码,供大家参考。
package com.panda.yuan.demo.mqtt;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
/**
* <Description>
*
* @author panda.yuan
* @version 0.1
* @date 2023/07/23 <br>
*/
@Service
@Slf4j
public class IoTGateWay implements MqttCallback {
@Value("${publish.mqtt.host}")
private String host;
@Value("${publish.mqtt.clientid}")
private String clientid;
@Value("${publish.mqtt.username}")
private String username;
@Value("${publish.mqtt.password}")
private String password;
@Value("${publish.mqtt.cleansession}")
private boolean cleansession;
@Value("${publish.mqtt.keepalive}")
private int keepalive;
@Value("${publish.mqtt.connection-timeout}")
private int connectionTimeout;
private MqttClient mqttClient;
@PostConstruct
public void init() {
this.connectBroker();
this.subscribe("notice", 0);
log.info("事件通知topic已订阅");
this.publish("login", "我来了~", 1);
log.info("已发送在线通知");
}
public void connectBroker() {
if (null != this.mqttClient) {
return;
}
try {
MqttClient mqttClient = new MqttClient(this.host, this.clientid, new MemoryPersistence());
mqttClient.setCallback(this);
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(this.cleansession);
options.setUserName(this.username);
options.setPassword(this.password.toCharArray());
options.setConnectionTimeout(this.connectionTimeout);
options.setKeepAliveInterval(this.keepalive);
mqttClient.connect(options);
this.mqttClient = mqttClient;
} catch (MqttException e) {
e.printStackTrace();
log.error("初始化MQTTClient失败:", e);
}
}
public void subscribe(String topic, Integer qos) {
try {
this.mqttClient.subscribe(topic, qos);
} catch (MqttException e) {
e.printStackTrace();
log.error("订阅失败:", e);
}
}
public void unsubscribe(String topic) {
try {
this.mqttClient.unsubscribe(topic);
} catch (MqttException e) {
e.printStackTrace();
log.error("取消订阅失败:", e);
}
}
public void publish(String topic, String data, int qos) {
MqttTopic mqttTopic = this.mqttClient.getTopic(topic);
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setQos(qos);
mqttMessage.setRetained(false);
mqttMessage.setPayload(data.getBytes());
try {
MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
token.waitForCompletion();
Boolean success = token.isComplete();
if (success) {
log.info("投递成功:topic {} data {}", topic, data);
} else {
log.warn("投递失败:topic {} data {}", topic, data);
}
} catch (MqttException e) {
e.printStackTrace();
}
}
@Override
public void connectionLost(Throwable throwable) {
log.warn("跟Broker连接断开,试图重连");
try {
this.mqttClient.reconnect();
log.info("跟Broker重连成功!===");
} catch (MqttException e) {
e.printStackTrace();
log.error("重连失败:", e);
}
}
@Override
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
String result = new String(mqttMessage.getPayload(), "UTF-8");
log.info("=====[[[[接收消息主题 : {} ,Qos : {}, 内容 : {}", s, mqttMessage.getQos(), result);
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
log.info("消息到达???!!!P{}", iMqttDeliveryToken.getMessageId());
}
}
对应的配置文件
server:
port: 8081
publish:
mqtt:
host: tcp://localhost:1883
username: admin
password: public
cleansession: false
clientid: GW002
timeout: 1000
keepalive: 10
connection-timeout: 30000