Files
railwaysystem/RuoYi-Vue/docs/mqtt_removal_plan.md
T
buliping 1def568f24 refactor(iot): 移除 MQTT 传输层,仅保留设备开放接口与门禁写操作策略
- 依赖:删除根 pom 的 paho.version 与 org.eclipse.paho.client.mqttv3 依赖声明,
  同步移除 ruoyi-iot 模块中的 Paho 依赖,模块描述改为“iot设备数据与开放接口”
- MQTT 协议栈整体删除:IotMqttConfig、IotMqttProperties、MqttClientManager、
  MqttMessageDispatcher、MqttCallbackHandler、MqttConnectionCallback、
  IMqttMessageListener、MqttMessageDTO、MqttPublishRequest、MqttMessageEvent、
  IMqttService/MqttServiceImpl、IotMqttController,以及 lock 侧 topic 订阅与
  LockMessageListener、AccessRecordHandler、CommandRespHandler、
  GatewayOnlineHandler、LockSignalHandler
- MQTT 报文留痕链路删除:LockMqttLog 实体、LockMqttLogMapper(+XML)、
  ILockMqttLogService/LockMqttLogServiceImpl、LockMqttLogController,
  以及对应的前端页面 build_ui/src/views/iot/mqttlog 与 API build_ui/src/api/iot/mqttlog.js
- 命令下发改为仅落库:LockCommandServiceImpl 派发时直接置 TRANSPORT_DISABLED 失败,
  retryPending 返回 0;删除 GatewayOfflineCheckTask、LockCommandRetryTask、
  LockDeviceOfflineCheckTask 等依赖 MQTT 的补偿与离线检查定时任务
- 保留与传输无关的门禁写操作策略:新增 IotLockSecurityProperties(iot.lock-security),
  RealIotSecurityGate 及其测试改用该配置类
- 配置与调用处清理:application*.yml 中 iot.mqtt 段迁移为 iot.lock-security,
  删除 broker-url/client-id/username/password/topics/will/qos 等连接参数,
  修正 iot.face 环境标识注释引用;QA 工具启动参数改用 --iot.lock-security.*,
  并移除 browser_regression.js 的 mqttlog 路由
- 测试同步:删除依赖 MQTT 与传输层的 CommandRespHandlerMockTest、
  Round5sEgressIsolationTest、Round5sExecutionIntegrationTest、
  Round5v4BrowserFixture、Round5v4KingbaseIntegrationTest;
  更新 RealIotSecurityGateTest、FaceExtractClientMockTest、
  TrainIotLockAuthBridgeMockTest

说明:数据库侧 lock_mqtt_log 表结构与历史验收文档保留,未做数据迁移;
前端若仍配置了“MQTT报文日志”菜单,需在后台菜单管理中一并移除。
2026-11-10 16:06:23 +08:00

