Springboot+MQTT集成
pom文件
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
</dependencies>
yml文件
mqtt:
host: tcp://192.188.1.1:1883
username: admin
password: public
timeout: 30 #连接超时
keepalive: 60 #心跳检查时间
clientid: client01
topic: test01/#
MqttCallbackAutoConfiguration.java
@Configuration
@EnableConfigurationProperties(MqttConfig.class)
@ConditionalOnBean(MqttPushClient.class)
@ConditionalOnProperty(prefix = "mqtt", value = "enabled", matchIfMissing = true)
public class MqttCallbackAutoConfiguration {
@Autowired
private MqttConfig properties;
@Autowired
private MqttPushClient mqttPushClient;
@Bean
@ConditionalOnMissingBean(PushCallback.class)
public PushCallback pushCallback() {
PushCallback pushCallback = new PushCallback(properties);
mqttPushClient.setPushCallback(pushCallback);
mqttPushClient.connect(properties.getHost(), properties.getClientid(), properties.getUsername(), properties.getPassword(), properties.getTimeout(),properties.getKeepalive());
mqttPushClient.subscribe(properties.getTopic(), 0);
return pushCallback;
}
}
MqttConfig.java
@Data
@ConfigurationProperties(MqttConfig.PREFIX)
public class MqttConfig {
public static final String PREFIX="mqtt";
private String host;
private String clientid;
private String username;
private String password;
private String topic;
private int timeout;
private int keepalive;
}
MqttPushClient.java
@Slf4j
@Component
public class MqttPushClient {
private PushCallback pushCallback;
private static MqttClient client;
public static MqttClient getClient(){
return client;
}
public static void setClient(MqttClient client){
MqttPushClient.client = client;
}
public void setPushCallback(PushCallback pushCallback) {
this.pushCallback = pushCallback;
}
/**
* 客户端连接
*
* @param host ip+端口
* @param clientID 客户端Id
* @param username 用户名
* @param password 密码
* @param timeout 超时时间
* @param keeplive 保留数
*/
public void connect(String host,String clientID,String username,String password,int timeout,int keeplive){
MqttClient client;
try {
client=new MqttClient(host,clientID,new MemoryPersistence());
MqttConnectOptions options=new MqttConnectOptions();
options.setCleanSession(true);
options.setUserName(username);
options.setPassword(password.toCharArray());
options.setConnectionTimeout(timeout);
options.setKeepAliveInterval(keeplive);
options.setAutomaticReconnect(true);
MqttPushClient.setClient(client);
try {
client.setCallback(pushCallback);
client.connect(options);
}catch (Exception e){
e.printStackTrace();
}
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 发布,默认qos为0,非持久化
* @param topic
* @param pushMessage
*/
public void publish(int qos, boolean retained, String topic,String pushMessage){
try {
MqttMessage message = new MqttMessage();
message.setPayload(pushMessage.getBytes(StandardCharsets.UTF_8));
message.setRetained(retained);
message.setQos(qos);
client.publish(topic, message);
}
catch (Exception e) {
log.error(e.getMessage());
}
}
/**
* 订阅某个主题,qos默认为0
* @param topic
*/
public void subscribe(String topic){
log.info("开始订阅主题" + topic);
subscribe(topic,0);
}
public void subscribe(String topic, int qos){
try {
MqttPushClient.getClient().subscribe(topic,qos);
}catch (MqttException e){
e.printStackTrace();
}
}
}
PushCallback.java
@Slf4j
public class PushCallback implements MqttCallback {
private MqttConfig mqttConfig;
@Autowired
private IMqttResponse mqttResponse;
@Autowired
MqttPushClient mqttPushClient;
@Autowired
QuartzScheduler quartzScheduler;
public PushCallback(MqttConfig mqttConfiguration) {
this.mqttConfig = mqttConfiguration;
}
@Override
public void connectionLost(Throwable throwable) {
log.info("连接断开,正在重连....");
if (MqttPushClient.getClient() == null || !MqttPushClient.getClient().isConnected()) {
log.info("连接断开,正在重连....");
//mqttPushClient.;
}
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
log.info("接收消息主题 : " + topic);
//log.info("接收消息Qos : " + message.getQos());
//log.info("接收消息内容 : " + new String(message.getPayload()));
String[] topics = topic.split("/");
if(topics.length == 3) {
if(topics[1].equals(mqttConfig.getPlattopic())) {
String topicResp = "response-topic";
String str = "get string";
mqttPushClient.pushlish(0, false, topicResp, str);
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
try {
log.info("deliveryComplete---------" + token.getTopics());
}
catch (Exception e) {
log.error(e.getMessage());
}
}
}
完毕,代码可以跑起来了。
但是运行起来发现有点问题,用MQTTBox发送个消息后,PushCallback的messageArrived接收到消息开始处理,执行到mqttPushClient.pushlish就不往下走了,程序挂死在这儿了。
messageArrived方法由MQTT客户机同步调用。直到该方法干净地返回时,才将确认发送回服务器。
如果该方法的实现抛出异常,那么客户端将被关闭。当客户机下一次重新连接时,服务器将重新发送任何QoS 1或2消息。
当此方法的实现运行时到达的任何附加消息都将在内存中构建,然后在网络上备份。
如果应用程序需要持久化数据,那么它应该确保数据在从这个方法返回之前被持久化,就像从这个方法返回之后,消息被认为已经被传递了,并且不会被复制。
可以在这个回调的实现中发送一个新的消息(例如,对这个消息的响应),但是实现不能断开客户端,因为要发送对正在处理的消息的确认是不可能的,并且会出现死锁。
就是每次回调只能在上次回调完成后才能进入这个方法。如果时间多长,mqtt服务器会接不到消息,认为服务挂掉,断开连接。所有这个方法中如果有耗时的操作应该另外加一个线程操作。
解决Callback中不能发布消息问题
修改一下发送消息的地方,修改MqttPushClient类的publish方法
public void publish(int qos, boolean retained, String topic,String pushMessage){
try {
MqttMessage message = new MqttMessage();
message.setPayload(pushMessage.getBytes(StandardCharsets.UTF_8));
message.setRetained(retained);
message.setQos(qos);
//client.publish(topic, message);
MqttDeliveryToken token;
MqttTopic mqttTopic = client.getTopic(topic);
token = mqttTopic.publish(message);
}
catch (Exception e) {
log.error(e.getMessage());
}
}
问题解决!