113 lines
4.8 KiB
Markdown
113 lines
4.8 KiB
Markdown
# RailwaySystem 外部系统适配器契约设计 (Integration Contract)
|
||||
|
|
|
|||
|
|
> **集成原则:** 真实设备与第三方系统一期全部采用 **Mock First** 原则。业务 Service 严禁直接硬编码外部 HTTP 接口,统一通过 **防腐适配器接口 (Adapter SPI)** 进行解耦与隔离。
|
|||
|
|
> **外部调用解耦原则:** 数据库事务提交成功后,通过 `afterCommit` 触发后续 Adapter 调用(一期默认建议:`afterCommit` → 轻量异步执行器 → Adapter;若未引入异步执行器则为当前线程事务外调用 Adapter;两者皆保证外部调用失败不回滚已提交的本地数据库事务,而是独立更新同步状态并支持手工重试)。**MQ / Outbox / 分布式事务 = 一期不引入【扩展】。**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 适配器体系与 SPI 接口清单
|
|||
|
|
|
|||
|
|
系统抽象出三大核心集成适配器接口:
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
classDiagram
|
|||
|
|
class FaceAttendanceAdapter {
|
|||
|
|
<<interface>>
|
|||
|
|
+pushLessonSchedule(PushScheduleCmd cmd) PushResult
|
|||
|
|
+syncFaceFeature(SyncFaceCmd cmd) SyncResult
|
|||
|
|
+mockCheckinCallback(MockCallbackCmd cmd) CallbackResult
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class DoorAccessAdapter {
|
|||
|
|
<<interface>>
|
|||
|
|
+grantAccess(GrantAccessCmd cmd) AccessResult
|
|||
|
|
+revokeAccess(RevokeAccessCmd cmd) AccessResult
|
|||
|
|
+queryDeviceStatus(String lockSn) DeviceStatusResult
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class ExternalLearningAdapter {
|
|||
|
|
<<interface>>
|
|||
|
|
+validateEventId(String sourceSystem, String eventId) boolean
|
|||
|
|
+parseStudyPayload(Object rawPayload) StandardStudyEvent
|
|||
|
|
+mockPushStudyDuration(MockStudyCmd cmd) PushResult
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class MockFaceAttendanceAdapterImpl {
|
|||
|
|
+pushLessonSchedule()
|
|||
|
|
+syncFaceFeature()
|
|||
|
|
}
|
|||
|
|
class MockDoorAccessAdapterImpl {
|
|||
|
|
+grantAccess()
|
|||
|
|
+revokeAccess()
|
|||
|
|
}
|
|||
|
|
class MockExternalLearningAdapterImpl {
|
|||
|
|
+validateEventId()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FaceAttendanceAdapter <|.. MockFaceAttendanceAdapterImpl
|
|||
|
|
DoorAccessAdapter <|.. MockDoorAccessAdapterImpl
|
|||
|
|
ExternalLearningAdapter <|.. MockExternalLearningAdapterImpl
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 电子班牌与人脸考勤适配器:`FaceAttendanceAdapter`
|
|||
|
|
|
|||
|
|
### 2.1 业务场景
|
|||
|
|
1. **课表向班牌推送:** 当教室排定课次后,系统将排课时段、授课教师及学员人脸凭证推送给对应教室的电子班牌;
|
|||
|
|
2. **班牌签到打卡回传:** 学员在班牌刷脸后,班牌通过 HTTP 回调 RailwaySystem `/train/attendance/sign-in`。
|
|||
|
|
|
|||
|
|
### 2.2 接口规范与 Mock 行为
|
|||
|
|
- **下发排课与人脸:** `PushResult pushLessonSchedule(PushScheduleCmd cmd)`
|
|||
|
|
- **一期 Mock 实现【确认】:**
|
|||
|
|
一期 Mock 实现直接打印日志并返回 `success: true`,模拟班牌下发成功;支持单元测试中模拟设备超时或离线。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 智能门禁与门锁适配器:`DoorAccessAdapter`
|
|||
|
|
|
|||
|
|
### 3.1 业务场景
|
|||
|
|
学员完成宿舍分配后,系统下发人脸开锁授权;调房或退宿时,注销门锁权限。
|
|||
|
|
|
|||
|
|
### 3.2 接口规范
|
|||
|
|
- **授权下发:** `AccessResult grantAccess(GrantAccessCmd cmd)`
|
|||
|
|
- **权限撤销:** `AccessResult revokeAccess(RevokeAccessCmd cmd)`
|
|||
|
|
- **轻量解耦与容灾重试设计【默认/建议方案】:**
|
|||
|
|
1. 数据库事务提交成功后,通过 `afterCommit` 触发后续 Adapter 调用;
|
|||
|
|
2. 一期默认建议:`afterCommit` → 轻量异步执行器 → Adapter;如果未引入异步执行器:`afterCommit` → 当前线程事务外调用 Adapter;
|
|||
|
|
3. 两者都必须保证:外部调用失败不得回滚已经提交的本地数据库事务,而是保留/更新同步状态(`face_sync_status = 2`)并支持手工重试;
|
|||
|
|
4. 明确:MQ / Outbox / 分布式事务 = 一期不引入【扩展】;
|
|||
|
|
5. 单次 HTTP 请求超时阈值设为 5 秒,若调用失败或超时,在独立短事务中更新 `train_dorm_auth.face_sync_status = 2` (失败),记录 `last_error`,管理员可在页面一键手工重试。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. VR / 3D / 电子阅览室学习记录接入:`ExternalLearningAdapter`
|
|||
|
|
|
|||
|
|
### 4.1 业务场景与幂等保证
|
|||
|
|
外部专业实训系统在学员自主学习结束后,异步向 RailwaySystem 推送打卡流水。
|
|||
|
|
|
|||
|
|
### 4.2 接口响应三态设计 (HTTP 200)
|
|||
|
|
- **正常首次接收 (`status = "accepted"`):**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "学习记录接入成功",
|
|||
|
|
"data": { "status": "accepted", "durId": 5001, "message": "已记录学习时长 4500 秒" }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
- **重复事件推送 (`status = "duplicate"`):**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "事件已存在,忽略重复推送",
|
|||
|
|
"data": { "status": "duplicate", "durId": 5001, "message": "系统已存在该事件记录,无需重复入库" }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
- **参数或拓扑非法 (`status = "invalid"`):**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 400,
|
|||
|
|
"msg": "学习记录参数校验失败",
|
|||
|
|
"data": { "status": "invalid", "durId": null, "message": "校验失败:startTime 不能晚于 endTime" }
|
|||
|
|
}
|
|||
|
|
```
|