SpringBoot通过Moquette集成MQTT Broker快速实现设备管理消息订阅与发布

发布时间:2026/7/17 5:51:13

SpringBoot通过Moquette集成MQTT Broker快速实现设备管理消息订阅与发布
一、引言1.1 什么是 MQTTMQTT 是一种基于发布/订阅范式的轻量级消息传输协议。该协议专为计算资源受限、带宽有限以及网络连接不稳定的设备设计具有报文结构简洁、功耗低、传输可靠等特点。1.2 为什么选择 Moquette当业务需求比较简单没必要或开发受限无法在服务器部署第三方服务例如 EMQX、Mosquitto、HiveMQ那么就需要在 SpringBoot 中集成 MQTT Broker。Moquette 是一个轻量级嵌入式 Broker可以轻松封装在其他应用程序中。但由于0.18之前的版本不支持 MQTT5所以这里选择 Fraunhofer 维护的新分支。二、依赖配置!-- MQTT BrokerMoquette --dependencygroupIdde.fraunhofer.iosb.io.moquette/groupIdartifactIdmoquette-broker/artifactIdversion0.18.4/version/dependency三、代码整合3.1 创建配置类importio.moquette.broker.Server;importio.moquette.broker.config.IConfig;importio.moquette.broker.config.MemoryConfig;importio.moquette.interception.InterceptHandler;importjakarta.annotation.PostConstruct;importjakarta.annotation.PreDestroy;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.util.Arrays;importjava.util.List;importjava.util.Properties;ConfigurationpublicclassMqttBrokerConfig{privateServermqttBroker;AutowiredprivateCustomInterceptHandlerinterceptHandler;PostConstructpublicvoidstartBroker(){mqttBrokernewServer();PropertiespropsnewProperties();props.setProperty(port,1883);//监听端口默认 1883props.setProperty(host,0.0.0.0);//绑定地址0.0.0.0 表示允许所有 IP 访问props.setProperty(allow_anonymous,false);//禁止匿名登录必须用户名密码认证必须设为 false//性能相关配置props.setProperty(max_inflight_queue,1000);//单个客户端最大未确认消息队列长度防止消息堆积props.setProperty(netty.mqtt.message_size,65536);//最大消息体大小64KBprops.setProperty(persistence_enabled,true);//是否开启持久化props.setProperty(persistence_type,file);//持久化存储类型props.setProperty(data_path,D:\\haooo\\tempFile\\mqttFile);//持久化文件存放目录props.setProperty(persistence_recover_on_startup,true);//持久化启动时自动恢复props.setProperty(max_queued_messages,10000);//最大队列消息数IConfigconfignewMemoryConfig(props);try{ListInterceptHandlerhandlersArrays.asList(interceptHandler);mqttBroker.startServer(config,handlers,null,deviceAuthenticator,null);System.out.println(✅ Moquette MQTT Broker 启动成功端口 1883);}catch(Exceptione){System.err.println(❌ Moquette Broker 启动失败);e.printStackTrace();}}PreDestroypublicvoidstopBroker(){if(mqttBroker!null){mqttBroker.removeInterceptHandler(interceptHandler);mqttBroker.stopServer();System.out.println(✅ Moquette MQTT Broker 已停止);}}BeanpublicServermqttServer(){returnmqttBroker;//返回已启动的实例}}3.2 自定义认证importcom.github.benmanes.caffeine.cache.Cache;importcom.github.benmanes.caffeine.cache.Caffeine;importio.moquette.broker.security.IAuthenticator;importorg.springframework.stereotype.Component;importjava.time.Duration;/** * 自定义认证 * Moquette 支持插件式认证实现 IAuthenticator */ComponentpublicclassDeviceAuthenticatorimplementsIAuthenticator{privatefinalCacheString,BooleanauthCacheCaffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(5)).build();OverridepublicbooleancheckValid(StringclientId,Stringusername,byte[]password){if(usernamenull||passwordnull||clientIdnull){System.out.println(❌ 设备认证失败用户名或密码或客户端标识为空);returnfalse;}StringpwdStrnewString(password);//验证设备是否存在5分钟内的验证结果进行缓存避免认证失败的设备频繁重试BooleancachedauthCache.getIfPresent(clientId:username);if(cached!null){returncached;}else{//数据库查询DevicedeviceDeviceMapper.selectDevice(username,clientId,pwdStr);if(device!null){System.out.println(✅ 设备认证成功: clientId | username | pwdStr);authCache.put(clientId:username,true);returntrue;}else{authCache.put(clientId:username,false);}}System.out.println(❌ 设备认证失败: clientId | username | pwdStr);returnfalse;}}3.3 消息处理importio.moquette.interception.AbstractInterceptHandler;importio.moquette.interception.messages.InterceptConnectMessage;importio.moquette.interception.messages.InterceptDisconnectMessage;importio.moquette.interception.messages.InterceptPublishMessage;importio.netty.buffer.ByteBuf;importorg.springframework.stereotype.Component;importjava.nio.charset.StandardCharsets;ComponentpublicclassCustomInterceptHandlerextendsAbstractInterceptHandler{OverridepublicStringgetID(){returnCustomInterceptHandler;}OverridepublicvoidonConnect(InterceptConnectMessagemsg){System.out.println(✅ 设备连接成功: msg.getClientID() | msg.getUsername());//TODO: 更新数据库设备在线离线状态}OverridepublicvoidonDisconnect(InterceptDisconnectMessagemsg){System.out.println(❌ 设备连接断开: msg.getClientID() | msg.getUsername());//TODO: 更新数据库设备在线离线状态}OverridepublicvoidonPublish(InterceptPublishMessagemsg){ByteBufbufmsg.getPayload();if(bufnull||buf.readableBytes()0){return;}byte[]bytesnewbyte[buf.readableBytes()];buf.getBytes(buf.readerIndex(),bytes);StringpayloadnewString(bytes,StandardCharsets.UTF_8);System.out.println(✅ 设备发布消息: msg.getClientID() | msg.getUsername() | msg.getTopicName() | payload);//处理设备发送的消息if(msg.getTopicName().matches(devices/[^/]/[^/]/resp)){//处理设备发布主题}else{System.out.println(❌ 未匹配设备发布消息: msg.getClientID() | msg.getUsername() | msg.getTopicName() | payload);}}OverridepublicvoidonSessionLoopError(Throwablecause){System.out.println(❌ 会话循环错误: cause.getMessage());}}3.4 发送指令importcom.alibaba.fastjson2.JSONObject;importio.moquette.broker.Server;importio.netty.buffer.ByteBuf;importio.netty.buffer.Unpooled;importio.netty.handler.codec.mqtt.*;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Lazy;importorg.springframework.stereotype.Service;ServicepublicclassMqttCommandService{AutowiredLazyprivateServermqttBroker;/** * 向指定设备发送指令 * param clientId 客户端标识 * param username 设备序列号 * param command 指令内容 */publicvoidsendCommand(StringclientId,Stringusername,JSONObjectcommand){Stringtopicdevices/clientId/username/cmd;//订阅主题try{MqttFixedHeadermqttFixedHeadernewMqttFixedHeader(MqttMessageType.PUBLISH,false,MqttQoS.AT_LEAST_ONCE,false,0);MqttPublishVariableHeadervariableHeadernewMqttPublishVariableHeader(topic,0);ByteBufpayloadUnpooled.wrappedBuffer(command.toJSONString().getBytes());MqttPublishMessagemsgnewMqttPublishMessage(mqttFixedHeader,variableHeader,payload);mqttBroker.internalPublish(msg,clientId);System.out.println(✅ 已下发指令到设备 username → command);}catch(Exceptione){e.printStackTrace();}}}四、测试使用 MQTTX 进行测试/** * 测试Controller */RestControllerRequestMapping(/test)publicclassTestControllerextendsBaseController{AutowiredprivateMqttCommandServicemqttCommandService;/** * MQTT消息发送 */PostMapping(/command)publicRcommand(RequestBodyJSONObjectparams){mqttCommandService.sendCommand(params.getString(clientId),params.getString(username),params.getJSONObject(command));returnsuccess();}}

相关新闻

Dify 流程节点配置完全指南

Dify 流程节点配置完全指南

2026/7/17 5:51:13

Dify 流程节点配置完全指南 文档说明: 本文档依据 Dify 官方文档整理,覆盖工作流、对话流全部节点配置,每个节点附带可直接复制使用的实操配置示例,适配 Version1.13.3 版本。 目录: 一、基础入口与输出节点 2 1.1 开始…

YOLOv11【第十九章:行业垂直应用与定制篇·第9节】电力巡检——输电线缺陷 + 绝缘子破损无人机检测!

YOLOv11【第十九章:行业垂直应用与定制篇·第9节】电力巡检——输电线缺陷 + 绝缘子破损无人机检测!

2026/7/17 5:51:13

🏆本文收录于专栏 《YOLOv11实战:从入门到深度优化》。 本专栏围绕 YOLOv11 的改进、训练、部署与工程优化 展开,系统梳理并复现当前主流的 YOLOv11 实战案例与优化方案,内容目前已覆盖 分类、检测、分割、追踪、关键点、OBB 检测 等多个方向。 整体坚持 持续更新 + 深度解…

zed 新特性:终端选中自动复制

zed 新特性:终端选中自动复制

2026/7/17 5:51:13

引言 对于后端、运维、云原生开发者而言,终端复制是日均高频操作:容器日志、镜像地址、SQL、文件路径、报错堆栈都需要反复选取粘贴。copy on select(选中自动复制)看似微小功能,却直接决定连续工作流是否被打断。Zed …

深度学习模型压缩技术:量化、剪枝与蒸馏实战

深度学习模型压缩技术:量化、剪枝与蒸馏实战

2026/7/17 7:31:17

1. 深度学习模型压缩的核心价值与挑战在移动端和嵌入式设备上部署深度学习模型时,我们常常面临一个尴尬的现实:实验室里准确率高达95%的CNN模型,放到手机上运行需要3秒才能处理一张图片,内存占用直接爆掉512MB。这就是模型压缩技术…

Codex App Windows版worktree实战:多环境隔离与配置管理

Codex App Windows版worktree实战:多环境隔离与配置管理

2026/7/17 7:31:17

1. 项目概述:为什么一个“worktree”能让你从Codex App Windows用户变成真正高手?Codex App Windows版,最近在技术写作、文档自动化和本地AI辅助编程圈子里火得有点突然。很多人第一次打开它,发现界面清爽、响应快、中文支持还行&…

极速语音转写终极指南:如何使用faster-whisper实现4倍加速

极速语音转写终极指南:如何使用faster-whisper实现4倍加速

2026/7/17 7:31:17

极速语音转写终极指南:如何使用faster-whisper实现4倍加速 【免费下载链接】faster-whisper Faster Whisper transcription with CTranslate2 项目地址: https://gitcode.com/GitHub_Trending/fa/faster-whisper 你是否还在为语音转写速度慢、内存占用高而烦…

昉·星光2 RISC-V单板计算机GPU性能解析与优化

昉·星光2 RISC-V单板计算机GPU性能解析与优化

2026/7/17 7:31:17

1. 昉星光 2单板计算机的硬件架构解析作为全球首款面向边缘计算的RISC-V架构Linux单板计算机,昉星光2(VisionFive 2)采用了赛昉科技自主研发的惊鸿7100系列处理器。这款SoC的核心是采用64位RISC-V指令集的JH7110芯片,其四核设计主…

MySQL连接拒绝错误排查与解决方案

MySQL连接拒绝错误排查与解决方案

2026/7/17 7:31:17

1. MySQL连接拒绝错误的本质与常见场景当你在终端或应用程序中看到"Cant connect to MySQL server on xxx (61 "Connection refused")"这个错误时,本质上表示客户端无法与MySQL服务器建立TCP连接。这个错误发生在网络层,比认证错误&…

AI-Shoujo HF Patch安装配置全攻略:从原理到实战避坑指南

AI-Shoujo HF Patch安装配置全攻略:从原理到实战避坑指南

2026/7/17 7:21:17

1. 项目概述:为什么你需要HF Patch?如果你正在玩AI-Shoujo这款游戏,并且感觉原版内容在角色互动、场景构建或者功能扩展上有些“意犹未尽”,那么你大概率已经听说过HF Patch(High-Fidelity Patch,高保真增强…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/16 0:35:09

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/16 14:29:31

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/16 14:18:17

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

Cursor终端插件生态避坑指南:23个实测低效插件黑名单,附3个自研轻量替代方案

Cursor终端插件生态避坑指南:23个实测低效插件黑名单,附3个自研轻量替代方案

2026/7/17 0:00:57

更多请点击: https://intelliparadigm.com 第一章:Cursor终端插件生态避坑指南概览 Cursor 作为基于 VS Code 内核构建的 AI 原生编辑器,其终端插件生态虽活跃,但存在兼容性断层、权限策略突变与调试链路断裂等典型风险。开发者常…

ChatGPT写作提示词效率革命:单条提示词响应质量提升3.8倍的关键变量(附可复用提示词矩阵表)

ChatGPT写作提示词效率革命:单条提示词响应质量提升3.8倍的关键变量(附可复用提示词矩阵表)

2026/7/17 0:00:57

更多请点击: https://codechina.net 第一章:ChatGPT写作提示词效率革命:单条提示词响应质量提升3.8倍的关键变量(附可复用提示词矩阵表) 提示词工程已从经验试错迈入变量驱动的科学阶段。实证研究表明,影响…

DeepSeek V4替换Codex底座模型的实践与优化

DeepSeek V4替换Codex底座模型的实践与优化

2026/7/17 0:00:57

1. 为什么选择用DeepSeek V4替换Codex的底座模型去年我在开发一个智能代码补全工具时,发现Codex的默认底座模型在复杂业务逻辑场景下表现不尽如人意。经过多次测试对比,DeepSeek V4在以下几个关键指标上展现出明显优势:代码补全准确率&#x…