JavaProjectRepo/business-css/SimController 及相关接口实现建议v4-2.md

152 lines
13 KiB
Markdown
Raw Normal View History

2026-03-19 11:18:15 +08:00
# SimController 及相关接口实现建议 v4-2结合当前工程现状
本文档基于 [情景模拟分析结果v3.md](file:///e:/projectJava/JavaProjectRepo/business-css/%E6%83%85%E6%99%AF%E6%A8%A1%E6%8B%9F%E5%88%86%E6%9E%90%E7%BB%93%E6%9E%9Cv3.md) 第 3 条,并结合当前可运行代码的真实调用链,给出可落地的实现建议。
---
## 0. 现状盘点(必须先对齐)
### 0.1 当前“线上可用”的仿真接口在哪里
目前仿真入口实际在 `ProjectController`,而不是 `SimController`
- 初始化:`POST /projects/simulation/init` → [ProjectController.java:L275-L300](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/controller/ProjectController.java#L275-L300) → [ProjectServiceImpl.initSimulation](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L614-L774)
- 运行:`POST /projects/simulation/run` → [ProjectController.java:L288-L300](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/controller/ProjectController.java#L288-L300) → [ProjectServiceImpl.runSimulation](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L1296-L1351)
### 0.2 SimController 为什么不可用
[SimController.java](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/controller/SimController.java#L1-L43) 目前是“原型草稿”,在本仓库中无法落地,原因是:
- 引用的 `ProjectRepository/EventRepository/InfluenceRepository/InferenceConverter` 仅在该文件出现,仓库中不存在真实实现。
- `SimBuilder.buildUnits/buildEvents/buildInfluenceNodes` 也不存在([SimBuilder.java](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/build/SimBuilder.java#L1-L44) 只有注释草稿)。
- `SimService` 当前逻辑是 KV 级简化引擎,并且事件优先级与现有 `initSimulation` 的行为不一致([SimService.java](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/SimService.java#L7-L51))。
### 0.3 当前系统的“真实数据格式”
`runSimulation` 解析的是一种“frames → devices”结构并按 `deviceType` 分组:
- 调用入口:[ProjectServiceImpl.runSimulation](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L1296-L1351)
- 解析工具:[DeviceDataParser.parseAndGroupDeviceData](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/utils/DeviceDataParser.java#L1-L88)
- 单步模型:[DeviceStepInfo.java](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/model/DeviceStepInfo.java)
因此,“让 SimController 可用”的关键,不是从 0 造一套新格式,而是:**复用现有 frames 格式(或在 SimController 内把 SimContext 转为该格式)**,以便直接复用 `DeviceDataParser` + `DeviceInferService` 的整条推理/落库链路。
---
## 1. 建议的目标形态SimController 成为“仿真编排入口”
建议把 SimController 从“原型”升级为生产入口,但要遵循当前工程已存在的服务边界:
### 1.1 目标职责划分(贴合当前代码)
- **SimController**:只处理 HTTP + 参数校验 + 返回值结构统一(保持与 ProjectController 相同的 `{code,msg,data}` 或复用统一响应体)。
- **SimulationFacade新增**:负责把“现有 services + topology JSON + event 表”组装成可计算输入;并在需要时调用推理、落库、更新情景状态。
- **SimulationEngine新增或重构现有 SimService**:只做“时序帧生成/影响计算/事件注入”,纯内存计算,不碰 DB。
- **Converter新增**:把 Engine 输出转成 `DeviceDataParser` 能吃的 frames JSON或直接输出 Map 结构)。
这样做的好处:既保留 `SimController` 分层方向,又不引入仓库里不存在的 Repository/Converter 类型。
---
## 2. 具体落地建议(按当前文件/类名对齐)
### 2.1 先做最小可用:让 /sim 接口复用现有 ProjectServiceImpl 的能力
为了快速验证链路,第一阶段建议不要立刻重写引擎,而是“搬运+封装”:
1) **新增 `SimulationFacade`(建议放在 `com.yfd.business.css.service.sim` 包)**
内部依赖现有 service`ProjectService/ScenarioService/EventService/DeviceInferService`(以及 `MaterialService` 若需要 DB 补全静态物料属性)。
它暴露两类能力:
- `init(projectId, scenarioId, params)`:复用 [ProjectServiceImpl.initSimulation](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L614-L774) 或将其中解析/计算段迁移出来。
- `run(projectId, scenarioId, params)`:复用 [ProjectServiceImpl.runSimulation](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L1296-L1351)。
2) **SimController 直接调用 facade并提供与 ProjectController 一致的返回结构**
这样能做到:新增 `/sim/*` 不影响现有 `/projects/simulation/*`,并且复用现有稳定链路。
这一阶段的目标是:**先让 SimController 可用、可回归测试、可逐步迁移**。
### 2.2 第二阶段:把 initSimulation 拆成“解析/计算/输出”三个可替换模块
当前 `initSimulation` 里混杂了:拓扑解析、设备顺序、静态注入、影响计算、事件解析、帧输出。建议拆成 3 个模块,便于未来替换而不改 API
#### A. Topology & Static 解析模块建议TopologyParser
直接复用现有实现(迁移或抽取):
- 设备顺序:`parseDeviceOrder(projectId)`[ProjectServiceImpl.java:L370-L397](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L370-L397)
- 设备-物料绑定:`buildDeviceMaterialMap`[ProjectServiceImpl.java:L1063-L1090](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L1063-L1090)
- 静态/影响解析:
- 设备:`parseDeviceStaticsAndInfluences`[ProjectServiceImpl.java:L806-L860](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L806-L860)
- 物料:`parseMaterialStaticsAndInfluences`[ProjectServiceImpl.java:L861-L928](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L861-L928)
- DB 物料静态补全:`buildMaterialStaticFromDb`[ProjectServiceImpl.java:L1116-L1141](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L1116-L1141)
- 设备 size 注入:`injectDeviceSize`[ProjectServiceImpl.java:L776-L804](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L776-L804)
建议输出一个结构化的 DTO例如
- `List<Device> orderedDevices`
- `Map<deviceId, deviceType>`
- `Map<deviceId, materialId>`
- `devStatic/devInfluence/matStatic/matInfluence/matStaticDb`
#### B. Event 解析模块建议EventScheduleBuilder
直接复用现有 `attr_changes` 解析逻辑:
- `buildValueProviders`[ProjectServiceImpl.java:L929-L996](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L929-L996)
- `collectTimePoints`[ProjectServiceImpl.java:L1037-L1061](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L1037-L1061)
- `readValue`[ProjectServiceImpl.java:L998-L1035](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L998-L1035)
补强建议(贴合现状的缺口):
-`timePoints` 为空时不要直接失败:允许用 params 提供 `start/end/interval` 生成时间网格(否则“无事件仿真”无法跑)。
- ramp 事件目前仅把起止时刻作为输出点;若前端想看平滑曲线,需要补齐采样点(例如每 1s
#### C. Frame 生成模块建议FrameGenerator
复用 `initSimulation` 的生成循环,但把“覆盖策略”参数化:
- 现在的覆盖策略是:**Static → Influence → overrideWithEvents最终覆盖**
代码:[overrideWithEvents](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L1106-L1114)
- 建议支持两类事件Input 与 Override可先用 params 开关模拟)
- Input计算前注入
- Override计算后强制覆盖
这样第三阶段才需要动到“事件类型”定义;第二阶段只要把钩子留好即可。
---
## 3. SimService/SimModel 如何与现有链路对接(不要重新造轮子)
### 3.1 现有 SimModel 的适配建议(只做必要改造)
当前 SimModel 过于抽象(纯 KV无法表达“设备/物料静态属性注入、deviceType、material 绑定”等现有业务关键点:
- `SimUnit` 只有 `unitId/deviceId/materialId/deviceType`[SimUnit.java](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/model/SimUnit.java)
- `SimContext` 只有 `Map<SimPropertyKey, Double>` 的 currentValues[SimContext.java](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/model/SimContext.java)
建议的最小增强(为了能生成当前 runSimulation 可消费的 frames
- `SimUnit` 增加 `Map<String, Double> staticProps`(至少承载 diameter/height 与物料关键属性)。
- `SimEvent` 增加 `boolean override` 或扩展 EventType区分 Input/Override
- `SimInfluenceSource.delay` 目前未在 `SimService` 使用;若要支持 delay必须用 `ctx.timeline` 回看历史值(当前 `SimContext` 已能保留 step 的快照)。
### 3.2 Converter把 SimContext 输出转换成现有 frames 格式
建议增加一个 Converter替代原型里的 `InferenceConverter`),输出结构与 `DeviceDataParser` 一致:
```json
{
\"data\": {
\"frames\": [
{
\"step\": 0,
\"time\": 0,
\"devices\": {
\"dev-001\": {\"deviceType\": \"CylindricalTank\", \"diameter\": 20, \"height\": 20, \"u_concentration\": 20}
}
}
]
}
}
```
理由:这样 `SimController` 可以直接调用 `DeviceDataParser.parseAndGroupDeviceData` + `DeviceInferService.processDeviceInference`,与现有落库路径完全一致。
---
## 4. SimController 的接口形态建议(与现有系统兼容)
建议同时支持“两段式”和“一段式”,避免推倒重来:
### 4.1 两段式(兼容现有前端/流程)
- `POST /sim/init`:返回 frames`/projects/simulation/init` 对齐)
- `POST /sim/run`:接收 frames调用推理并落库`/projects/simulation/run` 对齐)
### 4.2 一段式(面向后端批处理/自动化)
- `POST /sim/run-all`:内部调用 init 生成 frames再立即 run 推理落库,返回摘要(如 snapshots、结果条数、耗时
---
## 5. 迁移与风险控制(建议强制执行)
1) **先引入新接口,不删旧接口**:让 `/sim/*``/projects/simulation/*` 并行一段时间。\n\n2) **帧格式不变**:任何新实现必须输出 `DeviceDataParser` 可解析的结构,否则推理链路与前端都要一起改,风险最大。\n\n3) **行为一致性测试**:对比新旧 init 输出(同 projectId/scenarioId是否一致对比 run 后写入 `scenario_result` 条数与 key 字段是否一致。\n\n4) **清理 System.out.println**`ProjectServiceImpl` 的 init/run 里有大量 `System.out.println`(例如 [ProjectServiceImpl.java:L644-L661](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L644-L661) 与 [runSimulation debug](file:///e:/projectJava/JavaProjectRepo/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java#L1319-L1338)),建议迁移到统一日志体系后再移除,以免污染生产日志与性能。\n\n---\n\n## 6. 最小实现清单(按优先级排序)\n\n- 建议 1`SimController` 先“可用”——删除/替换不存在的 Repository/Converter 依赖,改用现有 Service。\n- 建议 2新增 `SimulationFacade`,把现有 `ProjectServiceImpl.initSimulation/runSimulation` 先封装起来。\n- 建议 3逐步抽取 `TopologyParser/EventScheduleBuilder/FrameGenerator`,把 `ProjectServiceImpl` 中的计算逻辑迁移出来。\n- 建议 4最后再考虑把增强后的 `SimService/SimModel` 正式替换成唯一引擎实现。\n+