【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro IoT 物联网模块:从协议网关到物模型,一文讲透开源 IoT 平台架构
大家好,我是你们的老朋友-腻害兔,今天继续我们的 RuoYi-Vue-Pro(芋道)源码拆解系列。上一期我们聊了报表模块,今天来啃一块硬骨头——IoT 物联网模块(yudao-module-iot)。
为什么说它是硬骨头?因为这个模块是整个 RuoYi-Vue-Pro 中架构最复杂、技术栈最多样、协议适配最多的模块,没有之一。它不是一个简单的 CRUD 模块,而是一个完整的 IoT 平台,涵盖了协议网关、物模型、设备管理、规则引擎、OTA 升级、告警系统等 IoT 核心能力。
废话不多说,直接上干货!
一、今日模块概览
一句话总结:IoT 物联网模块是一个支持多协议接入、多租户隔离、物模型驱动的全栈 IoT 平台。
它解决的核心问题是:让不同类型的物联网设备(MQTT、Modbus、CoAP、TCP/UDP、WebSocket、HTTP)能够通过统一的协议网关接入平台,通过物模型标准化数据结构,再通过规则引擎实现场景联动和数据流转。
整个模块分为三个子模块:
| 子模块 | 职责 | 部署方式 |
|---|---|---|
| yudao-module-iot-core | 公共基础设施:消息总线、枚举、工具类 | 共享 jar,部署在 gateway 和 biz 两端 |
| yudao-module-iot-biz | 业务逻辑层:设备管理、物模型、规则引擎、OTA、告警 | 业务服务器 |
| yudao-module-iot-gateway | 协议网关层:MQTT/Modbus/CoAP/TCP/UDP/HTTP/WebSocket/EMQX | 独立的网关服务器(可水平扩展) |
划重点!!! 网关和业务层通过消息总线(Message Bus)解耦,支持 Redis Stream、Kafka、RocketMQ、RabbitMQ 四种 MQ 实现,甚至可以退化为本地 Spring Event(单机模式)。这意味着你可以先单机跑起来,后续按需切换到分布式部署,架构弹性非常好。
二、技术选型分析
2.1 为什么用 Vert.x 而不是 Netty 做协议网关?
这是我在读代码时最好奇的一个问题。RuoYi 的主框架是 Spring Boot + Spring MVC,但网关层却选择了 Vert.x(vertx-mqtt、vertx-web),而不是直接用 Netty 或者 Spring 生态的 Spring Integration。
我的分析:
| 维度 | Vert.x | Netty | Spring Integration |
|---|---|---|---|
| 开发效率 | 高,内置 MQTT/HTTP/WebSocket/CoAP 支持 | 低,需要自己编解码 | 中等,配置繁琐 |
| 性能 | 高(基于 Netty) | 最高 | 一般 |
| 多协议支持 | 开箱即用 | 需要自己实现 | 需要额外模块 |
| 与 Spring Boot 集成 | 有 vertx-spring-boot-starter | 需要手动管理 | 原生 |
| 响应式模型 | EventLoop 非阻塞 | EventLoop 非阻塞 | 线程池模型 |
结论: Vert.x 本质上是 Netty 的上层封装,既保留了高性能,又提供了开箱即用的多协议支持。对于 IoT 场景需要同时支持 MQTT、HTTP、WebSocket、CoAP 等多种协议,Vert.x 的开发效率优势非常明显。而且通过 lichee:vertx-spring-boot-starter-web,Vert.x 可以嵌入 Spring Boot 一起运行,不需要独立部署。
2.2 为什么用 TDengine 而不是 InfluxDB / TimescaleDB?
设备消息和属性历史数据存储在 TDengine(时序数据库),而不是更常见的 InfluxDB 或 TimescaleDB。
我的分析:
| 维度 | TDengine | InfluxDB | TimescaleDB |
|---|---|---|---|
| 国产 vs 国外 | 国产(涛思数据) | 国外 | 国外 |
| 超级表概念 | 原生支持,一个设备一张子表 | 不支持 | 不支持(普通表) |
| SQL 兼容性 | 兼容 SQL | 自有查询语法 | 完全 PostgreSQL |
| 写入性能 | 极高(专为 IoT 优化) | 高 | 中等 |
| 社区生态 | 国内活跃 | 全球活跃 | PostgreSQL 生态 |
| JDBC 驱动 | 有(taos-jdbcdriver) | 有 | 有 |
结论: TDengine 的超级表(Super Table)概念天然适合 IoT 场景——每个设备一张子表,同类型设备的超级表自动聚合查询。而且 TDengine 对 SQL 的兼容降低了学习成本,JDBC 驱动可以直接用 MyBatis-Plus 操作,和现有代码框架无缝集成。从 pom.xml 中看到引入了 taos-jdbcdriver,说明是通过标准 JDBC 方式访问的。
踩坑提醒: TDengine 的表结构是动态的——当物模型修改时,需要同步修改 TDengine 的超级表结构。代码里通过 syncProductPropertyTable 和 defineDevicePropertyData 方法实现了自动同步,这个设计很巧妙,后面会详细讲。
2.3 为什么消息总线支持 5 种实现?
消息总线(Message Bus)是连接网关和业务层的核心纽带。IotMessageBus 接口有 5 种实现:
| 实现 | 适用场景 | 特点 |
|---|---|---|
| Local(Spring Event) | 单机开发/测试 | 零依赖,但不支持多节点 |
| Redis Stream | 轻量级分布式 | 依赖 Redis,运维成本低 |
| Kafka | 高吞吐场景 | 百万级 TPS,适合大规模设备接入 |
| RocketMQ | 阿里生态 | 事务消息、延迟消息支持好 |
| RabbitMQ | 企业级消息 | 路由灵活,死信队列支持好 |
为什么不只支持一种? 因为 IoT 平台的部署规模差异极大。一个管理 100 台设备的智能楼宇系统,和一个管理 100 万台设备的工业物联网平台,对消息中间件的需求完全不同。RuoYi 的做法是:默认用 Redis(大多数场景够用),但保留了切换到专业 MQ 的能力。 这种"渐进式架构"的设计思路非常务实。
2.4 为什么用 MyBatis-Plus 而不是 JPA / Spring Data?
这个选择其实和 RuoYi 整体框架一致。MyBatis-Plus 在国内 Java 生态中占据绝对主流地位,原因是:SQL 可控、代码生成器好用、对复杂查询支持好。IoT 模块大量使用了 MyBatis-Plus 的 LambdaQueryWrapper、@TableField(JSON 类型处理器)等特性。
三、需求溯源推演
读完整套代码,我尝试还原这个 IoT 模块最初的产品需求文档大概长什么样:
3.1 核心需求推测
需求背景: 随着物联网的普及,企业需要一个统一的 IoT 平台来管理各种类型的智能设备。市面上的 IoT 平台(如阿里云 IoT、华为 IoT)虽然功能强大,但私有化部署成本高、定制灵活性差。开源社区缺少一个轻量级、可私有化部署、支持多协议的 IoT 平台。
核心用户角色:
| 角色 | 核心诉求 |
|---|---|
| 设备管理员 | 管理设备生命周期(注册、上线、下线、分组、删除) |
| 产品管理员 | 定义产品模板和物模型(属性、服务、事件) |
| 运维工程师 | 监控设备状态、处理告警、OTA 升级 |
| 集成开发者 | 通过数据流转将设备数据对接到第三方系统 |
| 规则配置员 | 配置场景联动规则(温度过高自动关阀) |
3.2 需求演进推测
从代码的成熟度和功能完整性来看,这个模块经历了至少 3 个迭代周期:
V1.0(基础版): 产品管理 + 物模型 + 设备管理 + MQTT 接入 + 设备消息存储。这是 IoT 平台的最小可用集。
V2.0(增强版): 增加 Modbus/CoAP/TCP/UDP/HTTP/WebSocket 协议支持 + 场景联动规则引擎 + 数据流转 + 告警系统。这一步把 IoT 从"能接入"升级到"能联动"。
V3.0(完整版): 增加 OTA 固件升级 + EMQX 集成 + Modbus TCP Server + 设备动态注册 + 网关子设备拓扑管理 + 统计面板。这一步补齐了企业级 IoT 平台的必备能力。
产品思考: 这个模块的迭代路径其实是一个很好的 IoT 产品规划范本——先做"连接"(协议网关),再做"数据"(物模型+存储),然后做"智能"(规则引擎),最后做"运维"(OTA+告警)。每一层都建立在前一层的基础上。
四、竞品对标分析
IoT 开源平台赛道其实非常热闹,让我们把 RuoYi IoT 和几个主流竞品做个对比:

RuoYi IoT 的优势
-
生态集成度最高: 直接复用 RuoYi 的用户、权限、租户、字典、通知等基础设施,不需要额外对接。对于已经用 RuoYi 做后台管理系统的团队,加一个 IoT 模块就能用。
-
协议覆盖最全: 8 种协议支持,特别是 Modbus TCP Client/Server 双模式,这在工业 IoT 场景非常实用。很多开源平台只支持 Modbus 一种模式。
-
EMQX 集成: 这是一个亮点。很多企业已经在用 EMQX 作为 MQTT Broker,RuoYi 通过 HTTP Hook + MQTT Client 的方式桥接 EMQX,避免了"换 Broker"的迁移成本。
-
多租户原生支持: 设备、产品、场景规则等核心表都继承了 TenantBaseDO,天然支持 SaaS 化部署。
RuoYi IoT 的劣势
-
规则引擎偏简单: 场景联动规则是简单的 Trigger-Condition-Action 模型,不支持 ThingsBoard 那种可视化的规则链编排(多个节点串联、函数计算、条件分支等)。
-
缺少可视化大屏: IoT 平台通常需要一个数据可视化大屏来展示设备地图、实时数据曲线、告警统计等。RuoYi 目前只有一个基础的统计 Controller。
-
设备影子/期望值: 阿里云 IoT 有"设备影子"功能——当设备离线时,云端缓存期望状态,设备上线后自动同步。RuoYi 目前没有这个能力。
五、核心业务流程
5.1 设备接入全流程
这是 IoT 平台最核心的流程——一台设备从"不存在"到"在线上报数据"的完整链路:
5.2 场景联动规则执行流程

