# 05 门禁集成适配器架构与厂商无关接口设计 (Adapter Architecture) > **设计核心**:**强边界解耦与高内聚设计**。 > 住宿业务层(Accommodation Service)对外部物联网厂商的协议细节、Token、URL、整数请求类型完全无感知。 > 针对门禁控制定义**厂商中立的抽象网关接口 (`DoorAccessGateway`)**,DMS 专用协议转换完全收敛在 `DmsAccessAdapter`。 --- ## 1. 系统分层集成架构图 (Mermaid) ```mermaid flowchart TD subgraph UI_Layer["前端与接入层 (Web / Controller)"] AC["TrainAccommodationController\n(住宿分配 / 换房 / 退宿)"] DC["TrainDoorAccessController\n(门禁状态查询 / 重试 / 受控应急)"] end subgraph Business_Layer["核心业务领域层 (Domain Service)"] AS["TrainAccommodationService\n(维护住宿事实真源 / 状态推进)"] AGS["DoorAccessOrchestrationService\n(授权编排: 提早下发 / 补偿 / 批量处理)"] end subgraph Gateway_Boundary["厂商无关抽象边界 (Vendor-Agnostic Gateway)"] DAG["<>\nDoorAccessGateway\n+grantAccess(GrantCommand): OperationResult\n+revokeAccess(RevokeCommand): OperationResult\n+queryOperation(QueryCommand): OperationStatusResult\n+queryLockHealth(HealthCommand): LockHealthResult\n+remoteUnlock(UnlockCommand): OperationResult"] end subgraph Integration_DMS["DMS 专用集成适配层 (ruoyi-train/integration/dms)"] ADAPTER["DmsDoorAccessGateway\n(协议转换 / 参数映射 / 状态归一化)"] subgraph DMS_Core["DMS 核心支撑组件"] TM["DmsTokenManager\n(单飞互斥登录 / 缓存 / 401自愈)"] PROP["DmsProperties\n(受控环境变量配置)"] POLLER["DmsOperationPoller\n(Spring/Quartz 10秒对账轮询器)"] end subgraph Clients["细分领域 HTTP 客户端 (Feign / RestTemplate)"] PLC["DmsPlaceClient\n(楼栋/楼层/房间查询)"] DLC["DmsDoorLockClient\n(门锁列表/电量信号)"] KC["DmsKeyClient\n(在线密码/在线卡片)"] OPC["DmsOperationClient\n(query-operation-status)"] end end subgraph Remote_DMS["外部物联网云平台 (DMS IoT Platform)"] CLOUD["DMS REST API\n(https://dms.dmsiot.com)"] end AC --> AS DC --> AGS AS --> AGS AGS --> DAG DAG <|.. ADAPTER : 实现 ADAPTER --> TM ADAPTER --> PROP ADAPTER --> PLC ADAPTER --> DLC ADAPTER --> KC ADAPTER --> OPC POLLER --> DAG PLC --> CLOUD DLC --> CLOUD KC --> CLOUD OPC --> CLOUD ``` --- ## 2. 厂商无关内部标准接口契约 (`Vendor-Agnostic Interface`) 为确保沈阳房建公寓段学员管理系统未来平滑支持其他设备供应商(如海康威视、大华或铁路专用门禁系统),设计中立门禁网关接口 `DoorAccessGateway`: ```java package com.ruoyi.train.integration.gateway; import com.ruoyi.train.integration.gateway.dto.*; /** * 厂商中立门禁系统服务网关接口 * 严禁在该接口及方法签名中暴露任何具体厂商(如 DMS)的特定字段、类名或数字枚举。 */ public interface DoorAccessGateway { /** * 下发门禁通行授权 (支持在线密码、在线卡片等凭据) * * @param command 统一授权下发指令 (包含目标房间、门锁标识、学员信息、时间窗口、凭据要求) * @return 异步操作受理结果 (包含本地操作ID、外部受理ID、初步状态) */ AccessOperationResult grantAccess(GrantAccessCommand command); /** * 撤销已生效或下发中的门禁授权 (退宿、退训、换房时调用) * * @param command 统一撤销指令 (包含外部钥匙ID、目标硬件标识等) * @return 异步操作受理结果 */ AccessOperationResult revokeAccess(RevokeAccessCommand command); /** * 统一查询异步操作执行状态 (对账轮询) * * @param command 操作状态查询指令 (包含 operationId, hardwareId, 原始业务类型) * @return 归一化后的设备执行结果 (SUCCESS, UNDONE, FAILED, TIMEOUT) */ OperationStatusResult queryOperationStatus(QueryOperationCommand command); /** * 查询指定房间/门锁的物理运行健康度 (电量、信号、在线状态) * * @param command 查询健康度指令 * @return 归一化设备健康度指标 */ DeviceHealthResult queryDeviceHealth(QueryHealthCommand command); /** * 紧急远程开锁 (受控应急功能,仅限特定权限管理员并记录审计追踪) * * @param command 远程开锁指令 (必须携带操作人、两票审核号、操作原因) * @return 异步操作受理结果 */ AccessOperationResult remoteUnlock(RemoteUnlockCommand command); } ``` --- ## 3. 推荐工程目录结构规范 (`Package Structure`) 后续 R.3B 实现时,建议在 `ruoyi-train` 模块中创建如下包结构,本阶段仅冻结设计,**禁止创建 Java 文件**: ``` ruoyi-train └── src/main/java/com/ruoyi/train ├── domain # 领域实体 (TrainAccommodation, TrainDormitoryInfo, etc.) ├── service # 核心业务服务 (ITrainAccommodationService, etc.) └── integration # 外部集成根包 ├── gateway # 【厂商无关抽象层】 │ ├── DoorAccessGateway.java │ ├── dto # 统一标准入参/出参 DTO │ │ ├── GrantAccessCommand.java │ │ ├── RevokeAccessCommand.java │ │ ├── AccessOperationResult.java │ │ └── OperationStatusResult.java │ └── enums # 标准业务枚举 (CredentialType, NormalizedOpStatus) └── dms # 【DMS 厂商专用集成适配层】 ├── config # 配置类 (DmsProperties, DmsConfiguration) ├── auth # 认证与 Token 管理 (DmsTokenManager, DmsTokenResponse) ├── client # 底层 HTTP 交互客户端 │ ├── DmsBaseClient.java │ ├── DmsPlaceClient.java │ ├── DmsDoorLockClient.java │ ├── DmsKeyClient.java │ └── DmsOperationClient.java ├── dto # DMS 原始报文映射 DTO (只在 integration.dms 内部可见) │ ├── request # DMS 专用请求实体 (如 DmsOnlinePasswordCreateRequest) │ └── response # DMS 专用响应实体 (如 DmsApiResponse, DmsKeyData) ├── adapter # 核心适配器实现 │ └── DmsDoorAccessGateway.java (实现 DoorAccessGateway 接口) ├── scheduler # 异步任务与定时对账 │ └── DmsOperationPoller.java (10秒延迟轮询与超时处理) └── util # 专用编码工具 (CardNumberCodec: 读卡器十进制与16进制小端转换) ``` --- ## 4. 适配器边界与职责隔离红线 (`Adapter Boundary Rules`) 1. **DTO 边界完全隔离**: - DMS 的返回体对象(如 `DmsApiResponse`)的生命周期**绝不允许超出 `com.ruoyi.train.integration.dms` 包范围**。 - `DmsDoorAccessGateway` 必须负责将其翻译为中立的 `AccessOperationResult`,禁止向上层抛出 DMS 内部原始 JSON。 2. **状态与数字编码归一化**: - DMS 使用数字 `requestType`(1=下发密码, 2=在线卡片, 3=删除密码, 5=远程开锁)。业务 Service **严禁传递数字 1 或 3**,必须传递强类型枚举 `CredentialOperationType.PASSWORD_GRANT`。适配器内部完成枚举到数字 `requestType` 的转换。 - DMS 返回的 `operationStatus` 字符串(`"undone"`, `"success"`, `"failed"`, `"timeout"`)由适配器转换为内部标准领域枚举 `NormalizedOperationStatus`。 3. **第三方异常吞吐隔离**: - 外部网络超时、401 故障、DMS 内部报错统一由适配器包装为 `IntegrationException` 及其子类,不得泄露第三方平台的底层堆栈至前端。 --- ## 5. Wave 1 Implementation Result (Wave 1 implemented) - **阶段状态**:Wave 1 implemented。 - **持久化层落地**: - 完成外部资源映射实体 `TrainExternalResourceMapping` 与操作流水实体 `TrainExternalOperation`。 - 完成持久化 Mapper 与 Service (`IExternalResourceMappingService`, `IExternalOperationService`)。 - 落地 `train_external_resource_mapping`(支持一房多锁、Active 唯一性)与 `train_external_operation`(支持 DoorAuthorization 1:N 流水追踪)。 - **零外部耦合红线**: - 本 Wave 严格保持 `DMS_HTTP_CLIENT_COUNT = 0`,`DMS_TOKEN_MANAGER_COUNT = 0`。 - 零 RestTemplate / WebClient / HttpClient 网络调用,零明文敏感凭据。 - **数据库 Migration**:`008_external_resource_operation.sql` 验证通过,生产库未执行。 --- ## 6. Wave 2 Implementation Result (Wave 2 implemented against Mock DMS only) - **阶段状态**:Wave 2 implemented against Mock DMS only。 - **适配层核心交付清单**: 1. `config/DmsProperties`:受控配置中心,`dms.enabled = false`(安全默认),支持参数化超时、提前刷新窗口、Token Cookie 头名称。 2. `auth/DmsTokenManager`:全应用唯一集中 Token 缓存,基于 ReentrantLock + DCL 的 Single-Flight 并发互斥锁,支持滑动延展 (`markSuccessfulUse`) 与 401 集中失效自愈。 3. `client/DmsHttpClient`:基础底层 HTTP 客户端,统一 Cookie 传输,脱敏日志(密码、Token、Secret 全程保护),写操作读取超时严禁盲目自动重试 (`AMBIGUOUS_MUTATION_AUTO_RETRY = NO`)。 4. `client/DmsLocationClient` 与 `gateway/ExternalLocationGateway`:位置资源查询与 Place 空间定位。 5. `client/DmsDoorLockClient` 与 `gateway/ExternalDoorLockGateway`:门锁适配器,严格支持 0 把锁(返回空列表,非 NPE)、1 把锁与多把锁(完整返回全部锁)。 6. `client/DmsPasswordClient` 与 `gateway/ExternalCredentialGateway`:在线限时密码创建与删除适配器,支持 4~8 位数字,密码明文内存短暂留存,零落库零输出。 7. `client/DmsOperationStatusClient` 与 `gateway/DmsOperationStatusMapper`:异步状态查询与集中映射器(success->SUCCESS, undone->PENDING, failed->FAILED, timeout->TIMEOUT, 未知状态->UNKNOWN 严禁判定为 SUCCESS)。 8. `poller/DmsOperationPoller`:异步对账轮询调度器,仅在 `dms.enabled=true` 启用,单进程并发防重,终态不可篡改保护,错误分类退避持久化。 9. `mock/MockDmsServer`:轻量内嵌测试服务器,精准模拟 DMS 服务端登录互斥、读超时、多锁/零锁与状态流转。 - **环境纪律与迁移标记**: - `DMS_DEFAULT_ENABLED = FALSE` - `LIVE_DMS_REQUEST_COUNT = 0` - `FRONTEND_MODIFIED = 0` - `008_RUNTIME_FIRST_RUN = NOT_EXECUTED`,`008_RUNTIME_SECOND_RUN = NOT_EXECUTED` - `RUNTIME_MIGRATION_GATE_BEFORE_PRODUCTION = REQUIRED`