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)实现多语言错误提示。

相关推荐
purpleseashell_Lili2 分钟前
react 基本写法
java·服务器·前端
oneDay++23 分钟前
# IntelliJ IDEA企业版高效配置指南:从主题到快捷键的终极优化
java·经验分享·intellij-idea·学习方法
Jasmin Tin Wei30 分钟前
idea中的vcs不见了,如何解决
java·ide·intellij-idea
Java程序员-小白1 小时前
使用java -jar命令指定VM参数-D运行jar包报错问题
java·开发语言·jar
ClearViper32 小时前
Java的多线程笔记
java·开发语言·笔记
全栈凯哥2 小时前
Java详解LeetCode 热题 100(17):LeetCode 41. 缺失的第一个正数(First Missing Positive)详解
java·算法·leetcode
神经毒素2 小时前
WEB安全--Java安全--LazyMap_CC1利用链
java·开发语言·网络·安全·web安全
逸夕2 小时前
httpclient请求出现403
java
呆呆洁ᵔ·͈༝·͈ᵔ3 小时前
配置集群-日志聚集操作
java·ide·eclipse
阑梦清川3 小时前
关于Go语言的开发环境的搭建
开发语言·后端·golang