通义灵码全局异常控制:ControllerAdvice编写最佳实践
在Spring Boot项目中实现全局异常处理,看似简单,实际开发中常在两个环节出错:处理器类未被扫描,或异常匹配顺序颠倒,导致前端收到混乱的堆栈信息。本文从零梳理完整实现,确保落地即用。
关键前提:@RestControllerAdvice类必须位于@ComponentScan扫描范围内,否则Spring不会注册该Bean,全局异常处理器形同虚设。定义@ExceptionHandler方法时,需遵循从具体到宽泛的原则:优先捕获NullPointerException、参数校验异常,其次处理自定义BusinessException,最后以Exception.class兜底。顺序一旦颠倒,具体异常会被通用处理器提前拦截,失去精细控制。
直接进入实现环节。
编写全局异常处理类
在项目任意目录下新建一个Java类,命名为GlobalExceptionHandler.ja va,加上@RestControllerAdvice注解——它等价于@ControllerAdvice与@ResponseBody的组合,使得所有方法默认返回JSON格式,无需在每个方法上重复添加@ResponseBody。
类内部需定义多个@ExceptionHandler方法,排列顺序严格遵循“越具体越靠前”的原则。例如优先处理NullPointerException和IllegalArgumentException等业务常见异常,接着处理自定义的BusinessException,最后用Exception.class做兜底。再次强调:处理器类绝对不能位于@ComponentScan扫描路径之外,否则异常处理逻辑完全失效,代码形同虚设。
定义统一响应结构
全局异常处理的核心在于提供统一的JSON响应格式,便于前端统一解析。以下两种常见方案:
- 方法一:Lombok配合静态工厂模式
新建一个Result类,包含code、message、data三个字段。提供两个静态方法success()和error(),分别组装成功与失败响应。这是最简洁、最常用的方式。 - 方法二:复用现有响应对象
若项目中已有Response等通用响应类(例如兼容Swagger),可直接在@ExceptionHandler方法中返回Response.fail(400, "参数错误"),避免重复维护。
分类型精确处理异常
核心部分来了——根据不同异常类型定制处理逻辑,而非一刀切。
第一步:捕获空指针异常
通过@ExceptionHandler(NullPointerException.class)标注的方法,返回Result.error(500, "系统繁忙,请稍后再试")。务必避免返回类似user.getName()的调用链细节,以免暴露内部实现且对用户无实际帮助。
第二步:处理参数缺失异常
当捕获到MissingServletRequestParameterException,利用e.getParameterName()获取缺失参数名,返回Result.error(400, e.getParameterName() + "是必填项")。这种提示比笼统的“参数错误”更精准,前端可快速定位问题。
第三步:处理自定义业务异常
业务层抛出new BusinessException(1001, "库存不足")时,@ExceptionHandler(BusinessException.class)方法直接提取异常中的code和message填充Result。保持前后端错误码一致,排查问题更高效。
第四步:兜底处理未捕获的异常
@ExceptionHandler(Exception.class)必须置于所有具体处理器之后——若前置,则具体异常处理逻辑永远不会被执行,所有异常均被其吞没。该方法返回通用500错误,例如“服务异常,请稍后重试”,确保用户看到友好提示,而非堆栈信息。
关键要点:确保扫描路径正确、异常处理顺序从具体到通用、响应格式保持一致。掌握这三点,全局异常处理即可稳定运行。
