Mqtt消费端实现的几种方式

2024-09-03 22:36
文章标签 实现 方式 几种 mqtt 消费

本文主要是介绍Mqtt消费端实现的几种方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

此处测试的mqtt的Broker是使用的EMQX 5.7.1,可移步至https://blog.csdn.net/tiantang_1986/article/details/140443513查看详细介绍

一、方式1

添加必要的依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-mqtt</artifactId>
</dependency>

配置

# mqtt 服务端配置
spring:# mqtt 配置mqtt:url: tcp://127.0.0.1:1883,tcp://127.0.0.2:1883clientId: "00000001"       # 客户端Id(不可重复)username: <访问用户名>      # 认证的用户名password: <访问密码>        # 认证的密码qos: 1topic: test/#              # 监听的topic

读取配置文件

import org.apache.commons.lang3.StringUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;@Data
@Configuration
@ConfigurationProperties(prefix = "spring.mqtt")
public class MqttConfig {private String username;private String password;private String url;private String clientId;private String topic;private Integer qos;@Beanpublic MqttPahoClientFactory mqttClientFactory() {DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();MqttConnectOptions options = new MqttConnectOptions();options.setUserName(username);options.setPassword(password.toCharArray());if (StringUtils.isNotBlank(url) && url.contains(",")) {options.setServerURIs(url.split(","));} else {options.setServerURIs(new String[]{url});}        options.setCleanSession(true);//自动重连options.setAutomaticReconnect(true);//设置超时时间,单位为秒options.setConnectionTimeout(0);//设置心跳时间 单位为秒,表示服务器每隔 1.5*20秒的时间向客户端发送心跳判断客户端是否在线options.setKeepAliveInterval(90);//设置遗嘱消息options.setWill("will_topic", (this.clientId + "与服务器断开连接").getBytes(), qos, false);factory.setConnectionOptions(options);factory.setPersistence(new MemoryPersistence());return factory;}
}

MQTT消息入站配置

@Slf4j
@Configuration
@IntegrationComponentScan
public class MqttInboundConfiguration {@Resourceprivate MqttConfig mqttConfig;@Resourceprivate MqttPahoClientFactory mqttClientFactory;@Resourceprivate MqttMessageReceiver mqttMessageReceiver;@Beanpublic MessageChannel mqttInBoundChannel() {return new PublishSubscribeChannel();}@Beanpublic MessageProducerSupport mqttInbound() {MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(mqttConfig.getClientId(), mqttClientFactory, mqttConfig.getTopic());DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter();//传输Hex数据,如果是String则可使用默认值falseconverter.setPayloadAsBytes(true);adapter.setConverter(converter);adapter.setRecoveryInterval(10000);adapter.setQos(mqttConfig.getQos());adapter.setOutputChannel(mqttInBoundChannel());return adapter;}@Bean@ServiceActivator(inputChannel = "mqttInBoundChannel")public MessageHandler mqttMessageHandler() {return this.mqttMessageReceiver;}
}

消费者

@Slf4j
@Component
public class MqttMessageReceiver implements MessageHandler {@Resourceprivate DataConvertStrategyFactory convertStrategyContext;@Overridepublic void handleMessage(Message<?> message) throws MessagingException {MessageHeaders headers = message.getHeaders();String topic = (String) headers.get(MqttHeaders.RECEIVED_TOPIC);if (StringUtils.isNotBlank(topic)) {return;}byte[] payload = (byte[]) message.getPayload();log.info("topic: {}, message: {}", topic, HexUtils.bytesToHex(payload));//从topic中获取clientId,topic的格式:{业务}/{clientId}/{事件标识}Map<String, String> map = MqttDataConverter.covertTopic(topic);String clientId = map.get("clientId");log.info("clientId: {}", clientId);//topic中的事件标识String eventUrl = map.get("event");//自定义的enum,主要用来消息处理消息分组,相同组可以使用相同的数据转换服务Event[] events = Event.values();String deviceId = clientId;Arrays.stream(events).filter(item -> item.getEvent().equals(eventUrl)).findFirst().ifPresent(item -> {//使用策略模式实现DataConvertService convertService = convertStrategyContext.getStrategy(item.getGroup());convertService.convert(deviceId, eventUrl, payload);});}
}

数据转换服务接口,具体的数据解析只要实现这个接口就行

public interface DataConvertService {/*** 转换数据** @param clientId 设备SN* @param topic  topic* @param data  数据* @return*/Boolean convert(String clientId, String topic, byte[] data);/*** 获取转换器** @return*/String getConverter();
}

MQTT数据转换策略工厂

@Component
public class DataConvertStrategyFactory implements InitializingBean {@Resourceprivate List<DataConvertService> handlers;private Map<String, DataConvertService> dataConvertServiceMap = new ConcurrentHashMap<>();/*** 初始化*/@Overridepublic void afterPropertiesSet() {//进行初始化if (CollectionUtils.isNotEmpty(handlers)) {handlers.forEach(item -> {dataConvertServiceMap.put(item.getConverter(), item);});}}/*** 返回实际处理对象** @param strategy 处理策略* @return 实际处理对象*/public DataConvertService getStrategy(String strategy) {return dataConvertServiceMap.get(strategy);}
}

二、方式2

使用EMQXWebhook钩子
首先创建钩子函数,把需要监听的事件加上处理逻辑,示例:

@Slf4j
@RequestMapping("/mqtt/client")
@RestController
public class ClientController {@PostMapping("/webhook")public Result webhook(@RequestBody Map<String, Object> message) {log.info("webhook map:{}", message);String action = (String) message.get("action");String clientid = (String) message.get("clientid");if ("client_connected".equals(action)) {log.info("client:{} 上线", clientid);}if ("client_disconnected".equals(action)) {log.info("client:{} 下线", clientid);}if ("message.publish".equals(action)) {log.info("已接收到 client:{} 的消息:{}", clientid, message.get("payload"));}return Result.success("OK");}
}

然后在EMQX的Dashboard中创建Webhook,可以选择多个触发器
在这里插入图片描述
填好URL后可以进行测试,之后使用MQTTX进行消息发送测试
在这里插入图片描述
控制台输出日志
在这里插入图片描述

三、方式3

package com.iinplus.mqtt.handler;import com.iinplus.mqtt.config.MqttConfig;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;import javax.annotation.Resource;@Slf4j
@Component
public class MqttSubscriber implements InitializingBean {@Resourceprivate MqttConfig config;@Overridepublic void afterPropertiesSet() {try {MqttClient client = new MqttClient(config.getUrl(), config.getClientId(), new MemoryPersistence());MqttConnectOptions options = new MqttConnectOptions();options.setUserName(config.getUsername());options.setPassword(config.getPassword().toCharArray());options.setCleanSession(true);options.setAutomaticReconnect(true);options.setConnectionTimeout(0);client.connect(options);client.subscribe(config.getTopic());//设置消息回调client.setCallback(new MqttMsgHandler());} catch (MqttException e) {log.error("MqttException:", e);}}
}

消息回调处理

@Slf4j
public class MqttMsgHandler implements MqttCallback {@Overridepublic void connectionLost(Throwable t) {// 连接丢失log.info("Connection lost:", t);}@Overridepublic void messageArrived(String topic, MqttMessage message) {// 接收到消息log.info("Message arrived:" + new String(message.getPayload()));}@Overridepublic void deliveryComplete(IMqttDeliveryToken token) {// 消息发送成功log.info("Delivery complete");}
}

这篇关于Mqtt消费端实现的几种方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1134238

相关文章

Android实现悬浮按钮功能

《Android实现悬浮按钮功能》在很多场景中,我们希望在应用或系统任意界面上都能看到一个小的“悬浮按钮”(FloatingButton),用来快速启动工具、展示未读信息或快捷操作,所以本文给大家介绍... 目录一、项目概述二、相关技术知识三、实现思路四、整合代码4.1 Java 代码(MainActivi

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

基于Python实现读取嵌套压缩包下文件的方法

《基于Python实现读取嵌套压缩包下文件的方法》工作中遇到的问题,需要用Python实现嵌套压缩包下文件读取,本文给大家介绍了详细的解决方法,并有相关的代码示例供大家参考,需要的朋友可以参考下... 目录思路完整代码代码优化思路打开外层zip压缩包并遍历文件:使用with zipfile.ZipFil

Python实现word文档内容智能提取以及合成

《Python实现word文档内容智能提取以及合成》这篇文章主要为大家详细介绍了如何使用Python实现从10个左右的docx文档中抽取内容,再调整语言风格后生成新的文档,感兴趣的小伙伴可以了解一下... 目录核心思路技术路径实现步骤阶段一:准备工作阶段二:内容提取 (python 脚本)阶段三:语言风格调

C#实现将Excel表格转换为图片(JPG/ PNG)

《C#实现将Excel表格转换为图片(JPG/PNG)》Excel表格可能会因为不同设备或字体缺失等问题,导致格式错乱或数据显示异常,转换为图片后,能确保数据的排版等保持一致,下面我们看看如何使用C... 目录通过C# 转换Excel工作表到图片通过C# 转换指定单元格区域到图片知识扩展C# 将 Excel

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指