Files
railwaysystem/docs/development/dms-r3/05_adapter_architecture.md
T

11 KiB
Raw Blame History

05 门禁集成适配器架构与厂商无关接口设计 (Adapter Architecture)

设计核心:强边界解耦与高内聚设计。 住宿业务层(Accommodation Service)对外部物联网厂商的协议细节、Token、URL、整数请求类型完全无感知。 针对门禁控制定义厂商中立的抽象网关接口 (DoorAccessGateway),DMS 专用协议转换完全收敛在 DmsAccessAdapter。


1. 系统分层集成架构图 (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["<<interface>>\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:

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<DmsKeyData>)的生命周期绝不允许超出 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