@RestControllerAdvice注解
@RestControllerAdvice
是 Spring 4 引入的一个组合注解,它结合了 @ControllerAdvice
和 @ResponseBody
,专门用于处理 @RestController
类型的控制器中的全局异常、全局数据绑定和全局模型属性等问题。在 Spring Boot 中,@RestControllerAdvice
通常用于统一处理应用中的异常,确保系统中的异常处理逻辑集中管理。
1. @RestControllerAdvice
的组成
@RestControllerAdvice
实际上是两个注解的组合:
@ControllerAdvice
:是一个用于全局处理 Spring MVC 中异常的注解,它的作用范围不仅限于某个单一的控制器,而是全局适用。@ResponseBody
:表示返回的对象会自动序列化为 JSON 格式,直接作为 HTTP 响应体返回。
因此,@RestControllerAdvice
结合了这两者的功能,表示该类是一个控制器增强器,可以全局处理异常、模型属性或数据绑定等,而且返回的结果会直接作为 HTTP 响应体(通常是 JSON 格式)返回给客户端。
2. @RestControllerAdvice
的功能
@RestControllerAdvice
主要有以下几个功能:
1. 全局异常处理 (@ExceptionHandler
)
@RestControllerAdvice
可以结合 @ExceptionHandler
注解来全局处理异常。应用中抛出的异常会被该类中的方法捕获并处理,然后返回合适的响应结果。
例如:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResultData handleException(Exception e) {
log.error("Global exception occurred: ", e);
return ResultData.fail("500", "Internal Server Error");
}
}
@ExceptionHandler(Exception.class)
:表示该方法将处理所有类型的Exception
异常。handleException
方法会捕获到任何未被其他异常处理器捕获的Exception
,然后返回统一的错误响应。
2. 全局模型属性 (@ModelAttribute
)
@RestControllerAdvice
可以在控制器方法执行前,通过 @ModelAttribute
注解向所有的控制器方法添加公共模型属性。这样,所有的控制器方法都可以访问到这些公共属性。
例如:
@RestControllerAdvice
public class GlobalModelAttribute {
@ModelAttribute
public void addAttributes(Model model) {
model.addAttribute("globalAttribute", "This is a global attribute");
}
}
@ModelAttribute
注解的方法会在每个控制器方法执行之前执行。这里添加了一个名为globalAttribute
的属性,这个属性会自动添加到每个控制器方法的Model
中。
3. 全局数据绑定 (@InitBinder
)
@RestControllerAdvice
也可以通过 @InitBinder
注解定义全局的数据绑定方法。@InitBinder
用于初始化数据绑定,通常用于处理请求参数的格式化和转换。
例如:
@RestControllerAdvice
public class GlobalDataBinder {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields("password");
}
}
@InitBinder
注解的方法可以用来处理请求参数的绑定和验证。在上面的例子中,所有请求参数中的password
字段将被排除在外,不能进行绑定。
3. 常见用法
1. 全局异常处理
在 Spring Boot 中,异常处理通常分为两种:
- 局部异常处理:每个控制器方法使用
try-catch
语句或者@ExceptionHandler
处理特定的异常。 - 全局异常处理:通过
@RestControllerAdvice
统一处理整个应用中的异常。
示例:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResultData<String> handleException(Exception e) {
log.error("Unexpected exception occurred: ", e);
return ResultData.fail("500", "Internal Server Error");
}
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResultData<String> handleResourceNotFound(ResourceNotFoundException e) {
log.error("Resource not found: ", e);
return ResultData.fail("404", e.getMessage());
}
}
- 通过
@ExceptionHandler
注解,可以指定不同的异常类型来进行处理。例如,Exception
类的异常返回 500 错误,ResourceNotFoundException
返回 404 错误。 - 使用
@ResponseStatus
注解可以自定义返回的 HTTP 状态码。
2. 返回统一格式的响应
在实际应用中,通常会要求所有的 API 响应都遵循统一的格式。使用 @RestControllerAdvice
可以确保异常处理的响应符合统一的格式。
示例:
public class ResultData<T> {
private String code;
private String message;
private T data;
// 省略构造方法、getter、setter等
}
在 GlobalExceptionHandler
中,可以返回 ResultData
类型的对象,确保所有的异常响应都有一致的结构:
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResultData<String> handleException(Exception e) {
return new ResultData<>("500", "Internal Server Error", null);
}
3. 全局模型属性和数据绑定
@RestControllerAdvice
还可以用来定义全局的模型属性和数据绑定逻辑。比如,可以在全局中设置一些公共的参数,或者格式化请求参数。
示例:
@RestControllerAdvice
public class GlobalDataBinder {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
}
在这个例子中,@InitBinder
配置了一个全局的数据绑定,允许所有的控制器方法接收和格式化 Date
类型的参数。
4. @RestControllerAdvice
的优势
- 集中管理异常:通过
@RestControllerAdvice
,你可以把全局的异常处理逻辑集中在一个地方,而不需要在每个控制器中重复写异常处理代码。 - 统一的错误响应:能够保证整个应用中返回的错误响应有统一的结构(例如
ResultData
)。 - 增强可维护性:集中式的异常处理和数据绑定配置使得代码更易维护和扩展。当业务需求发生变化时,只需要修改
@RestControllerAdvice
中的逻辑,而无需修改每个控制器的代码。 - 减少冗余代码:通过全局处理,可以避免在多个控制器中重复定义相同的异常处理逻辑或数据绑定逻辑。
是的,@RestControllerAdvice
和@ControllerAdvice
都可以实现相似的功能,特别是在处理全局模型属性和数据绑定时,使用@ControllerAdvice
是完全可以的。两者的区别主要体现在以下几个方面:
5.@RestControllerAdvicevs
@ControllerAdvice
@RestControllerAdvice
vs @ControllerAdvice
-
@ControllerAdvice
是 Spring 的一个用于全局处理控制器异常、数据绑定、模型属性等的注解,适用于所有类型的控制器。它结合了@Controller
和@ResponseBody
的功能,用于处理普通的控制器(即返回视图的控制器,通常是.jsp
、.html
等)。 -
@RestControllerAdvice
是@ControllerAdvice
和@ResponseBody
的组合注解,适用于 RESTful 风格的控制器,即返回 JSON 或 XML 等数据的控制器。它与@RestController
结合使用,可以自动将返回值转换为 JSON 格式的响应体,而@ControllerAdvice
适用于传统的基于视图的控制器。
具体区别
-
返回类型:
@ControllerAdvice
默认处理的是基于视图的返回类型,也就是说,它通常返回的是页面视图(例如.jsp
、.html
)而非 JSON 数据。@RestControllerAdvice
用于 RESTful API 服务,它默认会返回 JSON 数据,而不需要额外配置@ResponseBody
。
-
场景选择:
- 使用
@ControllerAdvice
:如果你的应用主要是传统的 Spring MVC 控制器(处理视图渲染),那么@ControllerAdvice
是合适的。 - 使用
@RestControllerAdvice
:如果你的应用是基于 RESTful API 服务,返回 JSON 或 XML 数据,并且你希望所有的异常处理、数据绑定、模型属性等也以 JSON 格式返回,那么@RestControllerAdvice
更为合适。
- 使用
实际应用中的选择
- 如果你在做的是 传统的 Spring MVC 应用,并且通过控制器返回的是 视图(HTML),那么使用
@ControllerAdvice
是合适的。 - 如果你在做的是 RESTful API 应用,返回的是 JSON 或 XML 数据,并且希望全局异常、全局数据绑定、全局模型属性等都以 JSON 格式返回给客户端,那么
@RestControllerAdvice
更为合适。
总结
@RestControllerAdvice
是 Spring 提供的一个功能强大的注解,允许你为整个应用提供全局的异常处理、全局模型属性和全局数据绑定等功能。它的主要优势是能够集中管理异常处理,并且提供统一的响应结构,使得应用程序更加清晰、易于维护,尤其在处理大规模应用时,能够极大地减少代码冗余,提高开发效率和系统的健壮性。