SpringMVC中统一处理异常

今天和大家谈谈SpringMVC中如何统一处理异常。本篇文章我们还是以简单明了的风格和大家介绍。

我们使用SpringBoot来进行讲解,其版本为2.2.1.RELEASE。首先来谈一下SpringMVC和Http状态码的关系。

把异常映射为HTTP状态码

需要提到的是在SpringMVC中出现以下异常时,SpringMVC就会把这些异常自动转换成特定的Http状态码。异常和状态码的映射关系如下:

  1. BindException->400:BadRequest
  2. ConversionNotSupportedException->500:Internal Server Error
  3. HttpMediaTypeNotAcceptableException->406:Not Acceptable
  4. HttpMediaTypeNotSupportedException->415:Unsupported Media Type
  5. HttpMessageNotReadableException->400:BadRequest
  6. HttpMessageNotWritableException->500:Internal Server Error
  7. HttpRequestMethodNotSupportedException->405:Method Not Allowed
  8. MethodArgumentNotValidException->500:Internal Server Error
  9. MissingServletRequestParameterException->400:BadRequest
  10. MissingServletRequestPartException->400:BadRequest
  11. TypeMismatchException->400:BadRequest

除此之外,我们还可以把我们自定义的异常也映射为HTTP状态码。达到这种目的的方式是用一个注解来标记这个我们自定义的异常,这个注解就是@ResponseStatus,用法如下:

SpringMVC中统一处理异常_第1张图片

@ResponseStatus标记异常类

@ResponseStatus注解的value属性表示返回的HTTP状态码,reason表示消息。当Controller抛出ParamException异常时,SpringMVC会返回一个400的HTTP状态码,因为HttpStatus.BAD_REQUEST的值是400。

SpringMVC中统一处理异常_第2张图片

抛出ParamException

请求index3路径之后浏览器会收到400的响应,如图:

SpringMVC中统一处理异常_第3张图片

type=Bad Request, status=400

那么如果我们把ParamException异常类的注解@ResponseStatus去掉,浏览器又会收到什么状态码呢?去掉后如图:

SpringMVC中统一处理异常_第4张图片

注释掉@ResponseStatus

浏览器得到的状态如下,我们可以从图中看到HTTP状态是500:

SpringMVC中统一处理异常_第5张图片

type=Internal Server Error, status=500

这就说明了我们是可以通过@ResponseStatus注解把ParamException异常映射为400状态码的。

在SpringMVC的开发过程中仅仅把特定的异常映射为HTTP状态码是远远不够的,我们还需要统一处理Controller中抛出的异常。那么如何实现呢?我们在这里提供2种方式,下面我们一一来看。

第一种:在Controller的基类中统一处理

        首先要说明的是@ExceptionHandler注解,这个注解是用来标记一个方法是异常处理器。这个注解标记的方法能够处理当前Controller中所有抛出的异常,如果把这个注解用在一个Controller的基类中,让所有的Controller都继承这个基类,那么这个被@ExceptionHandler注解标记的方法就能处理所有Controller抛出的异常了。

        先看一下基类如何设置:

基类

package com.fri.audioengine.utils;

import org.springframework.web.bind.annotation.ExceptionHandler;

public class BaseExceptionController {
    @ExceptionHandler(Exception.class)
    void myExcptionHandler(Exception ex){
        if(ex instanceof IllegalStateException){
            System.out.println("io is");
        }else if(ex instanceof NullPointerException){
            System.out.println("null ex");
        }
    }
}

        从图中可以看到这个基类非常简单,仅仅一个方法,而且这个方法被@ExceptionHandler注解标记,括号中的参数表示这个方法用于处理什么类型的异常。这个方法有一个参数,这个参数可以接收到抛出的异常。

继承基类

        再让其他的具体的Controller继承这个基类就可以了,如图:

SpringMVC中统一处理异常_第6张图片

        这样就完成了,在基类的myExceptionHandler方法中就可以统一处理所有Controller中抛出的异常了。

第二种:在Controller的切面中统一处理

        这种方式就是为Controller设置一个切面,在切面中处理异常。

定义切面

        首先定义一个切面,定义切面的方式是在切面类上添加@ControllerAdvice注解就可以了,标记完切面之后再通过@ExceptionHandler注解定义异常处理方法,如图:

SpringMVC中统一处理异常_第7张图片

        然后我们就可以定义控制器了,而且我们的控制器也不用继承基类控制器了,如图:

SpringMVC中统一处理异常_第8张图片

        这样所有Controller抛出的异常都能被Controller的切面中的异常处理器捕获到了,是不是很简单呢?

结束语

        今天简单和大家分享了如果统一处理Controller的异常,在这里简单总结一下,第一点就是定义处理异常的handler,这是必须的,而且无论你是通过基类处理还是通过切面处理这都是不能缺少的。在这两种方式中定义异常handler的方式都是通过@ExceptionHandler注解完成的。

你可能感兴趣的:(Spring,Boot,学习笔记,异常处理)