Files
qhmes/yy-admin-master/doc/桌面端后端数据交互通用模板(以车辆管理为例).md

8.8 KiB
Raw Blame History

桌面端后端数据交互通用模板(以车辆管理为例)

1. 目的与适用范围

本文将“车辆管理”已落地的同步能力抽象为可复用模板,适用于后续任意业务模块(如供应商、订单、库存、质检等)快速实现:

  • 桌面端 CRUD 与后端数据交互
  • 正向同步(桌面端 -> 后端)
  • 反向同步(后端 -> 桌面端)
  • 断线续传(离线可操作,重连自动补偿)
  • 本地缓存(保证离线可查、可改)

2. 总体架构模板

建议统一采用“信号触发 + REST 拉取 + Outbox 补偿”架构:

  1. 后端业务变更后,广播 STOMP 信号(只发变更事件,不强依赖完整数据包)。
  2. 桌面端接收信号后,不直接写本地业务表,而是触发“拉取接口”同步最新数据。
  3. 桌面端本地操作时,在线优先调用后端;失败或离线则先写本地缓存 + 记录待同步操作Outbox
  4. 网络恢复后自动回放 Outbox成功后清理队列并全量回拉一次做一致性对齐。

核心原则

  • 在线追求实时,离线保证可用,重连追求最终一致。
  • 任何“回传动作”必须幂等。
  • 同步链路必须有完整日志(请求、结果、回放、失败原因)。

3. 后端接口模板(推荐样式)

以车辆管理为例,接口分两类:业务 CRUD 接口 + 同步辅助接口。

3.1 业务 CRUD给桌面端直接调用

建议统一路径风格(示例):

  • GET /{module}/{entity}/anon/list?pageNo=1&pageSize=10000&tenantId=1002
  • GET /{module}/{entity}/anon/queryById?id=xxx&tenantId=1002
  • POST /{module}/{entity}/anon/add?tenantId=1002
  • POST /{module}/{entity}/anon/edit?tenantId=1002
  • DELETE /{module}/{entity}/anon/delete?id=xxx&tenantId=1002
  • POST /{module}/{entity}/anon/updateStatus?id=xxx&status=1&tenantId=1002

返回建议统一:

{
  "success": true,
  "code": 200,
  "message": "操作成功",
  "result": {}
}

分页 result 建议统一包含:

  • records
  • total
  • current
  • size

3.2 后端推送信号(反向同步触发)

后端每次成功增删改后,广播 STOMP

  • Topic/topic/sync/{entity-topic}
  • Payload 示例:
{
  "cmd": "MES_VEHICLE_CHANGED",
  "action": "add|edit|delete|status",
  "entityId": "xxx",
  "timestamp": 1710000000000
}

说明:

  • cmd 必须唯一且稳定,桌面端按它路由处理。
  • action 用于日志和增量策略判断。
  • entityId 可选但建议提供。

3.3 桌面端正向回传批量接口(可选增强)

若使用统一 Outbox 回传通道,建议后端提供:

  • POST /sys/sync/batch

请求体示例:

[
  {
    "messageId": "outbox-id-1",
    "aggregateType": "VEHICLE",
    "aggregateId": "vehicle-id",
    "eventType": "CREATE|UPDATE|DELETE|TOGGLE_STATUS",
    "payload": "{...}",
    "occurredAt": "2026-01-01T10:00:00Z"
  }
]

后端必须做 messageId 幂等去重。


4. 桌面端数据层模板

4.1 必备组件

