SpringBoot集成mqtt启动就不断报已断开连接问题
踩坑记录,实在是天坑!!!
原因一:clientId相同,即clientId重复导致(不过我不是这个问题)
我的问题是:
项目启动成功后,控制台不停地反复输出:已断开连接,,,
加了重连机制后,则不停地输出:重连失败,已连接客户机,,,
尼玛,,关键点还在于我能接收到订阅的消息(不影响消息处理),这又是什么情况,明明没断连,确一直报已断开连接
百度了半天,愣是找不到对的方法
原因二:项目启动类用了ApplicationListener(就是这个原因,改为ApplicationRunner就行了)
附成功代码:::
maven依赖
<!-- mqtt --> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-mqtt</artifactId> </dependency>
yaml文件
#mqtt配置 mqtt: # 服务器连接地址,如果有多个,用逗号隔开 url: tcp://127.0.0.1:1883 # 连接服务器默认客户端ID clientId: ${random.value} # 主题 topics: topic-docker # 用户名 username: admin # 密码 password: admin # 连接超时 timeout: 30 # 保持活动间隔 keepalive: 60
mqtt配置类
package com.wt.mqtt; import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * mqtt信息 * * @author wt **/ @Data @Component public class MqttConfig { @Value("${mqtt.url}") private String url; @Value("${mqtt.clientId}") private String clientId; @Value("${mqtt.username}") private String username; @Value("${mqtt.password}") private String password; @Value("${mqtt.topics}") private String subtopic; @Value("${mqtt.timeout}") private Integer timeout; @Value("${mqtt.keepalive}") private Integer keepalive; }
mqtt启动类
package com.hzzcdz.job.mqtt;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 项目启动 订阅主题
*
* @author wangtao
*/
@Slf4j
@Component
public class MqttManager implements ApplicationRunner {
@Resource
private MqttConfig mqttConfig;
@Resource
private MyCallback callback;
private final MqttConnect server;
@Autowired
public MqttManager(MqttConnect server) {
this.server = server;
}
@Override
public void run(ApplicationArguments args) {
try {
server.setMqttClient(mqttConfig.getUsername(), mqttConfig.getPassword(), callback);
server.sub(mqttConfig.getSubtopic());
log.info("MQTT启动连接成功!");
log.info("订阅的主题是 : " + mqttConfig.getSubtopic());
} catch (MqttException e) {
log.error(e.getMessage(), e);
log.error("MQTT启动连接失败!");
}
}
}
mqtt连接工具类
package com.hzzcdz.job.mqtt; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.*; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author wt * MQTT工具类操作 */ @Slf4j @Component public class MqttConnect { @Resource private MqttConfig mqttConfig; private MqttClient mqttClient; /** * 客户端connect连接mqtt服务器 * * @param userName 用户名 * @param passWord 密码 * @param mqttCallback 回调函数 **/ public void setMqttClient(String userName, String passWord, MqttCallback mqttCallback) throws MqttException { MqttConnectOptions options = mqttConnectOptions(userName, passWord); mqttClient.setCallback(mqttCallback); mqttClient.connect(options); } /** * MQTT连接参数设置 */ private MqttConnectOptions mqttConnectOptions(String userName, String passWord) throws MqttException { mqttClient = new MqttClient(mqttConfig.getUrl(), mqttConfig.getClientId(), new MemoryPersistence()); MqttConnectOptions options = new MqttConnectOptions(); //用户名 options.setUserName(userName); //密码 options.setPassword(passWord.toCharArray()); //连接超时,默认:30 options.setConnectionTimeout(mqttConfig.getTimeout()); //自动重新连接,默认:false options.setAutomaticReconnect(false); //清理会话,默认:true options.setCleanSession(false); //保持活动间隔,默认:60 options.setKeepAliveInterval(mqttConfig.getKeepalive()); return options; } /** * 关闭MQTT连接 */ public void close() throws MqttException { mqttClient.close(); mqttClient.disconnect(); } /** * 重连 */ public void reConnect(String topic) { try { mqttClient.reconnect(); while (true) { if (mqttClient.isConnected()) { sub(topic); break; } else { Thread.sleep(10000); log.info("重连中,请稍后......"); } } log.info("MQTT连接成功,订阅成功.topic={}", topic); } catch (MqttException | InterruptedException e) { log.error("重连失败,失败原因{}", e.getMessage()); } } /** * 向某个主题发布消息 默认qos:1 * * @param topic:发布的主题 * @param msg:发布的消息 */ public void pub(String topic, String msg) throws MqttException { MqttMessage mqttMessage = new MqttMessage(); mqttMessage.setPayload(msg.getBytes()); MqttTopic mqttTopic = mqttClient.getTopic(topic); MqttDeliveryToken token = mqttTopic.publish(mqttMessage); token.waitForCompletion(); } /** * 向某个主题发布消息 * * @param topic: 发布的主题 * @param msg: 发布的消息 * @param qos: 消息质量 Qos:0、1、2 */ public void pub(String topic, String msg, int qos) throws MqttException { MqttMessage mqttMessage = new MqttMessage(); mqttMessage.setQos(qos); mqttMessage.setPayload(msg.getBytes()); MqttTopic mqttTopic = mqttClient.getTopic(topic); MqttDeliveryToken token = mqttTopic.publish(mqttMessage); token.waitForCompletion(); } /** * 订阅某一个主题 ,此方法默认的的Qos等级为:1 * * @param topic 主题 */ public void sub(String topic) throws MqttException { mqttClient.subscribe(topic); } /** * 订阅某一个主题,可携带Qos * * @param topic 所要订阅的主题 * @param qos 消息质量:0、1、2 */ public void sub(String topic, int qos) throws MqttException { log.info("订阅的主题是 : " + topic); log.info("订阅的Qos是 : " + qos); mqttClient.subscribe(topic, qos); } /** * 取消某个主题发布消息 */ public void unSub(String topic) { log.info("取消订阅的主题是 : " + topic); try { mqttClient.unsubscribe(topic); } catch (MqttException e) { throw new RuntimeException(e); } } }
mqtt回调函数类
package com.hzzcdz.job.mqtt; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * MQTT回调函数 * * @author wt */ @Slf4j @Component public class MyCallback implements MqttCallback { @Resource private MqttConfig mqttConfig; @Resource private MqttConnect mqttConnect; /** * MQTT 断开连接会执行此方法 */ @Override public void connectionLost(Throwable throwable) { log.info("断开了MQTT连接 :{}", throwable.getMessage()); log.error(throwable.getMessage(), throwable); mqttConnect.reConnect(mqttConfig.getSubtopic()); } /** * publish发布成功后会执行到这里 */ @Override public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { log.info("发布消息成功"); } /** * subscribe订阅后得到的消息会执行到这里 */ @Override public void messageArrived(String topic, MqttMessage message) { // TODO 此处可以将订阅得到的消息进行业务处理、数据存储 log.info("收到来自 " + topic + " 的消息:{}", new String(message.getPayload())); //数据处理
} }
至此填上了坑!!!