首页 > 其他分享 >Spring Boot「15」统一异常处理

Spring Boot「15」统一异常处理

时间:2022-12-20 22:01:39浏览次数:60  
标签:15 处理 Spring Boot ExceptionHandler Controller 异常 public

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情

今天我们将一块学习下 Spring MVC 中实现统一异常处理的几种方式。

总得来说,统一异常处理有三种方式:

  1. @Controller + @ExceptionHandler
  2. ExceptionHandlerExceptionResolver
  3. @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 处理不了的异常类型,则会抛出来,例如:

mvc_none-mapping-exception.png

此种方式的显著缺点,无法在@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);
    }
}
复制代码
来源:https://juejin.cn/post/7158736790328147981

标签:15,处理,Spring,Boot,ExceptionHandler,Controller,异常,public
From: https://www.cnblogs.com/konglxblog/p/16995194.html

相关文章

  • Spring MVC 拦截器实现登录拦截以及多拦截器的配置执行详解
    持续创作,加速成长!这是我参与「掘金日新计划·10月更文挑战」的第25天,点击查看活动详情前言上一篇文章我们简单了解并完成了SpringMVC拦截器的入门案例,这一篇文章,我们......
  • 构成 Spring Web 服务的各种组件(二)
    6.在客户端上使用SpringWeb服务Spring-WS提供了一个客户端Web服务API,允许对Web服务进行一致的XML驱动访问。它还迎合了编组程序和取消编组程序的使用,以便服务层代码可以......
  • SpringBoot - Yaml语法
    测试用到的类:类的属性必须重写Get与Set方法不管属性是私有的还是公共的,必须重写Get与Set方法@Component@ConfigurationProperties(prefix="student")publicclass......
  • linux操作系统的kill -9 和 kill -15 的区别
    在linux操作系统中,要杀死一个进程需要使用的命令是kill。1kill-9PID强制停掉进程,不给进程使用回调函数的机会,也不会等进程处理完手上的工作,对于已经进入生产环境的系......
  • Spring源码编译
    资料参考地址1:Spring源码编译准备环境配置JDK8(与Spring5的兼容性最好)spring:5.2.0release下载Spring源码直接去官方的github库下载,https://github.com/spring......
  • Spring batch
    1.springbatch--批处理框架2.结构:Job>Flow>Step>Chunk>readprocesswrite2.1基本概念:SpringBatch运行基本单位是一个job,一个job就做一件批处理事情。......
  • SpringBoot - @ImportResource,@ConfigurationProperties 让xml生效与类属性绑定配置文
    @ImportResource作用:使用.xml配置文件范围:必须使用在主程序@SpringBootApplication或配置类上@Configuration@SpringBootApplication@ImportResource("classpath:appl......
  • SpringBoot - 条件注解 @Conditional
    @ConditiOnBean作用:如果Spring容器里面存在指定的Bean则生效范围:类上,方法上,一般在配置类中使用参数:value参数类型Class[],name参数类型String[]IOC容器中组件的名称......
  • 编程常用单词1500个
    很实用的编程英语词库,共收录一千五百余条词汇。第一部分:application应用程式应用、应用程序applicationframework应用程式框架、应用框架应用程序框架architectur......
  • (1)SpringMVC前传
    在我们熟知的建立在三层结构(表示层、业务逻辑层、持久层)基础之上的J2EE应用程序开发之中,表示层的解决方案最多。因为在表示层自身的知识触角很多,需要解决的问题也不少,这也就......