@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,应用程序将启动-但将使用找到的第一个处理程序。如果您不知道,这可能会导致意外的行为。

 

posted @ 2020-09-03 11:20  9529  阅读(291)  评论(0编辑  收藏  举报