全局异常处理器 - oljc/arco-serve GitHub Wiki
GlobalExceptionHandler
是一个全局异常处理器,使用 Spring Boot 的 @RestControllerAdvice
注解,能够统一处理整个应用中抛出的各种异常,并返回标准化的 JSON 响应格式。目前就封装了 6 种场景的下的异常自动处理。
graph TD
A[请求进入Controller] --> B{是否抛出异常?}
B -->|否| C[正常返回ApiResponse]
B -->|是| D[Spring AOP捕获异常]
D --> E{异常类型匹配}
E -->|BusinessException| F[handleBusinessException]
E -->|MethodArgumentNotValidException| G[handleMethodArgumentNotValid]
E -->|BindException| H[handleBindException]
E -->|MissingServletRequestParameterException| I[handleMissingParam]
E -->|HttpMessageNotReadableException| J[handleNotReadable]
E -->|其他Exception| K[handleOther]
F --> F1[记录WARN日志<br/>返回自定义错误码和消息]
G --> G1[收集字段错误信息<br/>返回详细验证错误]
H --> H1[收集绑定错误信息<br/>返回绑定错误]
I --> I1[返回缺少的参数名称]
J --> J1[记录WARN日志<br/>返回格式错误提示]
K --> K1[记录ERROR日志<br/>返回通用系统错误]
F1 --> L[统一返回ApiResponse格式]
G1 --> L
H1 --> L
I1 --> L
J1 --> L
K1 --> L
C --> M[客户端接收响应]
L --> M
- 业务异常处理:业务逻辑异常,如数据不存在、权限不足等
- 参数校验异常处理:使用
@Valid
注解进行参数校验时的异常 - 参数绑定异常处理:使用
@ModelAttribute
绑定对象时的异常 - 缺少参数异常处理:必需的请求参数未提供时
- 请求体解析异常处理:JSON 格式错误或请求体解析失败
- 兜底异常处理:未被其他处理器捕获的所有异常
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public ApiResponse<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
if (user == null) {
// 抛出业务异常,会被GlobalExceptionHandler捕获
throw new BusinessException(Code.NOT_FOUND, "用户不存在");
}
return ApiResponse.success(user);
}
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ApiResponse<User> createUser(@Valid @RequestBody CreateUserRequest request) {
// 如果request中的字段不满足校验条件,会抛出MethodArgumentNotValidException
// 被GlobalExceptionHandler捕获并返回详细的字段错误信息
User user = userService.create(request);
return ApiResponse.success(user);
}
}
// 请求对象
public class CreateUserRequest {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 18, message = "年龄不能小于18岁")
private Integer age;
// getters and setters...
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
public ApiResponse<List<User>> getUsers(@ModelAttribute UserQueryRequest request) {
// 如果URL参数绑定到对象时出错,会抛出BindException
// 被GlobalExceptionHandler捕获并返回绑定错误信息
List<User> users = userService.findByQuery(request);
return ApiResponse.success(users);
}
}
所有异常都会返回标准的 ApiResponse
格式:
{
"code": 200,
"message": "成功",
"data": { ... },
"timestamp": "2024-01-01T10:00:00Z"
}
{
"code": 404,
"message": "用户不存在",
"data": null,
"timestamp": "2024-01-01T10:00:00Z"
}
{
"code": 400,
"message": "参数校验失败",
"data": {
"username": "用户名不能为空",
"email": "邮箱格式不正确",
"age": "年龄不能小于18岁"
},
"timestamp": "2024-01-01T10:00:00Z"
}
{
"code": 400,
"message": "缺少必需参数",
"data": {
"param": "id"
},
"timestamp": "2024-01-01T10:00:00Z"
}
{
"code": 400,
"message": "请求体格式错误",
"data": null,
"timestamp": "2024-01-01T10:00:00Z"
}
{
"code": 500,
"message": "系统内部错误",
"data": null,
"timestamp": "2024-01-01T10:00:00Z"
}
-
异常处理顺序: Spring 会按照异常类型的继承关系选择最匹配的处理器,具体的异常类型会优先于通用的异常类型。
-
自定义业务异常: 如需添加新的业务异常,请继承
BusinessException
类或创建新的异常处理方法。 -
扩展性: 如需处理其他类型的异常,可以在
GlobalExceptionHandler
中添加新的@ExceptionHandler
方法。
-
BusinessException
: 自定义业务异常类 -
Code
: 错误码枚举类 -
ApiResponse
: 统一响应格式类