SpringMVC多拦截器执行顺序与异常处理

366 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第29天,点击查看活动详情

多拦截器执行顺序

如果我们配置了多个拦截器,拦截器的顺序是按照配置的先后顺序的。

这些拦截器中方法的执行顺序如图(preHandler都返回true的情况下):

image.png

如果拦截器3的preHandle方法返回值为false。执行顺序如图:

image.png

  • 只有所有拦截器都放行了,postHandle方法才会被执行。
  • 只有当前拦截器放行了,当前拦截器的afterCompletion方法才会执行。

统一异常处理

我们在实际项目中Dao层和Service层的异常都会被抛到Controller层。但是如果我们在Controller的方法中都加上异常的try...catch处理也会显的非常的繁琐。

所以SpringMVC为我们提供了统一异常处理方案。可以把Controller层的异常进行统一处理。这样既提高了代码的复用性也让异常处理代码和我们的业务代码解耦。

一种是实现HandlerExceptionResolver接口的方式,一种是使用@ControllerAdvice注解的方式。

HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolverSimpleMappingExceptionResolver

HandlerExceptionResolver

①实现接口

public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
​
}
​

②重写方法

public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    
    //如果handler中出现了异常,就会调用到该方法,我们可以在本方法中进行统一的异常处理。
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        //获取异常信息,把异常信息放入域对象中
        String msg = ex.getMessage();
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg",msg);
        //跳转到error.jsp
        modelAndView.setViewName("/WEB-INF/page/error.jsp");
        return modelAndView;
    }
}
​

③注入容器

可以使用注解注入也可以使用xml配置注入。这里使用注解注入的方式。在类上加 @Component注解,注意要保证类能被组件扫描扫描到。

@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    //....省略无关代码
}

@ControllerAdvice(重要)

①创建类加上@ControllerAdvice注解进行标识

@ControllerAdvice
public class MyControllerAdvice {
​
}

②定义异常处理方法

定义异常处理方法,使用 @ExceptionHandler标识可以处理的异常。

@ControllerAdvice
public class MyControllerAdvice {
​
    @ExceptionHandler({NullPointerException.class,ArithmeticException.class})
    public ModelAndView handlerException(Exception ex){
        //如果出现了相关的异常,就会调用该方法
        String msg = ex.getMessage();
        ModelAndView modelAndView = new ModelAndView();
        //把异常信息存入域中
        modelAndView.addObject("msg",msg);
        //跳转到error.jsp
        modelAndView.setViewName("/WEB-INF/page/error.jsp");
        return modelAndView;
    }
}

③注入容器

可以使用注解注入也可以使用xml配置注入。这里使用注解注入的方式。在类上加 @Component注解,注意要保证类能被组件扫描扫描到。

@ControllerAdvice
@Component
public class MyControllerAdvice {
    //省略无关代码
}

总结

我们在实际项目中一般会选择使用@ControllerAdvice 来进行异常的统一处理。

因为如果在前后端不分离的项目中,异常处理一般是跳转到错误页面,让用户有个更好的体验。而前后端分离的项目中,异常处理一般是把异常信息封装到Json中写入响应体。无论是哪种情况,使用@ControllerAdvice的写法都能比较方便的实现。

例如下面这种方式就是前后端分离的异常处理方案,把异常信息封装到对象中,转换成json写入响应体。

@ControllerAdvice
@Component
public class MyControllerAdvice {
​
    @ExceptionHandler({NullPointerException.class,ArithmeticException.class})
    @ResponseBody
    public Result handlerException(Exception ex){
        Result result = new Result();
        result.setMsg(ex.getMessage());
        result.setCode(500);
        return result;
    }
}
​