JavaProjectRepo/business-css/SimController 及相关接口实现建议v4-2.md
2026-03-19 11:18:15 +08:00

152 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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+