JavaProjectRepo/business-css/SimController及相关接口详细实现文档.md
2026-03-19 11:18:15 +08:00

7.6 KiB
Raw Permalink Blame History

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 中:

  1. injectDeviceSize: 解析设备尺寸。
  2. buildMaterialStaticFromDb: 补全物料静态属性。
  3. parseDeviceStaticsAndInfluences: 解析设备静态值和影响关系。
  4. parseMaterialStaticsAndInfluences: 解析物料静态值和影响关系。
  5. buildValueProviders: 解析事件 JSON (attr_changes)。

注意:在提取时,需要将原本直接操作 Map<String, Object> state 的逻辑,改为构建 SimUnitSimInfluenceNode 对象。


4. 兼容性与迁移

  • API 兼容:新接口 /sim/run 的返回结构应尽量与原 /projects/simulation/run 中的 frames 结构保持一致,以便前端无缝切换。
  • 分步上线
    1. 先上线 /sim/run 供测试使用。
    2. 验证无误后,将前端调用切到新接口。
    3. 废弃 ProjectController 中的相关接口。