41. Spring Boot中的`@RestControllerAdvice`如何用于全局异常处理?
大约 3 分钟
在 Spring Boot 中,@RestControllerAdvice
是一个非常强大的注解,它用于集中处理由 @RestController
或 @RequestMapping
注解的控制器抛出的异常。通过使用 @RestControllerAdvice
,你可以实现全局异常处理,从而避免在每个控制器中重复编写相同的异常处理代码。
1. 什么是 @RestControllerAdvice
?
@RestControllerAdvice
是 @ControllerAdvice
和 @ResponseBody
的组合注解,专门用于处理 REST
控制器的全局异常。它使得异常处理方法返回的数据直接序列化为 JSON 或 XML 格式,从而适应 RESTful API 的需求。
2. 如何使用 @RestControllerAdvice
进行全局异常处理
2.1 定义全局异常处理类
要使用 @RestControllerAdvice
进行全局异常处理,你需要定义一个带有该注解的类,并在类中定义处理各种异常的方法。
示例:
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理特定异常
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
// 处理所有未处理的异常
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Internal Server Error");
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
2.2 定义自定义异常类(可选)
在实际应用中,你可能需要定义自定义的异常类来代表特定的错误。
示例:
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
2.3 定义错误响应类
为了统一异常处理的响应格式,你可以定义一个错误响应类。
示例:
public class ErrorResponse {
private int statusCode;
private String message;
public ErrorResponse(int statusCode, String message) {
this.statusCode = statusCode;
this.message = message;
}
// Getters and Setters
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
3. @RestControllerAdvice
的常用功能
@ExceptionHandler
:用于处理特定类型的异常。你可以在方法上使用这个注解,并指定处理的异常类型。@ModelAttribute
:可以在全局范围内绑定模型数据到控制器的处理方法中。@InitBinder
:用于在全局范围内定制WebDataBinder
,可以用来配置全局的表单数据绑定规则。
4. @RestControllerAdvice
作用域控制
@RestControllerAdvice
默认作用于所有控制器,但你可以通过其属性限制作用的范围:
annotations
:指定哪些注解的控制器需要应用此@RestControllerAdvice
。basePackages
或basePackageClasses
:指定应用@RestControllerAdvice
的控制器所在的包或类。
示例:
@RestControllerAdvice(basePackages = "com.example.myapp.controllers")
public class SpecificExceptionHandler {
// 定义处理特定控制器的异常
}
5. 示例总结
假设你的应用中有一个 REST 控制器,它可能抛出一个 ResourceNotFoundException
。你可以通过全局异常处理器来捕获和处理这个异常,并返回标准化的错误响应。
- 全局异常处理类:使用
@RestControllerAdvice
注解,定义一个处理所有异常的类。 - 自定义异常类:根据需要定义特定的异常类型。
- 错误响应类:统一错误响应格式。
6. 完整示例
控制器类:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@GetMapping("/resource/{id}")
public String getResource(@PathVariable("id") int id) {
if (id == 1) {
return "Resource found";
} else {
throw new ResourceNotFoundException("Resource not found with id " + id);
}
}
}
全局异常处理类:
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Internal Server Error");
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
自定义异常类:
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
错误响应类:
public class ErrorResponse {
private int statusCode;
private String message;
public ErrorResponse(int statusCode, String message) {
this.statusCode = statusCode;
this.message = message;
}
// Getters and Setters
}
通过这种方式,你可以在一个地方集中处理异常,并为所有 REST 控制器提供统一的错误响应。这不仅减少了重复代码,还提升了应用的可维护性和一致性。