全局异常拦截器实现
-
- [1. 对全局异常拦截器的作用的理解](#1. 对全局异常拦截器的作用的理解)
- [2. 为什么需要全局异常拦截器](#2. 为什么需要全局异常拦截器)
- [3. 实现的基本思路](#3. 实现的基本思路)
- [4. 具体实现步骤](#4. 具体实现步骤)
-
- [4.1 创建异常处理类](#4.1 创建异常处理类)
- [4.2 添加异常处理方法](#4.2 添加异常处理方法)
-
-
- [4.2.1 业务异常 类型处理](#4.2.1 业务异常 类型处理)
- [4.2.2 参数校验异常 类型处理](#4.2.2 参数校验异常 类型处理)
- [4.2.3 系统异常 类型处理](#4.2.3 系统异常 类型处理)
-
- [4.3 实现业务异常处理](#4.3 实现业务异常处理)
- [5. @RestControllerAdvice注解的作用](#5. @RestControllerAdvice注解的作用)
- [6. 为什么叫"全局异常处理拦截器"](#6. 为什么叫"全局异常处理拦截器")
- [7. 异常处理器的执行流程](#7. 异常处理器的执行流程)
- [8. guanjian点 | key point](#8. guanjian点 | key point)
- [2. 不同角度的思考"?](#2. 不同角度的思考“?)
-
- [2.1 拦截器在框架中的角色?扮演什么角色?](#2.1 拦截器在框架中的角色?扮演什么角色?)
- [2.2 Spring 机制怎么知道这是一个拦截器?](#2.2 Spring 机制怎么知道这是一个拦截器?)
- [2.3 我们需要按怎样的"优先级"去拦截异常?](#2.3 我们需要按怎样的“优先级”去拦截异常?)
- [2.4 捕获到不同异常后,分别应该做哪三件事?](#2.4 捕获到不同异常后,分别应该做哪三件事?)
-
- [2.4.1 日志记录](#2.4.1 日志记录)
1. 对全局异常拦截器的作用的理解
全局异常拦截器 是一个Spring组件。
他主要是能
- 捕获controller层抛出来的所有异常
- 将捕获的所有异常转换为统一的响应格式
- 避免在每个controller层中重复的去编写异常处理的代码(冗余代码)
- 统一进行处理业务一场和系统异常
2. 为什么需要全局异常拦截器
- 代码复用 :避免在每个Controller中编写相同的异常处理逻辑(冗余问题)
- 统一 响应 :确保所有异常都返回相同的格式
- 职责分离 :Controller只负责业务逻辑,不负责异常处理 (分明)
- 安全 :避免将系统异常的详细信息暴露给前端(友好)
实现的基本思路
3. 实现的基本思路
- 创建异常处理类。 我们首先需要创建一个异常处理类,
- 添加类注解。 然后我们使用@RestControllerAdvice注解 标记为切片方法,用于捕获controller层的异常
- **添加异常处理方法。**对于该类的方法体,我来下一步就是定义异常处理方法:使用注解@ExceptionHandler对每个方法进行注解
- 异常是有多种不同类型的:业务异常、参数检验异常、系统异常
5.添加异常处理方法注解以及标记不同异常类型。 通过@ExceptionHandler标记不同的类型 - 统一响应 返回。 最后我们在定义的处理异常方法中转换为统一的响应返回给前端去,此时就需要使用统一响应结果结构类中的失败方法返回
Result.failure() 方法、
4. 具体实现步骤
4.1 创建异常处理类
java
@RestControllerAdvice
public class GlobalExceptionHandler {
// 异常处理方法将在这里
}
4.2 添加异常处理方法
例如,我们现在做的是业务异常类型的捕获处理并返回
4.2.1 业务异常 类型处理
添加异常处理方法
java
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public ResponseEntity<Result<Object>> handleBusinessException(BusinessException ex) {
// 实现代码
}
4.2.2 参数校验异常 类型处理
添加异常处理方法
java
//
// 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Result<Object>> handleValidationException(MethodArgumentNotValidException ex) {
// 实现代码
}
yichan
4.2.3 系统异常 类型处理
添加异常处理方法
java
//
// 处理系统异常
@ExceptionHandler(Exception.class)
public ResponseEntity<Result<Object>> handleException(Exception ex) {
// 实现代码
}
4.3 实现业务异常处理
5. @RestControllerAdvice注解的作用
@RestControllerAdvice 是 Spring 框架提供的注解,它结合了以下功能:
- @ControllerAdvice :定义全局控制器增强器,可以处理控制器层的异常
- @ResponseBody :自动将返回值转换为JSON格式
- @Component :作为Spring Bean被容器管理
所以@RestControllerAdvice = @ControllerAdvice + @ResponseBody + @Component

6. 为什么叫"全局异常处理拦截器"
因为它的作用机制是:
- 全局范围 :Spring Boot启动时会自动扫描并注册这个Bean
- 异常拦截 :当Controller层抛出异常时,Spring会自动调用对应的异常处理方法
- 统一处理 :所有异常都会被这个类捕获和处理
- 拦截器模式 :类似于AOP的拦截器,在异常发生时介入处理
7. 异常处理器的执行流程
bash
HTTP请求 → Controller → Service → 抛出异常
↓
Spring捕获异常 → 查找匹配的@ExceptionHandler方法
↓
执行对应的异常处理方法 → 返回统一响应
8. guanjian点 | key point
- @RestControllerAdvice :告诉Spring这是一个全局异常处理器
- @ExceptionHandler :指定要处理的异常类型 - 方法签名 :返回ResponseEntity<Result > ,确保统一响应格式
异常优先级:更具体的异常处理方法会优先匹配
与普通Controller的区别
普通Controller:
java
@RestController
public class MyController {
@GetMapping("/test")
public String test() {
// 业务逻辑
}
}
全局异常处理器:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<Result<Object>> handleException(Exception ex) {
// 异常处理逻辑
}
}
为什么它能全局生效
Spring自动扫描:启动时会注册为Bean
异常传播机制:Spring MVC框架会自动将Controller抛出的异常交给异常处理器
注解驱动:通过@ExceptionHandler注解实现异常类型的匹配
这样,当任何Controller抛出异常时,都会被这个全局异常处理器捕获和处理,实现了真正的"全局"效果。
2. 不同角度的思考"?
2.1 拦截器在框架中的角色?扮演什么角色?
设想一下:当 Controller 或 Service 抛出异常时,如果不处理,Spring 会默认返回 Servlet 容器的 500/404 错误页或者 HTML 。
定位:GlobalExceptionHandler 是系统在 HTTP 协议出口处的最后一道防火墙 ,负责把所有抛出的 Throwable/Exception "揉平"并包装成前端契约规定的统一 Result JSON 结构。
2.2 Spring 机制怎么知道这是一个拦截器?
我们思考一下:我们需要用 Spring MVC 提供的注解 告知 Spring 容器 接管全局异常。
工具:
-
@RestControllerAdvice :标注在类上 。它是 @ControllerAdvice + @ResponseBody 的组合,意味着该类捕获异常后,可以直接返回 JSON 对象。
-
@ExceptionHandler (XxxException.class):标注在具体的方法 上,告诉 Spring "如果抛出了 XxxException ,交给我这个方法来处理"。
2.3 我们需要按怎样的"优先级"去拦截异常?
Spring 匹配 @ExceptionHandler 时,遵循**"就近/精细原则"(即优先匹配更具体的子类异常,最后才匹配父类 Exception**)。
按照我们的业务设计,异常至少划分为 3 层:
bash
[精细度 高] 1. 自定义业务异常 (BusinessException) --> 业务规则主动拦截
│ 2. 参数校验异常 (ValidationException) --> 客户端传参错误
[精细度 低] 3. 未预期系统异常 (Exception) --> 兜底拦截(空指针、数据库故障等)
2.4 捕获到不同异常后,分别应该做哪三件事?
对于被拦截的每一个异常 ,处理函数内部 固定执行标准三部曲:
- 日志记录(Log):
-
业务 异常/参数 校验:打 log.warn (不需要打堆栈 ,属于正常业务拦停)。
-
未预期系统异常 :打 log.error ("...", ex)(必须打印完整堆栈 ,用于排查线上传奇 Bug)。
- HTTP 状态码映射(HTTP Status):
比如
STORE_NOT_FOUND 映射为 HTTP 404。
参数错误映射为 HTTP 400。
系统错误映射为 HTTP 500。
- 返回统一响应体(Response Body):
统一调用 Result.failure(...) 组装结构。
失败响应的 data 统一置为 null。
绝对不能把未预期异常(如 SQL 语法错误、NullPointer)的原始 ex.getMessage() 吐给前端,防止泄露数据表结构或安全隐患斜体样式。