JavaProjectRepo/business-css/SimController及相关接口详细实现文档.md

195 lines
7.6 KiB
Markdown
Raw Normal View History

2026-03-19 11:18:15 +08:00
# SimController 及相关接口详细实现文档 v4-2
本文档基于 [SimController 及相关接口实现建议v4.md](file:///e:/projectJava/JavaProjectRepo/business-css/SimController%20%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%8E%A5%E5%8F%A3%E5%AE%9E%E7%8E%B0%E5%BB%BA%E8%AE%AEv4.md) 进一步细化提供了更贴合当前代码库ProjectServiceImpl的详细实现方案。
## 1. 核心目标
* **激活 `SimController`**:使其成为仿真服务的唯一入口,替代分散在 `ProjectController` 中的逻辑。
* **标准化计算管线**:实现 `Static -> Event(Input) -> Influence -> Event(Override)` 的标准计算流程。
* **复用现有逻辑**:最大程度复用 `ProjectServiceImpl` 中已有的 JSON 解析和数据组装代码,避免重复造轮子。
---
## 2. 模块详细设计与实现
### 2.1 数据获取层 (SimDataFacade)
负责从 DB 获取原始数据,并进行初步的组装。
**File:** `src/main/java/com/yfd/business/css/facade/SimDataFacade.java` (新建)
```java
@Component
public class SimDataFacade {
@Autowired private ProjectService projectService;
@Autowired private EventService eventService;
@Autowired private MaterialService materialService; // 用于补全物料静态属性
public SimDataPackage loadSimulationData(String projectId, String scenarioId) {
// 1. 获取项目与拓扑
Project project = projectService.getById(projectId);
if (project == null) throw new IllegalArgumentException("Project not found: " + projectId);
// 2. 获取事件
List<Event> events = eventService.list(new QueryWrapper<Event>().eq("scenario_id", scenarioId));
// 3. 预加载物料库 (用于后续补全静态属性)
// 逻辑复用 ProjectServiceImpl.buildMaterialStaticFromDb
// 这里先返回原始数据,由 Builder 处理具体的补全逻辑
return new SimDataPackage(project, events);
}
}
```
### 2.2 模型构建层 (SimBuilder)
负责将 `Project` (JSON) 和 `Event` (JSON) 转换为 `SimUnit`, `SimEvent`, `SimInfluenceNode`
**关键策略**:直接复用 `ProjectServiceImpl` 中的解析方法(`parseDeviceStaticsAndInfluences`, `buildValueProviders` 等),将其重构为静态工具方法或独立组件。
**File:** `src/main/java/com/yfd/business/css/build/SimBuilder.java` (激活并重构)
```java
public class SimBuilder {
private final ObjectMapper objectMapper = new ObjectMapper();
// 1. 构建单元 (SimUnit) - 包含静态属性
public List<SimUnit> buildUnits(Project project, MaterialService materialService) {
List<SimUnit> units = new ArrayList<>();
JsonNode root = objectMapper.readTree(project.getTopology());
// 解析设备静态属性 (复用 ProjectServiceImpl.parseDeviceStaticsAndInfluences 的部分逻辑)
// 解析物料静态属性 (复用 ProjectServiceImpl.buildMaterialStaticFromDb)
// 伪代码示例
for (JsonNode deviceNode : root.path("devices")) {
String deviceId = deviceNode.path("deviceId").asText();
Map<String, Double> staticProps = new HashMap<>();
// 1.1 解析 topology 中的 static 节点
// 1.2 解析 Device.size 并注入
// 1.3 如果有绑定的 material查询 DB 并注入物料属性
units.add(new SimUnit(deviceId, ..., staticProps));
}
return units;
}
// 2. 构建事件 (SimEvent)
public List<SimEvent> buildEvents(List<Event> events) {
// 复用 ProjectServiceImpl.buildValueProviders 解析 attr_changes
// 将解析出的 Schedule 转换为 List<SimEvent>
// 注意区分 isOverride (强制覆盖)
}
// 3. 构建影响关系 (SimInfluenceNode)
public List<SimInfluenceNode> buildInfluenceNodes(Project project) {
// 复用 ProjectServiceImpl.parseDeviceStaticsAndInfluences 中的 influence 解析逻辑
}
}
```
### 2.3 核心计算引擎 (SimService)
实现标准计算管线。
**File:** `src/main/java/com/yfd/business/css/service/SimService.java` (重构)
```java
public class SimService {
public SimContext runSimulation(List<SimUnit> units,
List<SimEvent> events,
List<SimInfluenceNode> nodes,
int steps) {
SimContext ctx = new SimContext();
// Step 1: 初始化静态基线 (t=0)
for (SimUnit unit : units) {
unit.getStaticProperties().forEach((k, v) ->
ctx.setValue(SimPropertyKey.of(unit.unitId(), k), v)
);
}
// Step 2: 循环推进 (t=1 to steps)
for (int step = 1; step <= steps; step++) {
// 2.1 Event (Input): 应用普通事件
applyEvents(ctx, events, step, false);
// 2.2 Influence: 计算影响关系
// 基于当前 ctx (包含 static + input event) 计算
applyInfluences(ctx, nodes);
// 2.3 Event (Override): 应用强制覆盖事件
// 再次覆盖,确保强制逻辑生效
applyEvents(ctx, events, step, true);
// 2.4 Snapshot
ctx.snapshot(step);
}
return ctx;
}
// 辅助方法applyEvents, applyInfluences
}
```
### 2.4 统一控制器 (SimController)
**File:** `src/main/java/com/yfd/business/css/controller/SimController.java` (激活)
```java
@RestController
@RequestMapping("/sim")
public class SimController {
@Autowired private SimDataFacade simDataFacade;
@Autowired private SimBuilder simBuilder; // 如果是 Bean
@Autowired private SimService simService;
// 标准运行接口
@PostMapping("/run")
public Result<Map<String, Object>> run(@RequestBody SimulationRequest req) {
// 1. Load Data
SimDataPackage data = simDataFacade.loadSimulationData(req.getProjectId(), req.getScenarioId());
// 2. Build Model
List<SimUnit> units = simBuilder.buildUnits(data.getProject(), ...);
List<SimEvent> events = simBuilder.buildEvents(data.getEvents());
List<SimInfluenceNode> nodes = simBuilder.buildInfluenceNodes(data.getProject());
// 3. Run Engine
SimContext ctx = simService.runSimulation(units, events, nodes, req.getSteps());
// 4. Convert Result (复用 DeviceDataParser 或 InferenceConverter)
// 保持与前端/推理接口的数据格式兼容
return Result.success(SimResultConverter.toFrames(ctx));
}
}
```
---
## 3. 具体复用点清单 (ProjectServiceImpl -> SimBuilder)
为了加快开发,以下方法建议直接从 `ProjectServiceImpl` 提取到 `SimBuilder` 或工具类 `SimParserUtils` 中:
1. **`injectDeviceSize`**: 解析设备尺寸。
2. **`buildMaterialStaticFromDb`**: 补全物料静态属性。
3. **`parseDeviceStaticsAndInfluences`**: 解析设备静态值和影响关系。
4. **`parseMaterialStaticsAndInfluences`**: 解析物料静态值和影响关系。
5. **`buildValueProviders`**: 解析事件 JSON (attr_changes)。
**注意**:在提取时,需要将原本直接操作 `Map<String, Object> state` 的逻辑,改为构建 `SimUnit``SimInfluenceNode` 对象。
---
## 4. 兼容性与迁移
* **API 兼容**:新接口 `/sim/run` 的返回结构应尽量与原 `/projects/simulation/run` 中的 `frames` 结构保持一致,以便前端无缝切换。
* **分步上线**
1. 先上线 `/sim/run` 供测试使用。
2. 验证无误后,将前端调用切到新接口。
3. 废弃 `ProjectController` 中的相关接口。