Spring 的 异常管理的相关注解@ControllerAdvice 和@ExceptionHandler

@ControllerAdvice 和 @ExceptionHandler 是 Spring 框架中用于全局异常处理的关键注解,它们可以帮助你优雅地处理应用程序中抛出的异常,避免直接将错误信息暴露给用户。下面详细介绍这两个注解的作用和用法:

一、全局异常处理的作用

在 Spring 应用中,当控制器方法抛出异常时,默认会返回 HTTP 500 错误(Internal Server Error),这对用户体验和调试都不友好。全局异常处理可以:

统一错误响应格式:将不同类型的异常转换为标准化的 JSON 或 XML 格式返回给客户端。

隐藏敏感信息:避免直接暴露堆栈跟踪或数据库错误等内部信息。

提高可维护性:将异常处理逻辑集中管理,避免在每个控制器中重复编写。

二、核心注解解析

1. @ControllerAdvice

作用:标记一个类为全局异常处理器,它可以拦截所有控制器中抛出的异常。

使用方式:

@ControllerAdvice

public class GlobalExceptionHandler {

// 异常处理方法

}

特性:

可通过basePackages属性指定拦截特定包下的控制器。

可与@RestControllerAdvice(等价于@ControllerAdvice + @ResponseBody)替换使用。

2. @ExceptionHandler

作用:定义具体的异常处理方法,用于捕获并处理特定类型的异常。

使用方式:

java

@ExceptionHandler(ConstraintViolationException.class)

public ResponseEntity<ErrorResponse> handleValidationException(ConstraintViolationException ex) {

// 处理异常逻辑

}

特性:

可指定多个异常类(如@ExceptionHandler({Exception1.class, Exception2.class}))。

方法返回值可以是ResponseEntity、视图名称或直接返回对象(需配合@ResponseBody)。

三、示例:完善的全局异常处理器

下面是一个更完整的全局异常处理器示例,包含常见的异常类型处理:

import org.springframework.http.HttpStatus;

import org.springframework.http.ResponseEntity;

import org.springframework.validation.BindException;

import org.springframework.validation.FieldError;

import org.springframework.web.bind.MethodArgumentNotValidException;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.validation.ConstraintViolation;

import javax.validation.ConstraintViolationException;import java.util.HashMap;

import java.util.Map;

@ControllerAdvice

public class GlobalExceptionHandler {

// 处理请求参数校验异常(@RequestBody参数)

@ExceptionHandler(MethodArgumentNotValidException.class)

public ResponseEntity<Map<String, String>>

handleMethodArgumentNotValid(MethodArgumentNotValidExceptionex) {

Map<String, String> errors = new HashMap<>();

ex.getBindingResult().getAllErrors().forEach((error) -> {

String fieldName = ((FieldError) error).getField();

String errorMessage = error.getDefaultMessage();

errors.put(fieldName, errorMessage);

});

return ResponseEntity.badRequest().body(errors);

}

// 处理请求参数校验异常(@PathVariable和@RequestParam参数)

@ExceptionHandler(ConstraintViolationException.class)

public ResponseEntity<Map<String, String>> handleConstraintViolation(ConstraintViolationException ex) {

Map<String, String> errors = new HashMap<>();

ex.getConstraintViolations().forEach((violation) -> {

String propertyPath = violation.getPropertyPath().toString();

String errorMessage = violation.getMessage();

errors.put(propertyPath, errorMessage);

});

return ResponseEntity.badRequest().body(errors);

}

// 处理BindException(表单数据绑定错误)

@ExceptionHandler(BindException.class)

public ResponseEntity<Map<String, String>> handleBindException(BindException ex) {

Map<String, String> errors = new HashMap<>();

ex.getBindingResult().getFieldErrors().forEach((error) -> {

errors.put(error.getField(), error.getDefaultMessage());

});

return ResponseEntity.badRequest().body(errors);

}

// 处理其他未明确捕获的异常

@ExceptionHandler(Exception.class)

public ResponseEntity<Map<String, String>> handleGeneralException(Exception ex) {

Map<String, String> error = new HashMap<>();

error.put("message", "Internal Server Error");

error.put("details", ex.getMessage());

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);

}

}

四、异常处理方法详解

1. MethodArgumentNotValidException

触发场景:当@RequestBody参数校验失败时抛出。

处理逻辑:提取字段错误信息,返回 HTTP 400(Bad Request)。

2. ConstraintViolationException

触发场景:当@PathVariable或@RequestParam参数校验失败时抛出。

处理逻辑:提取路径变量 / 请求参数的错误信息,返回 HTTP 400。

3. BindException

触发场景:当表单数据绑定时校验失败(如@ModelAttribute参数)。

处理逻辑:提取表单字段的错误信息,返回 HTTP 400。

4. 通用异常处理

触发场景:捕获所有未被明确处理的异常(如数据库异常、空指针等)。

处理逻辑:返回 HTTP 500(Internal Server Error),隐藏敏感信息。

五、自定义错误响应格式

为了统一 API 返回格式,通常会定义一个标准的错误响应类:

public class ErrorResponse {

private int status;

private String message;

private Map<String, String> details;

private long timestamp;

// 构造方法、getter和setter

}

修改异常处理方法,返回自定义格式:

@ExceptionHandler(MethodArgumentNotValidException.class)

public ResponseEntity<ErrorResponse>

handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {

Map<String, String> errors = new HashMap<>();

ex.getBindingResult().getAllErrors().forEach((error) -> {

errors.put(((FieldError) error).getField(), error.getDefaultMessage());

});

ErrorResponse response = new ErrorResponse(

HttpStatus.BAD_REQUEST.value(),

"Validation Failed",

errors,

System.currentTimeMillis()

);

return ResponseEntity.badRequest().body(response);

}

六、总结

通过@ControllerAdvice和@ExceptionHandler,可以实现:

集中异常处理:将所有异常处理逻辑放在一个类中。

自定义错误响应:根据不同异常类型返回标准化的错误格式。

提升用户体验:避免直接暴露原始异常信息给客户端。

在实际项目中,建议根据业务需求扩展更多异常处理方法,如处理数据库异常(DataAccessException)、认证异常(AuthenticationException)等。同时,可以结合国际化资源文件(message.properties)实现多语言错误提示。

相关推荐
优秀的颜1 小时前
计算机基础知识(第五篇)
java·开发语言·分布式
BillKu1 小时前
Java严格模式withResolverStyle解析日期错误及解决方案
java
网安INF1 小时前
ElGamal加密算法:离散对数难题的安全基石
java·网络安全·密码学
AWS官方合作商2 小时前
在CSDN发布AWS Proton解决方案:实现云原生应用的标准化部署
java·云原生·aws
gadiaola3 小时前
【JVM】Java虚拟机(二)——垃圾回收
java·jvm
coderSong25685 小时前
Java高级 |【实验八】springboot 使用Websocket
java·spring boot·后端·websocket
Mr_Air_Boy6 小时前
SpringBoot使用dynamic配置多数据源时使用@Transactional事务在非primary的数据源上遇到的问题
java·spring boot·后端
豆沙沙包?7 小时前
2025年- H77-Lc185--45.跳跃游戏II(贪心)--Java版
java·开发语言·游戏
年老体衰按不动键盘7 小时前
快速部署和启动Vue3项目
java·javascript·vue
咖啡啡不加糖7 小时前
Redis大key产生、排查与优化实践
java·数据库·redis·后端·缓存