Spring Boot 全局异常处理器(GlobalExceptionHandler)

张开发
2026/4/11 20:50:22 15 分钟阅读

分享文章

Spring Boot 全局异常处理器(GlobalExceptionHandler)
Spring Boot 全局异常处理器GlobalExceptionHandler的核心代码是和CommonResultT配套的后端统一异常处理方案每一行代码的作用以及为什么要单独写这个类。This is the core code of the Spring Boot GlobalExceptionHandler, which is part of the backend unified exception handling solution paired withCommonResultT. Below, I will explain the function of each line of code, as well as why this class is written separately.一、代码逐行拆解1. 核心注解与类结构// 全局异常处理器注解标记这是一个全局异常处理类 RestControllerAdvice public class GlobalExceptionHandler { // 注入日志对象用于打印异常栈 private static final Logger logger LoggerFactory.getLogger(GlobalExceptionHandler.class); // 1. 处理 Controller 层自定义异常示例 ExceptionHandler(value ControllerException.class) public CommonResult? controllerException(ControllerException e) { // 打印错误日志方便排查问题 logger.error(controllerException:, e); // 封装统一错误响应返回给前端 return CommonResult.error( GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), e.getMessage() ); } // 2. 处理所有未捕获的 Exception 异常兜底 ExceptionHandler(value Exception.class) public CommonResult? exception(Exception e) { // 打印服务异常日志包含完整异常栈 logger.error(服务异常:, e); // 封装统一错误响应返回给前端 return CommonResult.error( GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), e.getMessage() ); } }2. 关键注解说明注解作用RestControllerAdvice标记类为全局异常处理器会拦截所有RestController抛出的未捕获异常是全局异常处理的核心注解ExceptionHandler(value 异常类.class)标记方法用于处理指定类型的异常value Exception.class表示捕获所有未被其他方法处理的异常兜底3. 核心逻辑拆解日志打印logger.error(xxx:, e)作用把完整的异常栈信息打印到日志文件中方便开发 / 运维排查线上问题注意这里必须传e异常对象才能打印完整的异常栈只传e.getMessage()只会打印错误信息无法定位问题统一响应封装CommonResult.error(...)作用把异常封装成和CommonResultT完全一致的格式返回给前端结构{ code: 500, msg: xxx错误信息, data: null }优势前端不用再处理「接口抛异常返回 500 错误页」的情况永远收到统一格式的响应错误码常量GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR作用统一管理错误码避免魔法值比如直接写 500保证全项目错误码一致示例INTERNAL_SERVER_ERROR对应code500msg服务器内部错误二、为什么要单独写这个类核心设计意义如果不写这个全局异常处理器会出现什么问题1. 原生 Spring Boot 异常返回的痛点接口失败时前端收到的是「错误页 / 500 状态码」不是统一格式的 JSON比如Whitelabel Error Page页面前端无法解析直接报错不同异常的返回结构五花八门前端要写 N 套错误处理逻辑异常信息直接暴露给用户比如NullPointerException、SQL 语法错误等敏感信息有安全风险业务异常和系统异常混在一起排查困难2. 全局异常处理器的核心价值✅ 1. 统一异常返回格式和 CommonResult 完美适配所有异常不管是业务异常、系统异常都被封装成CommonResult.error()前端永远收到统一格式的 JSON一套逻辑处理所有错误彻底解决前后端联调的痛点。✅ 2. 业务代码零侵入专注业务逻辑Controller/Service 层只需要直接抛异常不用手动写try-catch封装CommonResult.error()业务代码更干净、更易维护。// 业务代码中直接抛异常即可不用手动处理返回 if (user null) { throw new BusinessException(用户不存在); }✅ 3. 敏感信息隐藏提升系统安全性可以自定义异常处理逻辑不把底层异常栈如 SQL 错误、空指针直接返回给用户只返回友好的提示信息避免泄露系统细节。// 优化示例隐藏底层异常返回统一提示 return CommonResult.error( GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), 服务器繁忙请稍后再试 );✅ 4. 统一日志管理便于问题排查所有异常都在这个类中统一打印日志不用在每个 Controller 中手动写日志日志格式统一排查问题更高效。✅ 5. 分层异常分类处理可扩展性极强可以针对不同类型的异常写不同的处理逻辑业务异常BusinessException返回业务错误码如 400 参数错误权限异常UnauthorizedException返回 401 未授权系统异常Exception返回 500 服务器错误限流异常、熔断异常等单独处理返回对应错误码三、完整优化版代码生产环境可直接用package com.example.lotterysystem.controller.handler; import com.example.lotterysystem.common.errorcode.GlobalErrorCodeConstants; import com.example.lotterysystem.common.exception.BusinessException; import com.example.lotterysystem.common.pojo.CommonResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; /** * 全局异常处理器 * 统一处理所有Controller抛出的异常封装为CommonResult返回 */ RestControllerAdvice public class GlobalExceptionHandler { private static final Logger logger LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 处理业务自定义异常主动抛出的业务错误 */ ExceptionHandler(value BusinessException.class) public CommonResult? businessException(BusinessException e) { logger.error(业务异常: {}, e.getMessage(), e); return CommonResult.error(e.getCode(), e.getMessage()); } /** * 处理参数校验异常Valid 注解校验失败 */ ExceptionHandler(value ConstraintViolationException.class) public CommonResult? constraintViolationException(ConstraintViolationException e) { logger.error(参数校验异常: {}, e.getMessage(), e); // 提取第一个校验错误信息 String msg e.getConstraintViolations().stream() .map(ConstraintViolation::getMessage) .findFirst() .orElse(参数错误); return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), msg); } /** * 处理所有未捕获的系统异常兜底 */ ExceptionHandler(value Exception.class) public CommonResult? exception(Exception e) { logger.error(服务异常: , e); // 生产环境隐藏底层异常返回统一提示避免泄露敏感信息 return CommonResult.error( GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), 服务器繁忙请稍后再试 ); } }四、和 CommonResultT 的联动流程完整闭环前端发起请求 ↓ Controller 接收参数 ↓ Service 执行业务逻辑 ↓ 业务执行结果 / \ 成功 失败/抛异常 ↓ ↓ CommonResult.success() → 全局异常处理器捕获异常 ↓ CommonResult.error() ↓ SpringBoot 序列化为统一JSON ↓ 返回给前端统一格式响应五、关键优化建议生产环境必做禁止直接返回e.getMessage()给前端生产环境中系统异常如空指针、SQL 错误的getMessage()会泄露系统细节必须替换为统一提示如「服务器繁忙请稍后再试」只在日志中打印完整异常栈。自定义业务异常类单独定义BusinessException继承RuntimeException用于主动抛出业务错误和系统异常区分开方便分类处理。错误码枚举化所有错误码都定义在GlobalErrorCodeConstants枚举中避免魔法值保证全项目错误码一致。参数校验异常单独处理针对Valid注解的参数校验异常单独提取错误信息返回友好提示提升用户体验。

更多文章