每个模块建议固定四层:

  1. EntityService(例:VehicleService

    • CRUD 入口
    • 本地缓存 + 离线队列
    • 重连回放逻辑
  2. SyncCoordinator(例:VehicleSyncCoordinator

    • 监听 STOMP 信号
    • 识别 cmd 并发布本地事件或触发同步
  3. OutboxProcessor(全局复用)

    • 持久化消息
    • 在线实时发、离线补发
    • 失败重试 + 指数退避
  4. NetworkMonitor(全局复用)

    • 网络状态检测
    • 状态变化事件发布

4.2 本地缓存与待同步队列

推荐本地文件结构(示例):

  • %LocalAppData%/YY.Admin/sync-cache/{entity}-cache.json
  • %LocalAppData%/YY.Admin/sync-cache/{entity}-pending-ops.json

建议数据结构:

  • cache: 最新本地快照(可直接查询)
  • pendingOps: 离线期间操作日志,按时间顺序回放

pendingOps 字段建议:

  • id
  • opTypeAdd/Edit/Delete/UpdateStatus
  • entityId
  • payload
  • createdAt

5. 同步逻辑模板(标准流程)

5.1 查询流程Page/List

  1. 在线:先拉远端数据 -> 刷新本地缓存。
  2. 远端失败:回退本地缓存。
  3. pendingOps 叠加到查询结果(保证 UI 看到“离线后的最新本地状态”)。

5.2 新增/编辑/删除/状态修改

  1. 若在线,优先调用远端接口。
  2. 远端成功:更新本地缓存。
  3. 远端失败或离线:写入 pendingOps,并立即更新本地缓存(保证可用)。

注意:新增时若本地临时 IDlocal-xxx)不符合后端主键规则,回放前需清空 ID 让后端生成。

5.3 网络恢复(断线续传)

触发条件:NetworkMonitor 从离线 -> 在线。

流程:

  1. 串行回放 pendingOps
  2. 回放中任意失败立即停止,等待下次重试。
  3. 回放完成后再做一次全量拉取,覆盖本地缓存。
  4. 发布 UI 刷新事件(避免用户手动点查询)。

5.4 后端 -> 桌面反向同步

流程:

  1. STOMP 收到 cmd
  2. SyncCoordinator 解析命令。
  3. 触发本地“拉取并刷新缓存”。
  4. UI 订阅变更事件刷新列表。

6. 可复用方法模板

后续新模块可直接复用以下模式(名称替换即可):

  • FetchRemoteListAsync()
  • RemoteAddAsync() / RemoteEditAsync() / RemoteDeleteAsync() / RemoteUpdateStatusAsync()
  • ApplyFilters()
  • ApplyPendingOpsSnapshotUnsafe()
  • EnqueuePendingOperation()
  • ReplayPendingOperationsAsync()
  • ExecutePendingOperationAsync()
  • LoadPendingOpsFromDisk() / SavePendingOpsToDiskUnsafe()
  • LoadCacheFromDisk() / SaveCacheToDiskUnsafe()
  • CloneEntity()

建议抽一个通用基类(后续可做):

  • OfflineSyncEntityServiceBase<TEntity, TPendingOp>
    • 负责缓存、队列、回放、网络事件订阅
    • 业务子类只实现远端接口和过滤逻辑

7. 日志模板(强制建议)

每个模块建议统一日志前缀,便于检索。
车辆管理示例前缀可复用为模块名替换:

  • [车辆同步] 服务初始化
  • [车辆列表] 查询链路
  • [车辆新增] [车辆修改] [车辆删除] [车辆状态] 本地/远端操作
  • [车辆远端] 实际 HTTP 请求与结果
  • [车辆入队] 离线入队
  • [车辆回放] 重连回放
  • [车辆重连] 全量对齐
  • [车辆推送] STOMP 信号处理
  • [车辆网络] 网络状态变化

每条日志建议最少包含:

  • 操作类型
  • 业务主键
  • 在线/离线状态
  • 是否成功
  • 失败原因(异常 message
  • 队列长度(适用时)

8. 新模块落地清单(开发步骤)

按以下顺序复制模板最稳:

  1. 后端先准备 anon CRUD 接口(或授权接口)+ 统一返回结构。
  2. 后端在 CRUD 成功后广播 STOMP 变更信号。
  3. 桌面端新增 EntityService(先把在线 CRUD 跑通)。
  4. 增加本地缓存与 pendingOps 持久化。
  5. 加入网络状态监听与重连回放。
  6. 新增 SyncCoordinator 处理 STOMP -> 本地刷新。
  7. 全链路日志补齐。
  8. 按“联调测试矩阵”逐项验证。

9. 联调测试矩阵(建议)

每个模块至少跑完以下用例:

  1. 在线新增 -> 后端可见。
  2. 在线编辑 -> 后端可见。
  3. 在线删除 -> 后端可见。
  4. 在线状态切换 -> 后端可见。
  5. 离线新增/编辑/删除 -> 本地立即可见。
  6. 重连后自动回放 -> 后端最终一致。
  7. 后端直接改数据 -> 桌面端自动刷新。
  8. 异常网络抖动 -> 不崩溃,回放可恢复。

10. 车辆管理对应实现参考(当前项目)

桌面端:

  • YY.Admin.Services/Service/Vehicle/VehicleService.cs
  • YY.Admin.Services/Service/Vehicle/VehicleSyncCoordinator.cs
  • YY.Admin.Core/Core/Services/IVehicleService.cs

后端:

  • jeecg-module-xslmes/.../MesXslVehicleController.java(业务接口 + 变更推送)
  • jeecg-module-device-sync/.../SyncController.java(如启用统一回传通道)

基础设施:

  • YY.Admin/Infrastructure/Sync/OutboxProcessor.cs
  • YY.Admin/Infrastructure/Network/NetworkMonitor.cs
  • YY.Admin/Infrastructure/Hubs/StompWebSocketService.cs

11. 推荐统一规范(后续团队约定)

  1. 所有新模块都按“在线优先 + 离线入队 + 重连回放 + 全量对齐”实现。
  2. 所有模块都使用统一日志前缀和字段。
  3. 后端变更推送统一 cmd 命名:{SYSTEM}_{ENTITY}_CHANGED
  4. 回传消息统一带 messageId 幂等键。
  5. 同步失败不阻塞主流程,但必须可观测(日志 + 队列长度)。
  6. 任意新模块上线前必须跑完“联调测试矩阵”。

结论:
车辆管理已经提供了完整的可复制样板。后续新模块只需替换“实体、接口、过滤字段、命令字”,其余同步骨架可直接复用,从而快速实现稳定的桌面端/后端数据交互能力。