@ControllerAdvice 是 Spring Framework 中的一个重要注解,主要用于全局处理异常、数据绑定和模型属性的配置。它使得你能够在多个控制器类中集中处理错误、共享模型数据,或者修改请求的绑定和响应。它是专门为控制器(@Controller)和请求(@RequestMapping)相关的操作提供的全局配置和功能。

1. 基本概念和用途

  • 全局异常处理@ControllerAdvice 可以用于捕获和处理控制器层的异常,并返回相应的 HTTP 状态码和错误消息。通常与 @ExceptionHandler 配合使用。
  • 全局模型属性:你可以使用 @ControllerAdvice 来定义全局共享的模型属性,这些属性可以在多个控制器方法中使用。
  • 全局数据绑定@ControllerAdvice 还可以用于全局配置数据绑定,影响所有控制器中绑定请求参数的方式。

2. @ControllerAdvice 的基本用法

2.1 全局异常处理

你可以通过 @ExceptionHandler 注解和 @ControllerAdvice 来统一处理所有控制器中的异常。

示例 1:全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {

    // 处理指定异常类型
    @ExceptionHandler(CustomException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)  // 设置 HTTP 响应码
    public String handleCustomException(CustomException ex) {
        // 返回异常的消息
        return "Error: " + ex.getMessage();
    }

    // 处理所有未处理的异常
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String handleGlobalException(Exception ex) {
        return "Global Error: " + ex.getMessage();
    }
}

解释

  • @ExceptionHandler:这个注解用于捕获指定类型的异常,当指定的异常被抛出时,@ControllerAdvice 会捕获并处理这些异常。
  • @ResponseStatus:用于设置异常处理后返回的 HTTP 状态码,像 500(内部服务器错误)或者 400(错误请求)。
  • handleCustomException:处理 CustomException 异常并返回错误信息和 HTTP 500 状态码。
  • handleGlobalException:处理所有没有特别指定的异常,并返回 HTTP 400 状态码。
示例 2:为不同的异常类型返回不同的响应
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NullPointerException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public String handleNullPointerException(NullPointerException ex) {
        return "NullPointerException: " + ex.getMessage();
    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String handleIllegalArgumentException(IllegalArgumentException ex) {
        return "IllegalArgumentException: " + ex.getMessage();
    }
}

在这个例子中,NullPointerException 会返回 500 错误码,而 IllegalArgumentException 会返回 400 错误码。

2.2 捕获全局异常并返回统一格式的响应

你可以让异常处理返回更结构化的响应,而不是简单的字符串消息,通常返回一个包含错误代码、错误信息等字段的 JSON 对象。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex) {
        ErrorResponse errorResponse = new ErrorResponse("ERR-500", ex.getMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

ErrorResponse 类:

public class ErrorResponse {
    private String code;
    private String message;

    public ErrorResponse(String code, String message) {
        this.code = code;
        this.message = message;
    }

    // Getter and Setter
}

在这个例子中,异常处理器将会返回一个 JSON 格式的响应,包含 codemessage 字段,而不是直接返回一个简单的字符串。

2.3 处理特定异常类型并提供详细错误信息

你可以根据不同的异常类型返回不同的错误信息,甚至使用 ResponseEntity 来进一步控制响应的内容。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(CustomException.class)
    public ResponseEntity<ErrorResponse> handleCustomException(CustomException ex) {
        ErrorResponse errorResponse = new ErrorResponse("CUSTOM_ERROR", ex.getMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {
        ErrorResponse errorResponse = new ErrorResponse("GENERAL_ERROR", "A general error occurred");
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

解释

  • handleCustomException 返回一个包含错误代码 CUSTOM_ERROR 和错误消息的 ErrorResponse,并返回 400 状态码。
  • handleGeneralException 处理所有其他未捕获的异常,并返回 500 状态码。

3. @ControllerAdvice 用于全局数据绑定

除了异常处理,@ControllerAdvice 还可以用于全局的数据绑定。可以配置全局的参数验证、格式化等。

示例:全局数据绑定
@ControllerAdvice
public class GlobalBindingHandler {

    // 为所有请求的参数添加全局的数据格式化规则
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.setDisallowedFields("password"); // 禁止绑定密码字段
    }
}

解释:使用 @InitBinder 可以初始化 WebDataBinder,它允许你全局配置参数绑定的行为,比如禁用某些字段的绑定(如 password 字段)。

4. @ControllerAdvice 用于全局模型属性

你还可以使用 @ControllerAdvice 来共享模型数据,这些数据会在每个控制器方法中都可用。

示例:共享全局模型属性
@ControllerAdvice
public class GlobalModelAttributes {

    @ModelAttribute("globalAttribute")
    public String globalAttribute() {
        return "This is a global attribute available in all controllers";
    }
}

解释

  • @ModelAttribute 注解的作用是将 globalAttribute 添加到模型中,这样每个控制器都能访问这个全局属性。
在控制器中使用共享的模型属性
@Controller
public class SomeController {

    @GetMapping("/some-page")
    public String somePage(@ModelAttribute("globalAttribute") String globalAttribute) {
        System.out.println(globalAttribute); // 输出:This is a global attribute available in all controllers
        return "somePage";
    }
}

5. @ControllerAdvice 的作用范围

  • 适用于所有控制器@ControllerAdvice 可以被应用到所有标注为 @Controller 的类,所有控制器共享其配置,确保代码简洁、统一。
  • 组合使用@ControllerAdvice 可以与其他注解如 @ExceptionHandler@ModelAttribute@InitBinder 等一起使用,处理异常、共享模型数据、进行数据绑定等。

6. 常见的 @ControllerAdvice 使用场景

  1. 全局异常处理:捕获整个应用程序中的所有异常,并统一返回特定的 HTTP 状态码和错误信息。
  2. 全局数据绑定:全局配置请求参数的绑定规则,像禁用某些字段的绑定、数据格式化等。
  3. 全局模型属性:共享全局模型属性,避免每个控制器都写相同的数据。
  4. 统一的响应结构:在异常发生时返回统一格式的响应体,保持 API 的一致性。

总结

@ControllerAdvice 是 Spring 中一个强大的注解,可以让你集中处理与控制器相关的功能,如异常处理、数据绑定、共享模型属性等。通过 @ExceptionHandler 你可以捕获并处理全局异常,返回合适的 HTTP 响应码;通过 @ModelAttribute 你可以共享全局的模型数据;通过 @InitBinder 你可以配置全局的数据绑定行为。@ControllerAdvice 提供了一种集中式、优雅的方式来处理与 Web 层相关的功能,使得代码更加模块化和可维护。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