195 lines
7.6 KiB
Markdown
195 lines
7.6 KiB
Markdown
# 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` 中的相关接口。
|