生成时间: 2026-08-03 · 数据来源: xnybw平台需求及工作计划.xlsx(南网在线绿能云缺陷跟踪表)· 仅针对 backup730/730backup 分支代码

Row 15:OMS2.0侧"实际并网容量审核-新型储能"菜单点击进去之后报错

严重 已关闭 · 复测通过 新型储能 模块:项目信息填报 处理人:何佳星

1基本信息

问题描述OMS2.0侧,实际并网容量审核 - 新型储能,菜单点击进去之后报错。
所属模块项目信息填报 / -(实际并网容量审核)
严重程度严重(阻断流程:是)
涉及类型新型储能
提出人罗晶
处理人 / 状态何佳星 / 5.1.已关闭(复测通过)

2问题截图

实际并网容量审核-新型储能报错
图1:进入"实际并网容量审核 - 新型储能"列表页,顶部弹出两条"运行时异常,请联系管理员!"及一条"获取数据失败",列表为空

3旧代码定位(backup730 / 730backup 分支)

前端入口:src/views/projectNew/projectActualList.vue(路由 /project-actual-list/xxcn),页面进入时并行调用两个接口:概览统计 getAuditOverview(第257行)与分页列表 getDataList(第270-310行),二者最终都落到后端 SjbwController#getAuditOverview / 列表查询接口。

后端:SjbwAppService.java 第 350-386 行 getAuditOverview()

public Map getAuditOverview(SjbwDto dto) {
    List<SjbwAuditVo> list = this.getListAudit(dto);   // 351行:getListAudit 内部已经调用过一次 dealAuditList(list)
    dealAuditList(list);                                 // 352行:这里又对同一份 list 重复调用一次,属冗余二次处理
    ...
    for (SjbwAuditVo val : list) {
        BigDecimal changeRl = new BigDecimal(val.getChangeRl());   // 第371行:直接对字符串做 BigDecimal 转换,
                                                                      // 没有做 null / 空串 / 非数字格式的防护
        rlbh = rlbh.add(changeRl);
        ...
    }
}

getListAudit()(约第477-495行)内部:

public List<SjbwAuditVo> getListAudit(SjbwDto dto) {
    ...
    List<SjbwAuditVo> list = getCapBaseCommonDAO().queryList(
        "cn.csg.so.oms.in.newenergy.project.model.SjbwAuditVo_getPageAudit", dto);
    dealAuditList(list);          // 已经处理过一次,计算并回填 changeRl / bwrl
    ...
    return list;
}

dealAuditList() 内针对新型储能有专属分支 dealXxcnRl()(第546-608行),会再发起一轮 DB 查询(NePwrEnVO_queryByImplAndPlantIds / NePwrEnProcVO_queryByImplAndPlantIds)重新计算容量差值:

private void dealXxcnRl(List<SjbwAuditVo> list, Map<String, BigDecimal> rlMap, Map<String, String> batchMap) {
    ...
    for (NePwrEnVO val : energyList) {
        if (ObjectUtil.isEmpty(val.getGdyedgl()) || ObjectUtil.isEmpty(val.getTcsj()) || ObjectUtil.isNotEmpty(val.getBqtysj())) {
            continue;
        }
        BigDecimal rl = new BigDecimal(val.getGdyedgl());   // 对"归档容量"字段做强制转换,字段来源未做统一格式校验
        ...
    }
}
根因说明(受限于篇幅未逐条模拟运行时数据,以下为代码层面确认的两处风险点):
① 冗余的重复处理:getAuditOverview() 拿到 getListAudit() 的结果后又手动调用了一次 dealAuditList(list)(第352行),而 getListAudit() 内部(第490行附近)已经调用过。对"新型储能"分支,这意味着 dealXxcnRl() 会针对同一批 implId/plantId 再发起一轮数据库查询和内存计算,属于明显的代码坏味道,也放大了任何一次 DB 查询异常/超时对整体接口的影响面。
② BigDecimal 强转无防护:第371行 new BigDecimal(val.getChangeRl()) 及 dealXxcnRl 内的多处 new BigDecimal(val.getGdyedgl()) 均未对空值 / 非数字字符串做 try-catch 或格式校验,一旦新型储能场站存在"归档容量"字段为空、脏数据或格式异常(例如带单位、逗号分隔符等历史遗留数据),会直接抛出 NumberFormatException/NullPointerException,被全局异常处理器兜底为截图中的"运行时异常,请联系管理员!",与列表接口各自独立报错,因此页面同时出现两条"运行时异常"提示和一条"获取数据失败"。
说明:该问题在 xlsx 记录中状态已为"5.1.已关闭 / 复测通过",即在此后的迭代中已修复;本页面是对 backup730/730backup 快照代码的复盘定位,用于说明历史根因,不代表当前线上仍有此问题。

4修复方案

修复文件:src/main/java/cn/csg/so/oms/in/newenergy/project/appservice/SjbwAppService.java

① 去掉冗余的二次处理(第350-352行):
public Map getAuditOverview(SjbwDto dto) {
    List<SjbwAuditVo> list = this.getListAudit(dto);   // getListAudit 内部已完成 dealAuditList,这里不再重复调用
    // dealAuditList(list);   // 删除冗余调用
    ...
}
② 给 BigDecimal 转换加上防护(第371行 及 dealXxcnRl / dealFdgfRl 内所有同类转换):
private BigDecimal safeToBigDecimal(String raw) {
    if (StrUtil.isBlank(raw)) {
        return BigDecimal.ZERO;
    }
    try {
        return new BigDecimal(raw.trim());
    } catch (NumberFormatException e) {
        log.warn("容量字段格式异常,已按0处理,原始值={}", raw);
        return BigDecimal.ZERO;
    }
}
// 371行替换为:
BigDecimal changeRl = safeToBigDecimal(val.getChangeRl());
效果:去掉重复的 dealAuditList 调用可减少一倍不必要的数据库压力;BigDecimal 转换加上防护后,即便个别记录的容量字段存在脏数据,也只会被当作0处理并记录警告日志,不会导致整个"新型储能"审核列表页面无法打开。