5.3 OTA 升级流程
OTA(Over-The-Air)升级是 IoT 平台的运维核心能力。RuoYi 的 OTA 采用三级模型:
固件管理 → 升级任务 → 设备记录

六、数据模型解读
6.1 三库架构
RuoYi IoT 最让我眼前一亮的是它的三库架构设计:
| 存储引擎 | 存什么 | 为什么 |
|---|---|---|
| MySQL | 产品、设备、物模型、规则、告警、OTA 等元数据 | 关系型数据,需要事务和复杂查询 |
| TDengine | 设备上报的属性历史和消息日志 | 时序数据,写入量巨大,需要高效的时间范围查询 |
| Redis | 设备最新属性值、设备在线状态、规则缓存 | 高频读取,低延迟要求 |
划重点!!! 这种"元数据存 MySQL、时序数据存 TDengine、热数据存 Redis"的三层存储策略,是 IoT 平台的最佳实践。如果你要自己做一个 IoT 平台,这个架构可以直接抄。
6.2 核心表关系
iot_product_category (产品分类)
│
└── 1:N ──> iot_product (产品) ──> 1:N ──> iot_thing_model (物模型)
│ │
│ 1:N │ 物模型映射
v v
iot_device (设备) <── 1:N ── iot_device_modbus_point (Modbus 点位)
│ │
│ self-ref │ N:1
│ (gatewayId) v
└──> 网关-子设备拓扑 iot_device_modbus_config (Modbus 配置)
iot_scene_rule (场景联动) ──triggers──> 产品/设备/物模型
──actions──> 产品/设备/告警配置
iot_data_rule (数据流转) ──source──> 产品/设备
──sink──> iot_data_sink (数据目标)
iot_ota_firmware (固件) ──> iot_ota_task (任务) ──> iot_ota_task_record (记录) ──> iot_device
6.3 物模型 JSON 设计亮点
物模型(Thing Model)是整个 IoT 模块的灵魂。RuoYi 的物模型设计完全对标阿里云 Alink 规范,每条物模型记录代表一个"功能"(属性/服务/事件),通过 JSON 字段存储详细定义:
// 属性(Property)的 JSON 结构
{
"identifier": "temperature", // 标识符
"name": "温度", // 名称
"accessMode": "r", // 读写模式: r(只读) / rw(读写)
"required": true, // 是否必需
"dataType": "float", // 数据类型
"dataSpecs": { // 数据规格
"min": -40, // 最小值
"max": 120, // 最大值
"step": 0.1, // 步长
"unit": "°C" // 单位
}
}
数据类型系统使用了 Jackson 多态反序列化(@JsonTypeInfo + @JsonSubTypes),支持 9 种数据类型:int、float、double、enum、bool、text、date、struct、array。每种类型对应不同的 DataSpecs 子类,这个设计非常优雅——用一个 JSON 字段就能表达复杂的类型定义。
6.4 多租户隔离策略
| 租户隔离的表(TenantBaseDO) | 不隔离的表(BaseDO) |
|---|---|
| iot_product(产品) | iot_product_category(产品分类) |
| iot_device(设备) | iot_device_group(设备分组) |
| iot_scene_rule(场景规则) | iot_thing_model(物模型) |
| iot_device_modbus_config | iot_data_rule(数据规则) |
| iot_device_modbus_point | iot_data_sink(数据目标) |
| iot_alert_config / iot_alert_record | |
| iot_ota_firmware / iot_ota_task / iot_ota_task_record |
设计思路: 产品、设备、规则是租户级别的数据,需要隔离。而物模型、告警配置、OTA 固件等是平台级别的数据,所有租户共享。这个划分是合理的——比如告警模板通常由平台统一定义,租户只需要配置自己的场景联动规则。
七、产品设计亮点与槽点
7.1 让我眼前一亮的设计
亮点 1:消息总线的渐进式架构
从 Local(单机)→ Redis Stream(轻量分布式)→ Kafka/RocketMQ/RabbitMQ(重度分布式),用户可以根据业务规模平滑升级,不需要改一行代码,只需要改一个配置项:
yudao:
iot:
message-bus:
type: redis # 改成 kafka 就完事了
这个设计降低了 IoT 平台的入门门槛——开发阶段用 Local,上线后切 Redis,设备量大了再切 Kafka。
亮点 2:EMQX 桥接模式
很多企业已经在使用 EMQX 作为 MQTT Broker,如果让他们"换"成 RuoYi 内置的 MQTT Server,迁移成本太高。RuoYi 的做法是:通过 HTTP Hook 对接 EMQX 的认证/鉴权/事件回调,同时作为 MQTT Client 连接到 EMQX 订阅设备消息。这样 EMQX 还是 EMQX,只是"大脑"换成了 RuoYi。
亮点 3:物模型驱动 TDengine 表结构自动同步
当产品的物模型修改后,调用 syncProductPropertyTable 就能自动同步 TDengine 的超级表结构——新增属性自动 ALTER TABLE ADD COLUMN,数据类型自动映射。这个"物模型即 Schema"的设计大大降低了运维成本。
亮点 4:Modbus 双模式支持
同时支持 Modbus TCP Client(主动轮询)和 Modbus TCP Server(被动响应),覆盖了工业 IoT 中两种最常见的 Modbus 部署模式。而且 Modbus 点位可以从物模型自动生成(updateDeviceModbusPointByThingModel),减少了手动配置的工作量。
亮点 5:设备认证完全对标阿里云 Alink
MQTT 认证采用 HMAC-SHA256 签名,Topic 格式 /sys/{productKey}/{deviceName}/...,方法命名 thing.property.post 等,全部遵循阿里云 Alink 规范。这意味着:已有的 Alink 兼容设备可以零改造接入 RuoYi IoT。
7.2 我觉得可以改进的地方
槽点 1:规则引擎能力偏弱
当前的场景联动规则是简单的 Trigger-Condition-Action 模型,不支持:
- 多步骤串联(A 触发 → 延时 5 分钟 → 检查条件 → 执行动作)
- 函数计算(对属性值做数学运算后再判断)
- 可视化编排(拖拽式规则链)
ThingsBoard 的规则链引擎支持 50+ 种节点类型,包括脚本节点、延迟节点、消息过滤、关系判断等。如果要做复杂的 IoT 场景,RuoYi 当前的规则引擎会不够用。
改进建议: 可以引入类似 Node-RED 的可视化规则编排,或者集成 LiteFlow / Aviator 等轻量级规则引擎。
槽点 2:缺少设备影子(Device Shadow)
当设备离线时,如果云端想下发一个指令(比如"开灯"),当前系统只能等待设备上线后再发。阿里云 IoT 的"设备影子"功能可以缓存期望状态,设备上线后自动同步。这个功能在智能家居、智能楼宇等场景非常实用。
槽点 3:告警系统缺少分级升级机制
当前告警只有简单的"触发 → 记录 → 处理"流程,缺少:
- 告警升级(INFO 告警 30 分钟未处理 → 升级为 WARN)
- 告警收敛(同一设备 5 分钟内连续触发 → 合并为一条)
- 告警静默(维护期间屏蔽特定告警)
这些是企业级告警系统的标配能力。
槽点 4:OTA 不支持差分升级
当前 OTA 是全量升级(每次下载完整固件),对于固件体积较大的设备(比如带 Linux 系统的智能摄像头),全量下载耗时耗流量。差分升级(只下载变化部分)是更高级但很实用的能力。
槽点 5:部分表缺少租户隔离
OTA 相关的三张表(固件、任务、记录)和告警配置/记录都没有做租户隔离。如果要做多租户 SaaS 平台,这些可能需要调整——比如不同租户应该有自己的固件版本和升级策略。
八、发散性思考
8.1 这个模块还能做什么?
读完代码,我脑子里冒出很多可以扩展的方向:
方向 1:边缘计算
当前的架构是"设备 → 网关 → 云端"的集中式处理。但在工业场景中,很多实时性要求高的计算(比如异常检测、PID 控制)不能依赖云端往返。如果能在网关层嵌入轻量级规则引擎(Edge Rules),让网关本身就能做简单的判断和响应,会大大提升实时性。
方向 2:数字孪生
物模型 + 时序数据 + 设备拓扑,这三样东西组合起来就是"数字孪生"的基础。如果再加一个 3D 可视化层(比如基于 Three.js),就能构建工厂/楼宇的数字孪生体。
方向 3:AI + IoT(AIoT)
设备上报的时序数据天然适合做异常检测和预测性维护。比如:
- 用 LSTM 模型预测设备何时会故障
- 用聚类算法发现异常设备
- 用时间序列分析优化能耗
RuoYi 已经有 AI 模块(yudao-module-ai),如果把 AI 模块和 IoT 模块打通,就能实现"AIoT"的故事。
方向 4:低代码 IoT 应用开发
参考 ThingsBoard 的 Widget 系统,让用户通过拖拽组件的方式快速构建设备管理界面。想象一下:产品经理不需要写代码,就能拖出一个"温度监控仪表盘",这对企业用户的吸引力是巨大的。
8.2 如果让我重新设计
如果从零开始设计这个 IoT 模块,我会做以下调整:
-
规则引擎升级: 引入基于 DAG(有向无环图)的规则链引擎,支持可视化编排、条件分支、延时、函数计算。参考 ThingsBoard 的规则链设计,但用更轻量的实现(比如基于 LiteFlow)。
-
设备影子层: 在 Redis 中为每台设备维护一个 Shadow JSON(包含 reported 和 desired 两个状态),设备上线时自动同步差异。
-
插件化协议适配: 当前协议是硬编码在 gateway 模块中的。如果设计成 SPI 插件机制(IotProtocolProvider 接口 + @SPI 注解),第三方开发者就可以自己写协议适配器,不需要改核心代码。
-
数据湖集成: 除了 TDengine,增加对数据湖(如 Apache IoTDB、MinIO + Parquet)的支持,方便做离线分析和机器学习。
8.3 技术迁移思考
RuoYi IoT 的很多设计思路可以迁移到其他场景:
| 设计思路 | 可迁移场景 |
|---|---|
| 消息总线多实现 | 任何需要"渐进式架构"的系统(如微服务间通信) |
| 物模型(Schema 驱动) | API 网关的请求/响应 Schema 校验、低代码平台的组件属性定义 |
| 三库架构(MySQL + 时序 DB + Redis) | 任何需要同时处理元数据和时序数据的系统(如监控系统、日志平台) |
| 协议抽象层(IotProtocol 接口) | 任何需要多协议适配的系统(如支付网关对接多种支付渠道) |
| 场景联动规则引擎 | 营销自动化(用户行为触发 → 条件判断 → 发券/发短信)、DevOps 自动化运维 |
九、关键代码导读
最后,列出 5 个最值得深入阅读的代码文件,按优先级排序:
1. 消息总线核心:IotMessageBus.java
路径: yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/mq/messagebus/core/IotMessageBus.java
为什么值得读: 这是整个 IoT 模块的"血管系统"。网关和业务层之间的所有通信都通过这个接口。理解了这个接口的设计,就理解了 IoT 模块的架构精髓。它的 5 种实现(Local/Redis/Kafka/RocketMQ/RabbitMQ)也是学习消息中间件抽象的好材料。
2. 设备消息路由:IotDeviceMessageServiceImpl.java
路径: yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageServiceImpl.java
为什么值得读: 这是业务层的"消息路由器"——所有从设备端上报的消息都在这里被分类处理。handleUpstreamDeviceMessage 方法根据 method 字段将消息路由到不同的处理器(状态更新、属性存储、事件记录、OTA 进度、拓扑管理等)。读懂了这个文件,就读懂了 IoT 业务层的核心流程。
3. MQTT 协议实现:IotMqttProtocol.java
路径: yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/protocol/mqtt/IotMqttProtocol.java
为什么值得读: 这是 IoT 网关最核心的协议实现。基于 Vert.x 的 MqttServer,实现了完整的 MQTT 服务端——连接认证、Topic ACL、QoS 管理、上下行消息处理。如果你想学习如何用 Java 实现一个 MQTT Broker(或者至少理解 MQTT 协议的工作原理),这个文件是最好的参考。
4. 场景联动规则引擎:IotSceneRuleServiceImpl.java
路径: yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java
为什么值得读: 这是 IoT"智能"的核心——场景联动规则引擎。executeSceneRuleByDevice 方法展示了如何根据设备上报数据匹配规则、评估条件、执行动作。规则引擎的设计模式(Trigger → Condition → Action)可以迁移到很多其他场景(营销自动化、运维自动化等)。
5. 物模型与 TDengine 同步:IotDevicePropertyServiceImpl.java
路径: yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java
为什么值得读: 这个文件展示了"物模型驱动存储"的核心理念——defineDevicePropertyData 方法根据物模型定义动态创建 TDengine 超级表,saveDeviceProperty 方法将属性值同时写入 TDengine(历史)和 Redis(缓存)。这种"Schema 驱动存储"的设计思路非常值得学习。
总结
RuoYi-Vue-Pro 的 IoT 模块是我见过的开源 IoT 平台中功能最完整、架构最合理的实现之一。它有三个让我印象深刻的设计决策:
- 消息总线解耦网关和业务,支持从单机到分布式的平滑演进
- 三库架构(MySQL + TDengine + Redis),每种数据存到最适合的地方
- 物模型驱动一切——从 API 定义到存储 Schema 到 Modbus 点位映射,物模型是贯穿整个系统的核心抽象
如果你正在做一个 IoT 相关的项目,或者想学习 IoT 平台的架构设计,强烈建议把 yudao-module-iot 的代码 clone 下来,按照上面推荐的 5 个文件顺序阅读。相信我,读完之后你对 IoT 平台的理解会提升一个层次。
下一篇预告: IM 即时通讯模块——看看 RuoYi 是怎么在 Spring Boot 里实现一个完整的 IM 系统的,敬请期待!
觉得有用的话,点个赞支持一下呗~ 你们的点赞是我持续更新的动力!如果有任何疑问或者想讨论的话题,欢迎在评论区留言交流。
更多推荐


所有评论(0)