277 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 从项目移除 MQTT——文件级改造清单
> **适用范围**:RuoYi-Vue(`railwaysystem`)全部模块
> **方案定位**:方案 A(推荐)——只拆除"MQTT 传输 + 订阅回调 + 调度 + 留痕",保留数据层、协议构造层与 HTTP 能力
> **红线约束**:报到机**人脸采集**与**门锁入住** HTTP 链路必须完整保留
> **编制时间**:2026-11-10
---
## 目录
- [0. 关键前提](#0-关键前提)
- [1. 严禁删除、严禁修改的保留项](#1-严禁删除严禁修改的保留项)
- [1.1 报到机 HTTP 链路(红线)](#11-报到机-http-链路红线)
- [1.2 人脸能力(HTTP,非 MQTT)](#12-人脸能力http非-mqtt)
- [1.3 门锁主数据与 DB 层](#13-门锁主数据与-db-层)
- [1.4 状态机与协议构造层](#14-状态机与协议构造层)
- [1.5 HTTP 开放接口](#15-http-开放接口)
- [1.6 容易误删的隐形依赖](#16-容易误删的隐形依赖)
- [2. 需删除的文件(36 个)](#2-需删除的文件36-个)
- [3. 需修改的文件(7 个)](#3-需修改的文件7-个)
- [4. 改造后行为说明](#4-改造后行为说明)
- [5. 方案 B(彻底清理,仅供评估)](#5-方案-b彻底清理仅供评估)
- [6. 执行顺序建议](#6-执行顺序建议)
---
## 0. 关键前提
**不能直接删除 `ruoyi-iot` 模块。** 该模块除 MQTT 外还承载三类被强依赖的能力:
| 能力 | 被谁依赖 | 说明 |
|---|---|---|
| 报到机 HTTP(人脸采集 / 门锁入住) | `ruoyi-admin` | 控制器直接 `import com.ruoyi.iot.lock.*`(`LockDeviceMapper`、`ILockAuthService`、`LockAuth`) |
| 人脸特征提取(HTTP 调外部服务) | `ruoyi-train` | `TrainStudentServiceImpl` 使用 `FaceExtractClient`、`LockFace`、`LockAuthMapper` |
| 门锁主数据 + HTTP 开放接口 | `ruoyi-admin`、`ruoyi-train` | 设备/网关/分组/授权/开门记录 CRUD、`/openapi/**` |
**结论**:采用方案 A——仅移除 MQTT 传输侧,保留数据层、协议构造层、开放接口。授权/设备/网关三个业务服务**无需改动**。
---
## 1. 严禁删除、严禁修改的保留项
### 1.1 报到机 HTTP 链路(红线)
| 文件 | 说明 |
|---|---|
| `ruoyi-admin/.../controller/api/TrainRegisterApiController.java` | 人脸采集、门锁入住(`callStayCheckin`)、报到重置;**方案 A 下零改动** |
| `ruoyi-admin/.../controller/api/TrainFaceApiController.java` | 被报到机控制器复用(`deleteEmployee` 解绑人脸) |
| `ruoyi-train/.../integration/lock/client/TrainLockStayApiClient.java` | HTTP 门锁入住/退宿开放平台客户端 |
| `ruoyi-train/.../integration/lock/dto/LockStayCheckinResult.java` | 入住结果 DTO |
| `ruoyi-train/.../integration/lock/dto/LockAuthBridgeResult.java` | 授权桥接结果 DTO |
> `TrainRegisterApiController` 依赖的 `ILockAuthService`、`LockDeviceMapper` 在本方案中均保留,因此该文件**不需要任何改动**。
### 1.2 人脸能力(HTTP,非 MQTT)
```
ruoyi-iot/.../lock/remote/FaceExtractClient.java
ruoyi-iot/.../config/FaceExtractProperties.java
ruoyi-iot/.../lock/domain/LockFace.java
ruoyi-iot/.../lock/mapper/LockFaceMapper.java (+ resources/mapper/lock/LockFaceMapper.xml)
ruoyi-iot/.../lock/service/ILockFaceService.java
ruoyi-iot/.../lock/service/impl/LockFaceServiceImpl.java
ruoyi-iot/.../lock/controller/LockFaceController.java
ruoyi-train/.../service/impl/TrainStudentServiceImpl.java
ruoyi-train/.../mapper/TrainStudentMapper.java
```
### 1.3 门锁主数据与 DB 层
```
lock/domain/LockDevice.java LockGateway.java LockGroup.java LockAuth.java
LockAccessLog.java ExecutionRecord.java LockServiceConfig.java
lock/mapper/LockDeviceMapper.java LockGatewayMapper.java LockGroupMapper.java
LockAuthMapper.java LockAccessLogMapper.java LockServiceConfigMapper.java
resources/mapper/lock/Lock{Device,Gateway,Group,Auth,AccessLog,ServiceConfig}Mapper.xml
lock/service/ILock{Auth,Device,Gateway,Group,AccessLog,ServiceConfig}Service.java + impl
lock/controller/Lock{Auth,Device,Gateway,Group,AccessLog,ServiceConfig}Controller.java
```
> 三个业务实现类(`LockAuthServiceImpl`、`LockDeviceServiceImpl`、`LockGatewayServiceImpl`)只间接依赖命令服务,本方案中**不改**。
### 1.4 状态机与协议构造层
```
lock/security/RealIotSecurityGate.java (无任何 MQTT 引用,被 train 授权桥接直接用)
lock/security/ExecutionStates.java
lock/service/LockExecutionTransactions.java
lock/LockConstants.java
lock/protocol/YdlinkCodec.java YdlinkFrameDTO.java YdlinkOp.java
YdlinkTopicBuilder.java YdlinkTopicDTO.java YdlinkTopicType.java
LockAuthPayloadFactory.java
```
**原因**:上述协议类被 `LockAuthServiceImpl`、`LockDeviceServiceImpl`、`LockGatewayServiceImpl` 用于生成 `lock_command.payload/topic` 并落库(outbox)。删除会连带 4 个业务类和大量测试改动,违背最小改动原则。
### 1.5 HTTP 开放接口
```
ruoyi-iot/.../openapi/**(OpenAuthApiController、OpenFaceApiController、OpenQueryApiController、
OpenApiAuthFilter、OpenApiProperties、Open*Request)
```
### 1.6 容易误删的隐形依赖
| 文件 | 为什么不能删 |
|---|---|
| `ruoyi-iot/.../lock/task/LockScheduleConfig.java` | 全项目**唯一**的 `@EnableScheduling`;`ruoyi-train` 的 `DmsOperationPoller`(`@Scheduled`)依赖它,删除会静默停掉 DMS 轮询 |
---
## 2. 需删除的文件(36 个)
### 2.1 MQTT 连接与传输核心(13)
| 文件 | 删除理由 |
|---|---|
| `config/IotMqttConfig.java` | MQTT 客户端 Bean 装配与生命周期初始化 |
| `config/IotMqttProperties.java` | `iot.mqtt.*` 全部配置项 |
| `core/MqttClientManager.java` | 连接、重连、健康检查、订阅恢复、发布 |
| `core/MqttCallbackHandler.java` | Paho 回调入口 |
| `core/MqttConnectionCallback.java` | 连接状态回调接口 |
| `core/MqttMessageDispatcher.java` | 上行消息分发 |
| `core/IMqttMessageListener.java` | 业务监听器 SPI |
| `domain/MqttMessageDTO.java` | 消息载体 |
| `domain/MqttPublishRequest.java` | 发布请求 DTO |
| `event/MqttMessageEvent.java` | 消息事件(无其他监听者) |
| `service/IMqttService.java` | 发布/订阅抽象 |
| `service/impl/MqttServiceImpl.java` | 唯一实现 |
| `controller/IotMqttController.java` | `/iot/mqtt/status|publish|subscribe` 运维接口 |
### 2.2 订阅与上行回调处理(6)
| 文件 | 删除理由 |
|---|---|
| `lock/mqtt/LockTopicSubscriber.java` | 启动订阅 5 个 `ydlink` 主题(`ApplicationRunner`) |
| `lock/mqtt/LockMessageListener.java` | 消息路由 + 报文留痕 |
| `lock/mqtt/handler/GatewayOnlineHandler.java` | 上下线回调 |
| `lock/mqtt/handler/CommandRespHandler.java` | 三类回执处理 |
| `lock/mqtt/handler/AccessRecordHandler.java` | 开门记录回调 |
| `lock/mqtt/handler/LockSignalHandler.java` | 信号/电量回调 |
### 2.3 MQTT 相关调度任务(3)
| 文件 | 删除理由 |
|---|---|
| `lock/task/LockCommandRetryTask.java` | 依赖 `retryPending → dispatch → publish`,无传输后无意义 |
| `lock/task/GatewayOfflineCheckTask.java` | 依据 MQTT 心跳判定离线,移除后会误判全员离线 |
| `lock/task/LockDeviceOfflineCheckTask.java` | 同上 |
### 2.4 报文留痕(6)
```
lock/domain/LockMqttLog.java
lock/mapper/LockMqttLogMapper.java
resources/mapper/lock/LockMqttLogMapper.xml
lock/service/ILockMqttLogService.java
lock/service/impl/LockMqttLogServiceImpl.java
lock/controller/LockMqttLogController.java
```
> DB 表 `lock_mqtt_log` 在仓库内无 DDL,可保留空表或手工 `DROP`(不在本次代码范围)。
### 2.5 QA 模拟(1)
```
ruoyi-admin/.../controller/tool/QaMockMqttApiController.java
```
### 2.6 测试(3)
```
ruoyi-iot/src/test/.../lock/mqtt/handler/CommandRespHandlerMockTest.java
ruoyi-iot/src/test/.../lock/security/Round5sExecutionIntegrationTest.java (依赖 MqttClientManager/IMqttService)
ruoyi-iot/src/test/.../lock/security/Round5sEgressIsolationTest.java (以传输层断言为主)
```
---
## 3. 需修改的文件(7 个)
### 3.1 `ruoyi-iot/.../lock/service/impl/LockCommandServiceImpl.java`(唯一业务改动)
| 点位 | 改动 | 目的 |
|---|---|---|
| 第 18 行 | 删除 `import ...IMqttService` | 解除传输依赖 |
| 第 37 行 | 删除 `@Lazy @Autowired IMqttService mqttService` | 同上 |
| 留痕块(约 90-115 行) | 删除 `mqttLogMapper` 字段与 `writeMqttLog` 逻辑 | 留痕层已删除 |
| `dispatch()` 169-174 行 | 去掉 `isConnected()` 判断,改为**直接**置 `STATUS_FAIL` + `errorMsg="TRANSPORT_DISABLED"` 并返回 `null` | 保留断连语义,避免上游状态悬挂 |
| `dispatch()` 180-203 行 | 删除 `publishCommand()` 与 `AWAITING_ACK` 迁移分支,改为 `return false` | 移除发布逻辑 |
| `retryPending()` 206-210 行 | 改为 `return 0`(或随 RetryTask 一并删除) | 无补偿下发 |
> **替代方案**:若完全不想碰业务文件,可保留 `IMqttService`/`MqttServiceImpl` 作为空实现,但 MQTT 依赖仍在,不满足"移除"目标。二者取其一。
### 3.2 `ruoyi-iot/pom.xml`
- 删除 `org.eclipse.paho:org.eclipse.paho.client.mqttv3` 依赖(第 22-26 行)
- `<description>` 由"iot设备接入(MQTT)"改为"iot设备数据与开放接口"
### 3.3 根 `pom.xml`
- 删除 `paho.version` 属性
- 删除 `dependencyManagement` 中 Paho 条目(第 148-153 行)
### 3.4 `ruoyi-admin/src/main/resources/application.yml`
- **整段删除** `iot.mqtt`(第 195-259 行:enabled / mock / broker-url / username / topics / will 等)
- **保留** `iot:` 下其他节点:`hmac`、`openapi`、`face`、`lock_endpoint`、`api_key`、`avatar_profile`、`face_api_key`
### 3.5 三个环境变体配置
```
application_localhost.yml
application_localhost_24.yml
application_localhost_230.yml
```
同样只删 `mqtt:` 子树,保留其余 `iot.*`。
### 3.6 `ruoyi-iot/src/test/.../lock/security/RealIotSecurityGateTest.java`
- 删除使用 `new MqttClientManager(p, null).publish(...)` 的断言(约第 38 行)
- 保留其余门禁策略断言(该类本身保留)
### 3.7 文档(可选)
`docs/mqtt_usage_and_status.md` 标注"已移除",或移入归档目录。
---
## 4. 改造后行为说明
| 场景 | 改造后行为 |
|---|---|
| 应用启动 | 不再创建 MQTT 连接、不再订阅主题、无 `iot-mqtt-health` 线程、无连接失败日志 |
| 业务触发授权/开关锁 | 仍生成 `lock_command` 记录,但状态直接落 `FAIL / TRANSPORT_DISABLED`,不产生任何网络请求 |
| 报到机人脸采集 | 完全不变(HTTP + 本地文件 + 人脸服务 HTTP) |
| 报到机门锁入住 | 完全不变(`TrainLockStayApiClient` HTTP) |
| 管理端门锁/网关/分组/人脸页面 | 查询与维护功能保留;"下发/远程控制"类操作返回失败提示 |
| DMS 轮询任务 | 正常(`LockScheduleConfig` 保留) |
---
## 5. 方案 B(彻底清理,仅供评估)
若要求连同 `lock_command` outbox 一并移除,需追加修改:
- `LockAuthServiceImpl`、`LockDeviceServiceImpl`、`LockGatewayServiceImpl`:删除命令构造与 `commandService.send(...)`
- `LockCommandServiceImpl`、`ILockCommandService`、`LockCommand`、`LockCommandMapper(+XML)`、`LockCommandController`:整体删除
- `RealIotSecurityGate`:删除 `requireDispatchAllowed` / payload 校验分支
- `ruoyi-train/.../TrainIotLockAuthBridgeServiceImpl`:改为仅维护授权记录,不再生成命令
- 相关测试:`Round5v4KingbaseIntegrationTest`、`Round5v4BrowserFixture`、`TrainIotLockAuthBridgeMockTest` 需重写
- `protocol/**` 可随之删除
**风险**:触及 10+ 业务文件与 5+ 测试,且与保留链路相交(`LockAuthMapper` 仍在授权桥接中使用),回归成本高。
---
## 6. 执行顺序建议
1. 先改 `LockCommandServiceImpl`(去 `IMqttService`、去留痕)——此时传输层仍存在但不被引用
2. 再删 2.2 订阅/回调、2.3 调度、2.4 留痕、2.1 传输核心、2.5 QA
3. 删依赖(3.2、3.3)与配置(3.4、3.5)
4. 清理测试(2.6、3.6)
5. 验证:
```bash
mvn -o -pl ruoyi-iot,ruoyi-train,ruoyi-admin -am test-compile
```
启动冒烟后回归三条 HTTP 链路:**人脸上传 → 门锁入住 → 报到重置**
> **再次提醒**:`LockScheduleConfig`、`protocol/**`、`RealIotSecurityGate`、`openapi/**`、`FaceExtractClient`、`Lock*Mapper` 六类文件**不在删除范围**;删除会直接破坏保留功能或导致其它模块编译失败。
---
*文档结束。*