当前位置: 首页 > news >正文

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(MethodArgumentNotValidException ex) {

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

相关文章:

  • Java NIO 深度解析:突破传统IO的性能瓶颈
  • ​​金融合规革命:​​R²AIN SUITE 如何重塑银行业务智能​
  • OpenHarmony系统HDF驱动开发介绍(补充)
  • Kotlin 中 infix 关键字的原理和使用场景
  • C++23 ranges::to:范围转换函数 (P1206R7)
  • iOS视频编码详细步骤(视频编码器,基于 VideoToolbox,支持硬件编码 H264/H265)
  • Linux内核可配置的参数
  • 部署安装gitlab-ce-17.9.7-ce.0.el8.x86_64.rpm
  • QT之信号与槽
  • 深入理解ThingsBoard的Actor模型
  • std::ratio<1,1000> 是什么意思?
  • C语言_自定义类型:结构体
  • JT/T 808 各版本协议字段级别对比与解析适配建议
  • Spring AI 集成 Mistral AI:构建高效多语言对话助手的实战指南
  • 全流量解析:让安全防御从“被动挨打”升级为“主动狩猎”
  • 【Linux网络】网络层
  • RabbitMQ 快速上手:安装配置与 HelloWorld 实践(二)
  • maven项目, idea右上角一直显示gradle的同步标识, 如何去掉
  • Restfull API 风格规则以及特点
  • Unity Image组件无法阻挡手势的解决办法
  • 明查| 新一代AI诊疗系统可3秒筛查13种癌症?没有证据
  • 跨文化戏剧的拓荒者与传承者——洪深与复旦剧社的百年回响
  • 线下哪些商家支持无理由退货?查询方法公布
  • 国内首例侵入式脑机接口系统前瞻性临床试验:受试者已能用意念玩游戏
  • 演员发文抵制代拍获粉丝支持,媒体:追星“正确姿势”不妨多来点
  • 美国长滩港货运量因关税暴跌三成,港口负责人:货架要空了