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

① 基本信息

问题描述点击保存时报错,但是项目实际已经创建,内网侧水新账号看不到相关信息
一级模块项目信息填报
二级模块项目基本信息
涉及类型中压分布式新能源
台账标注区域五区
严重性严重
是否阻断流程
当前状态2.1.待开发
研发处理人冷柏烨
处理状态已调整待验证

② 问题截图

保存报运行时异常
点击"保存"后页面顶部弹出红色错误提示"运行时异常,请联系管理员!",但下方表单里数据(含创建时间"2026-08-02 00:25:00")已经正常显示
项目列表中实际已存在该项目
项目列表页可以查到刚才报错的"测试项目-09901-04-BH"(中压分布式光伏,待建状态),证明保存/创建实际已经成功写入数据库

③ 旧代码涉及的项目文件及行数(backup730/730backup 分支)

xnybw5b / src/main/java/cn/csg/so/oms/in/newenergy/logrecording/OperationLogAspect.java 第 34-71 行(controllerAround 环绕通知,finally 块内调用 insertLogByEntity)
xnybw5b / src/main/java/cn/csg/so/oms/in/newenergy/project/controller/NewNePjController.java 第 89-96 行(addOrUpdatePro 接口,标注 @OperationLog 注解)

④ 代码现状与修复方案

"新增/保存项目"接口(addOrUpdatePro)标注了 @OperationLog 操作日志注解,实际业务逻辑之外,还会被 OperationLogAspect 这个全局 AOP 切面环绕:

@PostMapping("/addOrUpdatePro")
@ApiOperation(value = "新增或更新项目", notes = "新增或更新项目信息")
@OperationLog(module = OperationModule.XNYBW_XMGL, type = OperationType.INSERT)   // 第92行:会被OperationLogAspect环绕拦截
public Object addOrUpdatePro(@RequestBody ProjectVo vo){
    ...
    return projectImplFacade.addProject(vo);   // 真正的建项目逻辑,此处执行完即已提交入库
}

OperationLogAspect.controllerAround() 的关键问题在于:记录操作日志的 insertLogByEntity(...) 调用放在了 finally 块里,且没有自己的 try/catch 兜底

try {
    result = joinPoint.proceed();   // 第55行:真正执行addOrUpdatePro,项目已创建并提交事务
    operationResult = "成功";
    return result;
} catch (Throwable e) {
    ...
    throw e;
} finally {
    watch.stop();
    Integer timeCost = Math.toIntExact(watch.getTotalTimeMillis());
    operationLogAppService.insertLogByEntity(args, result, date, request, timeCost, operationResult, errorMsg, operationLog);   // 第69行:finally里再抛异常会覆盖掉已经return的正常结果!
}
这是一个经典的 Java finally 覆盖异常陷阱:joinPoint.proceed()(也就是真正的建项目逻辑)此时已经执行完毕并成功提交数据库事务,方法本应正常 return result;但 finally 块里紧接着调用的 insertLogByEntity(...)——用于把本次请求的入参、返回值、耗时等序列化后写入操作日志表——如果这一步本身抛出异常(例如把 ProjectVo 这种带多层嵌套集合的大对象做 JSON 序列化时失败、或日志表写入超时/唯一键冲突等),这个异常会从 finally 块里向外抛出,直接盖过前面 try 块里已经成功执行的 return,导致整个 HTTP 请求最终以 500 错误返回给前端,页面就弹出了"运行时异常,请联系管理员!"——但此时项目其实早已经创建成功并落库,这与截图1(报错)和截图2(项目确实存在于列表中)完全吻合。

结合台账"内网侧水新账号看不到相关信息"的补充描述:由于该请求最终以异常告终,凡是依赖"接口正常返回成功"这个信号才触发的后续动作(例如给内网水新审核账号生成待办/通知记录,如果这类逻辑是在 addProject(vo)返回之后、或在同一个被 AOP 包裹的调用链后半段才执行),也会因为最终抛出的异常而被跳过或前端误判为"未完成",从而出现内网侧收不到通知的连带现象。

建议修复方式:finally 块里的日志记录调用单独加 try/catch,绝不能让"记日志"这种辅助性动作的失败影响主业务的正常返回:

} finally {
    watch.stop();
    Integer timeCost = Math.toIntExact(watch.getTotalTimeMillis());
    operationLogAppService.insertLogByEntity(args, result, date, request, timeCost, operationResult, errorMsg, operationLog);
}
} finally {
    watch.stop();
    Integer timeCost = Math.toIntExact(watch.getTotalTimeMillis());
    try {
        operationLogAppService.insertLogByEntity(args, result, date, request, timeCost, operationResult, errorMsg, operationLog);
    } catch (Throwable logEx) {
        // 记录日志失败绝不能影响主业务已经拿到的正常结果,仅记录,不再向外抛出
        LOGGER.error("操作日志记录失败(不影响主业务结果)--------- 》{}.{},异常信息:{}", className, methodName, logEx);
    }
}