Spring异常处理框架

58 篇文章 0 订阅

Spring异常处理框架

初识底层接口类HandlerExceptionResolver

  • HandlerExceptionResolver 是一个处理 Web 程序发生异常时的接口,当异常发生时,需要进行捕获并返回一个友好的ModelAndView给请求用户,可以通过继承AbstractHandlerExceptionResolver来实现。这个接口返回 null 表示让其他异常处理器进行处理,这里由于异常处理链机制,如果不处理异常,就会由 Web 容器将异常返回给客户端(直接将可读性很差的异常信息返回给用户是不推荐的做法)。
    接口如下
@Nullable
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);

底层扩展抽象类AbstractHandlerExceptionResolver

  • 当我们需要实现自定义的 HandlerExceptionResolver时,只要通过继承它的抽象类 AbstractHandlerExceptionResolver,覆写 doResolveException方法就可以了。

避免动不动扩展底层,而使用 @ExceptionHandler

  • 如果觉得只是简单的处理一下指定异常类对应的ModelAndView,最好不要那么麻烦跑去实现HandlerExceptionResolver接口,或者是继承AbstractHandlerExceptionResolver重写doResolveException接口,毕竟这些算是相对比较底层的接口,动不动就重写底层类不是好习惯。那么好习惯是怎样的呢?
  • 好习惯: ExceptionHandlerExceptionResolver类提供了一种 @ExceptionHandler注解,被这个注解过的返回可以处理指定异常的ModelAndView。
    如下:


@RestController 
public class RestApiController { 

    // 指定RestApiController的方法 遇到IllegalStateException,RemoteException时,返回 { data:null, message:"error msg", code: 400 } 给前端
    @ExceptionHandler({ IllegalStateException.class, RemoteException.class }) 
    public ModelAndView handleIllegalStateException(IllegalStateException ex) {  
        System.out.println("非法状态异常出现,需要处理 " + ex.getMessage()); 
        ModelAndView modelAndView = new ModelAndView(); 
        Map<String, String> maps = new HashMap<>(); 
        maps.put("data", null);
        maps.put("message", ex.getClass().getName()); 
        maps.put("code", "400"); 
        MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();        
        mappingJackson2JsonView.setAttributesMap(maps); 
        modelAndView.setView(mappingJackson2JsonView);
        return modelAndView;
     } 
}

  • 【注意】:!!这样方式使用 @ExceptionHandler 存在一个缺陷,就是只会针对当前控制器下的异常处理,比如上面的方法只能处理RestApiController的异常。

@ExceptionHandler的救星 @ControllerAdvice

  • @ExceptionHandler无法对全局异常有效,而加上@ControllerAdvice就可以了
    示例代码:
@ControllerAdvice
public class NormalExceptionHandler {
    @ExceptionHandler()
    public ResponseEntity handleException(Exception e) {
        System.out.println("NormalExceptionHandler handle exception");
        return ResponseEntity.ok(new Result<>(400, e.getMessage(), null));
    }
}

类似上面的代码,两个注解结合就可以实现全局handle了

可以通过 @ControllerAdvice(annotations = RestController.class)约定有效范围,免得动不动就全局

SpringBoot2.0挖的新坑 ErrorController

Springboot默认引入了一个异常处理控制器,他会根据前端请求得
请求时 Header 里 Accept 值是json还是html/text,来决定返回怎样的错误信息。

如下示例:

在这里插入图片描述

图片来源:https://juejin.im/post/5cdfe58051882525de0822a7

可以在 application.properties 设置 server.error.whitelabel.enabled 为 false 干掉这个坑。

ErrorViewResolver 与 ErrorController的关系

ErrorViewResolver是 AbstractErrorController 的成员, 用来解析异常Exception和请求HttpRequest用的,最终会返回ModelAndView给ErrorController,然后丢给前端。

HandlerExceptionResolver 与 ErrorController的关系

没关系。

因为先有Spring的HandlerExceptionResolver,后有SpirngBoot2.0的ErrorController。ErrorController没有用到任何Spring异常类,而是简单的用到了@RequestMapping({"KaTeX parse error: Expected '}', got 'EOF' at end of input: …ver.error.path:{error.path:/error}}"})注解来捕获异常。

他们是不同的两个流派,上面讲了半天都是与HandlerExceptionResolver有关的。
那么ErrorController流派如何处理异常呢?

参考示例如下:


package com.hehe.error;

@Controller@RequestMapping("${server.error.path:/error}")
public class GlobalErrorController implements ErrorController {


    private final static String DEFAULT_ERROR_VIEW = "error";//错误信息页

    /**
     * 情况1:若预期返回类型为text/html,则返回错误信息页(View).
     */
    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public ModelAndView errorHtml(HttpServletRequest request) {
        return new ModelAndView(DEFAULT_ERROR_VIEW, "errorInfo",null);
    }

    @Override
    public String getErrorPath() {//获取映射路径
        return "/error";
    }
    }

上面的代码看看就好,举个例子而已,不是很优雅。

总结:

SpirngBoot有两大 异常处理流派:

自己发明的ErrorController流

以及,Spring原生的 ExceptionHandler流

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值