@ControllerAdvice全局异常处理
@ControllerAdvice是Spring提供的注释,使您可以编写可应用于各种控制器的全局代码-从所有控制器到选定的包,甚至是特定的注释。在这个简短的教程中,我们将专注于处理异常使用@ControllerAdvice和@ExceptionHandler(@InitBinder和@ModalAttribute也可以使用@ControllerAdvice)。
使用如下依赖进行测试:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
对于hateoas的相关介绍,可以看看这篇文章https://blog.csdn.net/w57685321/article/details/82894803
默认情况下,
@ControllerAdvice
将应用于使用@Controller
注释的所有类(扩展到使用的类@RestController
)。如果您想更具体一点,可以使用一些属性来实现这一点。要按包减少适用的类,您只需要将包的名称添加到注释中。选择一个程序包后,将为该程序包内的子类以及子程序包启用该程序包。也可以按照相同的过程选择多个包,但是使用数组而不是单个字符串(其中的所有属性都
@ControllerAdvice
可以是单个或多个)。
@ControllerAdvice("my.chosen.package")
@ControllerAdvice(value = "my.chosen.package")
@ControllerAdvice(basePackages = "my.chosen.package")
可以通过basePackageClasses
属性来指定包,该属性将使@ControllerAdvice
类(或接口)所在的包中的所有控制器都可用。
如果要指定特定的类,可以通过@ControllerAdvice(assignableTypes = MyController.class)来指定。
如果要应用于某些带注释的控制器,可以使用 @ControllerAdvice(annotations = RestController.class) ,此处仅对RestController起作用,而不会对带controller的起作用,尽管RestControlle注解相当于@ResponseBody + @Controller。
@ExceptionHandler
顾名思义,您可以定义一个处理异常的方法。如果您不使用@ControllerAdvice
,则处理这些异常的代码将在控制器本身中,这可能会给类增加很多重复和混乱,并导致其不那么“干净”。您可以将这些@ExceptionHandler
方法移到控制器扩展以分离代码的基类中。此方法并不完美,并且存在一个问题,即您需要此全局异常处理的每个控制器现在都需要扩展基本控制器。因此,当您创建一个新的控制器而忘记扩展此基类时,您现在不再处理某些异常,以后可能会陷入困境。使用@ControllerAdvice
随@ExceptionHandler
通过提供全局(更具体的)错误处理来防止这种情况的发生,因此您无需记住自己实现它们或每次扩展另一个类。
示例:
@ControllerAdvice @RequestMapping(produces = "application/vnd.error+json") public class PersonControllerAdvice {
@ExceptionHandler(PersonNotFoundException.class) public ResponseEntity < VndErrors > notFoundException(final PersonNotFoundException e) {
return error(e, HttpStatus.NOT_FOUND, e.getId().toString());
}
private ResponseEntity < VndErrors > error(final Exception exception, final HttpStatus httpStatus, final String logRef) {
final String message = Optional.of(exception.getMessage()).orElse(exception.getClass().getSimpleName());
return new ResponseEntity < > (new VndErrors(logRef, message), httpStatus);
}
@ExceptionHandler(IllegalArgumentException.class) public ResponseEntity < VndErrors > assertionException(final IllegalArgumentException e) {
return error(e, HttpStatus.NOT_FOUND, e.getLocalizedMessage());
}
}
此类
@ExceptionHandler
为所有控制器全局提供了方法,因为(单独从此代码中看不到)有多个throw的控制器PersonNotFoundException
需要处理。RequestMapping
此处的注释用于设置所返回的内容类型ResponseEntity
。这些可以添加到方法本身,而不是需要返回的不同类型。每个@ExceptionHandler
标记实例都负责处理一个异常。本示例中的方法仅捕获异常并获取其错误消息,然后将其与适当的响应代码组合在一起。
@ExceptionHandler
为同一异常定义了多个对象 ,需要进行监视。当在同一类中定义时,Spring足以引发异常并在启动时失败。但是,当它们出现在不同的类中时,例如说两个@ControllerAdvice
类,都带有的处理程序PersonNotFoundException
,应用程序将启动-但将使用找到的第一个处理程序。如果您不知道,这可能会导致意外的行为。