MQTT
安装
服务端
# 配置 EMQX Yum 源
curl -s https://assets.emqx.com/scripts/install-emqx-rpm.sh | sudo bash
#安装 EMQX
yum install emqx -y
#启动 EMQX,开放端口
systemctl start emqx
#在浏览器输入服务器公网ip:18083,访问,进入登录界面admin/public
#配置文件:
/etc/emqx/emqx.conf
curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash
sudo apt-get install emqx
sudo emqx start
客户端
Java集成SrpingBoot
pom.xml
<!-- MQTT -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
<version>5.5.12</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
application.yml
mqtt:
broker:
# 设备MQTT应用配置
url: tcp://your_server_ip:1883
username: your_username
password: your_password
# 自定义约定client_id
clientId: your_client_id
topics:
# 默认监听
default: your/default_topic
# 自定义监听
subscriptions:
- your/topic1
- your/topic2
# application.properties配置如下
# MQTT 设备应用配置
# mqtt.broker.url=tcp://your_server_ip:1883
# mqtt.broker.username=your_username
# mqtt.broker.password=your_password
# mqtt.broker.clientId=terminalTcpServer
# MQTT 监听的默认主题和自定义订阅主题
# mqtt.topics.default=your/default_topic
# mqtt.topics.subscriptions=your/topic1,your/topic2
MqttConfig配置类
import com.baoer.terminaltcpserver.mqtt.utils.MqttUtil;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
@Configuration
public class MqttConfig {
// @Autowired
// private MqttUtil mqttUtil;
@Value("${mqtt.broker.url}")
private String brokerUrl;
@Value("${mqtt.broker.username}")
private String username;
@Value("${mqtt.broker.password}")
private String password;
@Value("${mqtt.broker.clientId}")
private String clientId;
@Value("${mqtt.topics.default}")
private String defaultTopic;
@Value("${mqtt.topics.subscriptions}")
private String[] topics;
// 配置MQTT客户端工厂
@Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
MqttConnectOptions options = new MqttConnectOptions();
options.setServerURIs(new String[]{brokerUrl});
options.setUserName(username);
options.setPassword(password.toCharArray());
// 设置自动重连
options.setAutomaticReconnect(true);
// 设置连接超时,单位为秒
options.setConnectionTimeout(10);
// 设置心跳时间,单位为秒
options.setKeepAliveInterval(60);
// Clean Start(会话清理),设置为 true 表示每次客户端连接服务器时清理会话
options.setCleanSession(false);
// 设置最大重连间隔时间,单位为秒
options.setMaxReconnectDelay(60);
factory.setConnectionOptions(options);
return factory;
}
// (接收消息:步骤一)定义一个消息通道,用于接收消息
@Bean
public MessageChannel mqttInputChannel() {
return new DirectChannel();
}
// (接收消息:步骤二)配置消息驱动通道适配器,用于接收指定主题的消息
@Bean
public MessageProducer inbound() {
MqttPahoMessageDrivenChannelAdapter adapter =
new MqttPahoMessageDrivenChannelAdapter(clientId + MqttClient.generateClientId(), mqttClientFactory(), topics);
adapter.setOutputChannel(mqttInputChannel());
return adapter;
}
// (接收消息:步骤三)配置消息处理器,用于处理接收到的消息
@Bean
@ServiceActivator(inputChannel = "mqttInputChannel")
public MessageHandler handler(MqttUtil mqttUtil) {
return message -> {
String topic = message.getHeaders().get("mqtt_receivedTopic").toString();
String payload = message.getPayload().toString();
System.out.println("接收到消息: 主题 = " + topic + ", 内容 = " + payload);
// 发布接收到的消息事件
mqttUtil.publishReceivedMessage(topic, payload);
};
}
// 配置MQTT消息发送处理器
@Bean
@ServiceActivator(inputChannel = "mqttOutboundChannel")
public MessageHandler mqttOutbound() {
MqttPahoMessageHandler messageHandler =
new MqttPahoMessageHandler(clientId + MqttClient.generateClientId(), mqttClientFactory());
messageHandler.setAsync(true);
messageHandler.setDefaultTopic(defaultTopic); // 设置默认主题
return messageHandler;
}
// 定义一个消息通道,用于发送消息
@Bean
public MessageChannel mqttOutboundChannel() {
return new DirectChannel();
}
}
MqttUtil 工具类
import com.baoer.terminaltcpserver.mqtt.config.MqttMessageEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
@Component
public class MqttUtil {
@Autowired
private MessageChannel mqttOutboundChannel;
@Autowired
private ApplicationEventPublisher eventPublisher;
/**
* 发送消息到默认主题
* @param payload 消息内容
*/
public void sendMessage(String payload) {
mqttOutboundChannel.send(MessageBuilder.withPayload(payload).build());
}
/**
* 发送消息到指定主题
* @param topic 主题
* @param payload 消息内容
*/
public void sendMessage(String topic, String payload) {
mqttOutboundChannel.send(MessageBuilder.withPayload(payload)
.setHeader("mqtt_topic", topic)
.build());
}
/**
* (接收消息:步骤四)发布接收到的MQTT消息事件
* @param topic 主题
* @param payload 消息内容
*/
public void publishReceivedMessage(String topic, String payload) {
MqttMessageEvent event = new MqttMessageEvent(this, topic, payload);
eventPublisher.publishEvent(event);
}
}
MqttMessageEvent消息事件类
import org.springframework.context.ApplicationEvent;
public class MqttMessageEvent extends ApplicationEvent {
private final String topic;
private final String payload;
public MqttMessageEvent(Object source, String topic, String payload) {
super(source);
this.topic = topic;
this.payload = payload;
}
public String getTopic() {
return topic;
}
public String getPayload() {
return payload;
}
}
MqttMessageListener消息监听器
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MqttMessageListener {
/**
* (接收消息:步骤五)事件监听器中处理消息
* 说明:此方法将接收到上方 MqttUtil.publishReceivedMessage() 发布的事件并处理这些消息
*
* @param event 接收到的事件
*/
@EventListener
public void handleMqttMessage(MqttMessageEvent event) {
String topic = event.getTopic();
String payload = event.getPayload();
System.out.println("处理接收到的消息: 主题 = " + topic + ", 内容 = " + payload);
// 根据不同的主题进行不同的处理
if ("your/topic1".equals(topic)) {
handleTopic1Message(payload);
} else if ("your/topic2".equals(topic)) {
handleTopic2Message(payload);
}
}
private void handleTopic1Message(String payload) {
// 处理来自 topic1 的消息
System.out.println("处理 topic1 消息: " + payload);
}
private void handleTopic2Message(String payload) {
// 处理来自 topic2 的消息
System.out.println("处理 topic2 消息: " + payload);
}
}
测试
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/mqtt")
public class MqttController {
@Autowired
private MqttUtil mqttUtil;
@RequestMapping("/send")
@ResponseBody
public String sendMessage() {
mqttUtil.sendMessage("your/topic1", "Hello from Spring Boot");
return "Message sent!";
}
}
调用接口发送成功
使用MQTT X查看是否接受成功,并发送测试
查看EMQX Dashboard中MQTTX工具的连接
运行流程
1.在 件中配置MQTT服务器的URL、用户名、密码、client_id、默认主题和订阅的主题。
2.启动MQTT Broker。
3.确保硬件设备连接到MQTT Broker,并发布和订阅消息。
4.启动Spring Boot应用程序,确保它可以发送和接收MQTT消息。
5.在控制台中查看接收到的消息,并根据不同的主题进行处理(设备上行消息要用不同的topic主题发布)。
遇到问题
o.s.i.m.outbound.MqttPahoMessageHandler : Lost connection
线上程序持续报错,有时能收到消息,能收到订阅的某些订阅消息,还有些订阅消息重启开始时能收到,但是发送指令后就没有了.后查验发现是发送消息的clientId和订阅消息时的客户端clientid不能一致,需要加上MqttClient.generateClientId()客户端代码
参考:
https://blog.csdn.net/weixin_43822632/article/details/141194093
如果这篇文章对你有用,可以关注本人微信公众号获取更多ヽ(^ω^)ノ ~