yeg
2026-09-05 90882aca0b60a5b39e127d30438752a774b3a7ac
修复模拟器 Redis 工步方案恢复

在 Redis 存储边界逐字段重建通道工步方案,兼容 JSONObject 嵌套状态并补充重启恢复回归测试。
2个文件已修改
40 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/battery/business/runtime/RedisBtsSimulatorStateStore.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/battery/business/runtime/RedisStateStoreTest.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/battery/business/runtime/RedisBtsSimulatorStateStore.java
@@ -12,6 +12,8 @@
import com.alibaba.fastjson2.JSONObject;
import com.battery.device.simulator.BtsSimulatorStateStore;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsDeviceProfile;
import com.battery.device.simulator.BtsSimulatorStateStore.ChannelConfiguration;
import com.battery.device.simulator.BtsSimulatorStateStore.SimulatorPlanStep;
import com.battery.device.api.model.DeviceWorkStatus;
/** 将开发模拟器完整状态写入 Redis,主状态不设置普通 TTL。 */
@@ -185,8 +187,27 @@
        JSONObject object = jsonObject(value);
        String workStatus = object.getString("workStatus");
        if (workStatus == null) throw new IllegalStateException("Missing BTS simulator state field: workStatus");
        JSONObject configuration = object.getJSONObject("configuration");
        return new ChannelState(requiredInteger(object, "channelId"), object.getBooleanValue("online"),
                DeviceWorkStatus.valueOf(workStatus), object.getObject("configuration", ChannelConfiguration.class));
                DeviceWorkStatus.valueOf(workStatus), channelConfiguration(configuration));
    }
    /** Redis 通用反序列化会把泛型 steps 恢复为 JSONObject,不能让 record 构造器直接强转。 */
    private ChannelConfiguration channelConfiguration(JSONObject object)
    {
        if (object == null) return null;
        JSONArray configuredSteps = requiredArray(object, "steps");
        List<SimulatorPlanStep> steps = new ArrayList<>();
        configuredSteps.forEach(item -> {
            JSONObject step = jsonObject(item);
            steps.add(new SimulatorPlanStep(step.getString("name"), step.getString("stepType"),
                    step.getDoubleValue("durationSeconds"), step.getDoubleValue("voltageV")));
        });
        return new ChannelConfiguration(requiredDecimal(object, "currentA"), requiredDecimal(object, "voltageV"),
                requiredDecimal(object, "capacityAh"), requiredDecimal(object, "energyWh"),
                requiredInteger(object, "cycleNo"), requiredInteger(object, "stepNo"),
                requiredInteger(object, "plannedCycleCount"), object.getLongValue("totalTimeSeconds"),
                object.getLongValue("relativeTimeSeconds"), steps);
    }
    private ChannelTombstone channelTombstone(Object value)
ruoyi-admin/src/test/java/com/battery/business/runtime/RedisStateStoreTest.java
@@ -112,6 +112,23 @@
    }
    @Test
    void restoresChannelPlanWhenRedisReturnsNestedJsonObjects()
    {
        JSONObject state = JSON.parseObject(JSON.toJSONString(state(1, "127.0.0.2")));
        JSONObject configuration = state.getJSONArray("devices").getJSONObject(0)
                .getJSONArray("channels").getJSONObject(0).getJSONObject("configuration");
        configuration.getJSONArray("steps").forEach(item -> ((JSONObject) item).put("@type", JSONObject.class.getName()));
        FastJson2JsonRedisSerializer<Object> serializer = new FastJson2JsonRedisSerializer<>(Object.class);
        Object restoredValue = serializer.deserialize(serializer.serialize(state));
        SimulatorState restored = store(new AtomicReference<>(restoredValue))
                .loadOrInitialize(state(9, "127.0.0.9"));
        assertEquals("恒流充电", restored.devices().get(0).channels().get(0)
                .configuration().steps().get(0).name());
    }
    @Test
    void upgradesLegacyCollectorDiscoveryStateWithSamplingDefaults()
    {
        AtomicReference<Object> stored = new AtomicReference<>("{\"version\":1,\"devices\":[],"