java对接MQTT协议
1.概述
MQTT是一种轻量级的物联网通信协议,基于客户端-服务器的消息发布/订阅传输协议,支持QoS级别,适用于低带宽、高延迟的网络环境。它具有精简的协议设计,开放的消息协议,以及广泛应用于物联网(IOT)、M2M通信、消息推送和智能设备等领域。MQTT协议涉及发布者、订阅者和消息代理(Broker)的角色,以及连接、订阅、发布消息的过程,并包含会话保持和心跳机制,确保消息的可靠传输。
MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
2.pom依赖
<!-- MQTT -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
3.相关代码
3.1MQTT工具类
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.stereotype.Component;
/**
* MQTT工具类
*/
@Slf4j
@Component
public class MQTTConnect {
private String HOST = "tcp://127.0.0.1:1883"; //mqtt服务器的地址和端口号
private final String clientId = "Test";
private final String username = "admin";
private final String password = "admin";
public static final String TOPIC = "home/garden/fountain";
private MqttClient mqttClient;
/**
* 测试订阅消息
*/
public static void main(String[] args) throws Exception {
MQTTConnect mqttConnect = new MQTTConnect();
mqttConnect.start();
//订阅消息
mqttConnect.sub(TOPIC,0);
}
public void onStart() throws MqttException {
MQTTConnect mqttConnect = new MQTTConnect();
mqttConnect.start();
}
public void start() throws MqttException {
// host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
mqttClient = new MqttClient(HOST, clientId + System.currentTimeMillis(), new MemoryPersistence());
// MQTT的连接设置
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(username);
options.setPassword(password.toCharArray());
// 设置超时时间 单位为秒
options.setConnectionTimeout(30);///默认:30
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
options.setCleanSession(false);//默认:true
// 设置断开后重新连接(设置为true时将启用自动重新连接)
options.setAutomaticReconnect(true);//默认:false
// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
options.setKeepAliveInterval(60);//默认:60
// 设置回调
mqttClient.setCallback(new Callback());
mqttClient.connect(options);
}
/**
* 自定义mqtt连接
* @param host
* @param clientId
* @param userName
* @param passWord
* @param connectionTimeout
* @param cleanSession
* @param automaticReconnect
* @param keepAliveInterval
* @param mqttCallback
* @throws MqttException
*/
public void start(String host,String clientId, String userName, String passWord,
int connectionTimeout, boolean cleanSession,boolean automaticReconnect,
int keepAliveInterval,MqttCallback mqttCallback) throws MqttException {
// host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
mqttClient = new MqttClient(host, clientId + System.currentTimeMillis(), new MemoryPersistence());
// MQTT的连接设置
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(userName);
options.setPassword(passWord.toCharArray());
// 设置超时时间 单位为秒
options.setConnectionTimeout(connectionTimeout);///默认:30
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
options.setCleanSession(cleanSession);//默认:true
// 设置断开后重新连接(设置为true时将启用自动重新连接)
options.setAutomaticReconnect(automaticReconnect);//默认:false
// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
options.setKeepAliveInterval(keepAliveInterval);//默认:60
// 设置回调
mqttClient.setCallback(mqttCallback);
mqttClient.connect(options);
}
/**
* 关闭MQTT连接
*/
public void close() throws MqttException {
mqttClient.disconnect();
mqttClient.close();
}
/**
* 向某个主题发布消息
*
* @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();
log.info("----------向主题 "+ topic+ "发送消息: "+msg +" ----------");
}
/**
* 订阅某一个主题,可携带Qos
*
* @param topic 所要订阅的主题
* @param qos 消息质量:0、1、2
*/
public void sub(String topic, int qos) throws MqttException {
mqttClient.subscribe(topic, qos);
}
}
3.2监听代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* 项目启动 监听主题
*/
@Slf4j
@Component
public class MQTTListener implements ApplicationListener<ContextRefreshedEvent> {
private final MQTTConnect server;
@Autowired
public MQTTListener(MQTTConnect server) {
this.server = server;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
try {
server.start();
server.sub(MQTTConnect.TOPIC,0);
log.info("-----------消息订阅成功-success----------");
} catch (Exception e) {
log.error(e.getMessage(), e);
log.error("-----------消息订阅失败-error-----------");
}
}
}
3.3发送消息controller
import com.compass.springboot3.common.StringUtils;
import com.compass.springboot3.response.ResponseResult;
import com.compass.springboot3.response.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/mqtt")
public class MqttTestController {
@Autowired
private MQTTConnect mqttConnect;
@ResponseBody
@PostMapping("/mqttTest01")
public ResponseResult<Object> test(@RequestParam("msg") String msg,
@RequestParam("topic") String topic, @RequestParam("qos") int qos) throws Exception {
if (StringUtils.isBlank(topic)){
topic =MQTTConnect.TOPIC;
}
mqttConnect.pub(topic, msg,qos);
return ResponseUtil.success("ok");
}
}
3.4 启动类启动监听器代码
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
public class MqttApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
MQTTConnect mqttConnect = new MQTTConnect();
try {
mqttConnect.onStart();
} catch (MqttException e) {
throw new RuntimeException(e);
}
}
}
3.5 消息回调
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.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
/**
* 常规MQTT回调函数
* MqttCallback 接口定义了用于处理 MQTT 客户端异步事件的方法。
* 当使用 Eclipse Paho MQTT 客户端库时,你可以实现这个接口来接收连接状态的变化和消息传递的通知。
*/
@Slf4j
public class Callback implements MqttCallback {
/**
* MQTT 断开连接会执行此方法
*
* 方法说明:当客户端与 MQTT 服务器之间的连接丢失时,此方法被调用。
* @param throwable 表示导致连接丢失的原因,通常为一个 Throwable 对象
*/
@Override
public void connectionLost(Throwable throwable) {
log.info("断开了MQTT连接 :{}", throwable.getMessage());
log.error(throwable.getMessage(), throwable);
}
/**
* publish发布成功后会执行到这里
*
* 方法说明:当一个消息的交付完成并且所有必要的确认都已收到时,此方法被调用。
* 注意事项:
* 对于 QoS 0 消息,在消息被网络层接收后会调用此方法。
* 对于 QoS 1 消息,在接收到 PUBACK 包后调用此方法。
* 对于 QoS 2 消息,在接收到 PUBCOMP 包后调用此方法。
* @param iMqttDeliveryToken the delivery token associated with the message.
*/
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
try {
log.info("-------发布消息成功: "+new String(iMqttDeliveryToken.getMessage().getPayload())+"-------");
} catch (MqttException e) {
throw new RuntimeException(e);
}
}
/**
* subscribe订阅后得到的消息会执行到这里
*
* 方法说明:当从服务器接收到一条新消息时,此方法被调用
* 注意事项:
* 在此方法中抛出任何异常将会导致客户端关闭,并且未确认的消息可能会被重新发送。
* 如果在此方法执行期间有其他消息到达,它们将被缓存直到此方法返回。
* @param topic 消息发布的主题名称
* @param message 实际的消息内容,类型为 MqttMessage
* @throws Exception
*/
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
// TODO 此处可以将订阅得到的消息进行业务处理、数据存储
log.info("收到来自主题 " + topic + " 的消息:{}", new String(message.getPayload()));
}
}
4.安装mosquitto
Mosquitto是用C语言实现MQTT协议的Broker。是一款实现了消息推送协议 MQTT v3.1 的开源消息代理软件,提供轻量级的,支持可发布/可订阅的的消息推送模式,使设备对设备之间的短消息通信变得简单,比如现在应用广泛的低功耗传感器,手机、嵌入式计算机、微型控制器等移动设备。一个典型的应用案例就是 Andy Stanford-ClarkMosquitto(MQTT协议创始人之一)在家中实现的远程监控和自动化。
官网:https://mosquitto.org/download/
网盘链接: https://pan.baidu.com/s/1wbDxPf7argZnYz4rrLA8CQ 提取码: pym7
下载完安装一直点击next即可,需要注意的是安装完成后打开服务查看mosquitto是否启动(可能会出现端口冲突导致启动失败)
5.安装MQTT.fx
MQTT.fx是一个基于Eclipse Paho用Java编写的MQTT客户端软件。支持通过Topic订阅和发布消息,用来前期模拟设备和物理云平台等调试。
本文中使用MQTT.fx来模拟设备发送消息
网盘链接: https://pan.baidu.com/s/1s54mXu-Bi-ojoJuB1jycNg 提取码: 2yki
1.下载完安装一直点击next即可,安装成功后先编辑连接信息
2.消息的发送
3.消息的监听
4.结果展示:
使用接口mqtt/mqttTest01发送消息,然后查看控制台打印的日志信息
https://pan.baidu.com/s/1s54mXu-Bi-ojoJuB1jycNg 提取码: 2yki
1.下载完安装一直点击next即可,安装成功后先编辑连接信息
[外链图片转存中…(img-HcczJnBd-1751361454619)]
2.消息的发送
[外链图片转存中…(img-ncLT6twJ-1751361454620)]
3.消息的监听
[外链图片转存中…(img-iG000Gpn-1751361454620)]
4.结果展示:
[外链图片转存中…(img-e8FL0ug7-1751361454620)]
使用接口mqtt/mqttTest01发送消息,然后查看控制台打印的日志信息