7.6 KiB
7.6 KiB
SimController 及相关接口详细实现文档 v4-2
本文档基于 SimController 及相关接口实现建议v4.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 (新建)
@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 (激活并重构)
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 (重构)
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 (激活)
@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 中:
injectDeviceSize: 解析设备尺寸。buildMaterialStaticFromDb: 补全物料静态属性。parseDeviceStaticsAndInfluences: 解析设备静态值和影响关系。parseMaterialStaticsAndInfluences: 解析物料静态值和影响关系。buildValueProviders: 解析事件 JSON (attr_changes)。
注意:在提取时,需要将原本直接操作 Map<String, Object> state 的逻辑,改为构建 SimUnit 或 SimInfluenceNode 对象。
4. 兼容性与迁移
- API 兼容:新接口
/sim/run的返回结构应尽量与原/projects/simulation/run中的frames结构保持一致,以便前端无缝切换。 - 分步上线:
- 先上线
/sim/run供测试使用。 - 验证无误后,将前端调用切到新接口。
- 废弃
ProjectController中的相关接口。
- 先上线