MQTT(Message Queuing Telemetry Transport, 消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为远程连接设备提过实时可靠的消息服务,作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(loT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。
1. 引入依赖
| <dependency> |
| <groupId>org.springframework.integration</groupId> |
| <artifactId>spring-integration-mqtt</artifactId> |
| <version>5.5.14</version> |
| </dependency> |
2. 创建配置文件类
| @Configuration |
| @ConfigurationProperties(prefix = "mqtt") |
| @Data |
| public class MqttConfiguration { |
| private String url; |
| private String clientId; |
| private String topics; |
| private String username; |
| private String password; |
| private String timeout; |
| private String keepalive; |
| } |
在application.yaml中添加具体配置,这里使用的中间件是emqx
| mqtt: |
| url: tcp://127.0.0.1:1883 |
| clientId: test_mqtt_client |
| topics: test/# |
| username: admin |
| password: public |
| timeout: 10 |
| keepalive: 20 |
3. 创建生产端
| |
| |
| |
| @Configuration |
| public class Publisher { |
| |
| @Resource |
| private MqttConfiguration mqttConfiguration; |
| |
| @Bean |
| public MessageChannel mqttOutboundChannel() { |
| return new DirectChannel(); |
| } |
| |
| |
| |
| |
| @Bean |
| public MqttPahoClientFactory mqttOutClient() { |
| DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); |
| String[] mqttServerUrls = mqttConfiguration.getUrl().split(","); |
| MqttConnectOptions mqttConnectOptions = new MqttConnectOptions(); |
| mqttConnectOptions.setServerURIs(mqttServerUrls); |
| mqttConnectOptions.setUserName(mqttConfiguration.getUsername()); |
| mqttConnectOptions.setPassword(mqttConfiguration.getPassword().toCharArray()); |
| |
| mqttConnectOptions.setCleanSession(false); |
| factory.setConnectionOptions(mqttConnectOptions); |
| |
| return factory; |
| } |
| |
| @Bean |
| @ServiceActivator(inputChannel = "mqttOutboundChannel") |
| public MessageHandler mqttOutbound() { |
| MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(mqttConfiguration.getClientId() + "_outbound_iot", |
| mqttOutClient()); |
| messageHandler.setDefaultTopic("test"); |
| messageHandler.setAsync(true); |
| return messageHandler; |
| } |
| |
| } |
4. 创建消费端
| |
| |
| |
| |
| @Slf4j |
| @Configuration |
| @IntegrationComponentScan |
| public class Consumer { |
| @Resource |
| private MqttConfiguration mqttProperties; |
| |
| @Bean |
| public MessageChannel mqttInputChannel() { |
| return new DirectChannel(); |
| } |
| |
| @Bean |
| public MqttPahoClientFactory mqttInClient() { |
| if (!mqttProperties.getEnabled()) { |
| return null; |
| } |
| DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); |
| |
| String[] mqttServerUrls = mqttProperties.getUrl().split(","); |
| MqttConnectOptions options = new MqttConnectOptions(); |
| options.setServerURIs(mqttServerUrls); |
| options.setUserName(mqttProperties.getUsername()); |
| options.setPassword(mqttProperties.getPassword().toCharArray()); |
| options.setKeepAliveInterval(2); |
| |
| |
| options.setCleanSession(false); |
| factory.setConnectionOptions(options); |
| return factory; |
| } |
| |
| |
| |
| |
| @Bean |
| public MessageProducer inbound() { |
| String[] inboundTopics = mqttProperties.getTopics().split(","); |
| MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(mqttProperties.getClientId() + "_inbound", |
| mqttInClient(), inboundTopics); |
| |
| adapter.setCompletionTimeout(1000 * 5); |
| adapter.setQos(1); |
| adapter.setConverter(new DefaultPahoMessageConverter()); |
| adapter.setOutputChannel(mqttInputChannel()); |
| return adapter; |
| } |
| |
| |
| |
| |
| @Bean |
| @ServiceActivator(inputChannel = "mqttInputChannel") |
| public MessageHandler handler() { |
| return message -> { |
| Object payload = message.getPayload(); |
| MessageHeaders messageHeaders = message.getHeaders(); |
| Object qos = messageHeaders.get(MqttHeaders.RECEIVED_QOS); |
| String topic = (String) messageHeaders.get(MqttHeaders.RECEIVED_TOPIC); |
| |
| String handMessage = "收到消息" + " topic ===> " + topic + "\nQOS ===> " + qos + "\n内容 ===> " + payload; |
| System.out.println(handMessage); |
| } |
| } |
| } |
5. 发送mqtt消息
| |
| |
| |
| @Service |
| @MessagingGateway(defaultRequestChannel = "mqttOutboundChannel") |
| public interface MqttGateWayService { |
| void sendMessageToMqtt(String data); |
| |
| void sendMessageToMqtt(String data, @Header(MqttHeaders.TOPIC) String topic); |
| |
| void sendMessageToMqtt(String data,@Header(MqttHeaders.TOPIC) String topic,@Header(MqttHeaders.QOS) int qos); |
| |
| void sendMessageToMqtt(byte[] data,@Header(MqttHeaders.TOPIC) String topic,@Header(MqttHeaders.QOS) int qos); |
| } |
测试消息发送
| |
| |
| |
| @RestController |
| @RequestMapping("/mqtt") |
| @Validated |
| public class MqttController { |
| |
| @Resource |
| private MqttGateWayService gateWay; |
| |
| @PostMapping(value = "/sendMqtt") |
| public void sendMqtt(@RequestParam(value = "topic") String topic, |
| @RequestParam(value = "msg") String msg, |
| @RequestParam(value = "qos") int qos) { |
| gateWay.sendMessageToMqtt(msg, topic, qos); |
| } |
| } |
| |
6. 补充
6.1 发送指定编码数据
在有些设备开发中,发送中文字符需要使用他指定的编码格式,例如GBK
发送时可以使用MqttGateWayService中的第四个方法
可以使用工具MQTT.fx进行测试,发送的中文是GBK编码,MQTTX则是UTF-8
| @PostMapping(value = "/sendGBK") |
| public void sendMqtt(@RequestParam(value = "topic") String topic, |
| @RequestParam(value = "msg") String msg, |
| @RequestParam(value = "qos") int qos) { |
| gateWay.sendMessageToMqtt(msg.getBytes("GBK"), topic, qos); |
| } |
6.2 接收编码数据
如果设备发送的中文字符也是GBK编码格式,需要修改一处
| @Bean |
| public MessageProducer inbound() { |
| String[] inboundTopics = mqttProperties.getTopics().split(","); |
| MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(mqttProperties.getClientId() + "_inbound", |
| mqttInClient(), inboundTopics); |
| |
| adapter.setCompletionTimeout(1000 * 5); |
| adapter.setQos(1); |
| |
| |
| DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter(); |
| defaultPahoMessageConverter.setPayloadAsBytes(true); |
| adapter.setConverter(defaultPahoMessageConverter); |
| |
| adapter.setOutputChannel(mqttInputChannel()); |
| return adapter; |
| } |
收到数据后处理后即可使用
| Object payload = message.getPayload(); |
| String data = ""; |
| try { |
| if (payload instanceof byte[]) { |
| data = new String((byte[]) payload, "GBK"); |
| } else if (payload instanceof String) { |
| data = (String) payload; |
| } |
| } catch (UnsupportedEncodingException e) { |
| log.info("解码失败"); |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)