持续创造,加快成长!这是我参与「日新方案 10 月更文应战」的第15天,点击查看活动概况
今天咱们将一块学习下 Spring MVC 中完成一致反常处理的几种办法。
总得来说,一致反常处理有三种办法:
- @Controller + @ExceptionHandler
- ExceptionHandlerExceptionResolver
- @ControllerAdvice + @ExceptionHandler
接下来,咱们逐一演示下上述三种办法。
01-在 Controller 类中运用@ExceptionHandler
注解
其运用办法如下:
@Controller
public class SayHiController {
@ExceptionHandler(value = {MyDemoException.class})
@ResponseBody
public String myDemoExceptionHandler() {
return "MyDemoException Exception";
}
}
在@Controller
中增加一个办法,其上经过注解@ExceptionHandler
标明其要处理的反常类型。
当咱们后续的恳求在当时@Controller
中抛出反常时,会首要运用 ExceptionHandler 来处理。
如果遇到 ExceptionHandler 处理不了的反常类型,则会抛出来,例如:
此种办法的明显缺陷,无法在@Controller
Bean 之间复用、同享,每个都需要单独地界说 ExceptionHandler。
02-运用 HandlerExceptionResolver
Spring Boot 程序在启动时,会注册两个 HandlerExceptionResolver bean 到容器中:DefaultErrorAttributes 和 HandlerExceptionResolverComposite。 其间后者是一个组合类,内部包含一个列表。 它自己并不处理 Exception,而是交由其内部的 resolvers 来处理 Exception。 其内部 resolver 包含(优先级依次降低):
- ExceptionHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
02.1-ExceptionHandlerExceptionResolver
首要用来查找是否有适宜的、标示了@ExceptionHandler
的办法能够处理遇到的反常。
上节中介绍的@Controller
+@ExceptionHandler
办法就是经过 ExceptionHandlerExceptionResolver 完成的。
以及后面要介绍的@ControllerAdvice
+@ExceptionHandler
也是如此。
02.2-ResponseStatusExceptionResolver
首要是负责处理带有@ResponseStatus
注解或承继自 ResponseStatusException 类的反常。
@ResponseStatus
是Spring 3.0引入的,首要用来将某个自界说反常与 HTTP 状况码相关起来。
当 Spring MVC 处理恳求的过程中遇到的反常类标示了@ResponseStatus
注解,Spring 会自动将此反常处理,并向 Response 中增加对应的状况码。
例如,咱们界说如下的反常:
@ResponseStatus(value = HttpStatus.NOT_ACCEPTABLE)
public class MyDemoException extends RuntimeException{
// ...
}
当处理恳求过程中抛出了此类型的反常,Spring 会捕捉,并获取对应的 HTTP 状况码,将其放置到 Response 中:
@GetMapping("/somecustomexception")
@ResponseBody
public String someOtherWithCustomException() throws MyDemoException {
if (true) {
throw new MyDemoException();
}
return "some ~~other~ runtime exception";
}
此种办法虽然能够完成反常类复用,但是仍然有许多不变之处。 必须界说许多自界说反常,而且反常一旦界说且与某个状况码绑定,那所有同类型反常都只能回来同一个状况码,不够灵敏。
Spring 5.0 引入了 ResponseStatusException 反常,处理了上述不够灵敏的问题。 上述事例中,咱们能够经过 ResponseStatusException 反常来改写:
@GetMapping("/someresponsestatusexception")
@ResponseBody
public String someOtherWithResponseStatusException() {
if (true) {
throw new ResponseStatusException(HttpStatus.NOT_ACCEPTABLE);
}
return "ResponseStatusException";
}
02.3-DefaultHandlerExceptionResolver
首要是将标准的 Spring MVC 反常转换成对应的 HTTP 状况码。 具体的反常类型及其对应的 HTTP 状况码能够参考官方网站介绍Handling Standard Spring MVC Exceptions。
02.4-自界说 HandlerExceptionResolver
经过承继 AbstractHandlerExceptionResolver,咱们能够界说自己的反常处理器。
@Component
public class MyDemoHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
public MyDemoHandlerExceptionResolver() {
this.setOrder(-1);
}
@Override
protected ModelAndView doResolveException(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
if (ex instanceof RuntimeException) {
try {
response.sendError(HttpServletResponse.SC_CONFLICT);
} catch (Exception e) {
}
}
return new ModelAndView();
}
}
AbstractHandlerExceptionResolver 完成了 Ordered 接口,因而咱们能够经过操控 order 值来操控所有 Resolver 的优先级。
03-运用@ControllerAdvice
完成全局反常处理
前两节中的办法都是 Spring 3.2 之前的办法,Spring 3.2 之后引入了更便利的办法,即@ControllerAdvice
。
@ControllerAdvice
public class MyDemoControllerAdvice extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = {MyDemoException.class})
public ResponseEntity<Object> handle(RuntimeException ex, WebRequest request) {
String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse,
new HttpHeaders(), HttpStatus.GONE, request);
}
}