SpringBoot之统一异常管理

326 阅读3分钟

总览

学习一个知识点的灵魂三问

为什么?

怎么做?

为啥可以这样做?

1,为什么需要统一异常管理

这个问题也挺简单,当我们在服务端开发时总会遇到一些无法避免的异常,或由于自己疏忽导致的异常等,如参数绑定异常等。

2,怎么对异常进行处理呢

第一种,在error/目录下编写两个html页面,以4xx,5xx命名

Snipaste_2021-11-02_10-50-38.png

原因:默认情况下,发送异常之后,spring底层会发送一个/error请求,处理所有错误的映射

对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。

对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据。

如果我们编写了错误页面,那么就会把响应状态码作为错误页的地址,error/状态码.html

模板引擎最终响应这个页面 error/状态码.html

第二种,自定义异常处理器

实现HandlerExceptionResolver接口,并放入容器@Component,最后@Order调整优先级

首先我们需要先了解spring给我们提供的默认异常处理器

异常处理器.png

发送异常之后,srping会依次遍历这些异常处理器来进行处理。

所以异常处理器的遍历顺序也就会对彼此进行影响。

默认情况下,我们自定义异常处理器会在最后遍历到。

所以如果我们想让我们的自定义异常处理器能够完全接管异常处理,可以使用设置优先级来进行调整。 @Order(value = Ordered.LOWEST_PRECEDENCE),数值越小,优先级越高

@Order(value = Ordered.LOWEST_PRECEDENCE)
@Component
@Slf4j
public class MyyExceptionController implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("main");
        mv.addObject("err", ex.getMessage());
        log.info(ex.getMessage());
        if (handler != null) {
            log.info(String.valueOf(handler.getClass()));
        }
        //一般返回null,才会遍历下一个异常处理器,如果设置优先级太高,也就会导致所有的异常都会由这个异常处理器处理
        return mv;
      
    }
}

第三种,就是对特定的异常进行处理

@ControllerAdvice+@ExceptionHandler处理全局异常;底层是 ExceptionHandlerExceptionResolver 支持的

代码实现

//推荐使用,理论上可以处理所有异常
@Slf4j
@ControllerAdvice
public class MyExeptionController {
    
    //能够处理异常数组,自己选择
    @ExceptionHandler({ArithmeticException.class, NullPointerException.class, TooMangException.class, MissingServletRequestParameterException.class})//参数绑定异常
    public String soleve(Exception e){
        log.error("异常信息{}" + e);
        return "table/basic_table";//页面
    }
}

自定义异常@ResponseStatus

有时候我们会发现java给我们提供的异常不够用,比如我们不想让某个表的数据量过多,我们希望能够有一个异常来体现。这个时候就需要自己定义我们需要的异常。

@ResponseStatus+自定义异常 ;底层是 ResponseStatusExceptionResolver ,把responsestatus注解的信息进行封装,value:状态码,reason:异常说明

//这个只是增加了框架中的异常种类而已
//这个一般是java底层的异常种类不够用时才使用,抛出的异常也可以被上面第三点接收处理
@ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "数量太多了")
public class TooMangException extends RuntimeException{
    public TooMangException() {
        super();
    }

    public TooMangException(String message) {
        super(message);
    }
}

//在需要的地方throw new TooMangException();即可