spring mvc 异常处理机制和统一异常处理

1、异常处理机制

Spring MVC 是经过 HandlerExceptionResolver 处理程序的异常,包括请求映射、数据绑定以及处理器执行时发生的异常html

一、HandlerExceptionResolver

HandlerExceptionResolver 只有一个接口方法java

public interface HandlerExceptionResolver {

    ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}

resolveException 方法尝试解决在处理程序执行期间引起的异常,处理以后返回 ModelAndView,转到对应的视图做为异常报告反馈给用户web

下面是可用的 HandlerExceptionResolver 实现:ajax

HandlerExceptionResolver 描述
SimpleMappingExceptionResolver 异常类名称和错误视图名称之间的映射,用于在浏览器应用程序中呈现错误页面
DefaultHandlerExceptionResolver 解决Spring MVC引起的异常,并将它们映射到HTTP状态代码
ResponseStatusExceptionResolver 使用@ResponseStatus注解解析异常,并根据注解中的值将它们映射到 HTTP 状态代码
ExceptionHandlerExceptionResolver 经过调用或类中的 @ExceptionHandler 方法来解决异常

Spring MVC 默认注册了这些内置异常解析器,用于支持 @ResponseStatus 注释异常和@ExceptionHandler方法spring

二、异常解析链

spring mvc 异常处理类结构图
spring mvc 异常处理类结构浏览器

上图咱们能够看到 AbstractHandlerExceptionResolver 实现了 Ordered 接口,这样造成了一个异常处理链,DispatcherServlet 把异常委托给 HandlerExceptionResolver 解析链以解决异常并提供替代处理。这个与视图解析器是类似的。mvc

能够经过HandlerExceptionResolver 在Spring配置中声明多个bean并根据须要设置 order 属性来造成异常解析链。order 的值越高,异常解析器定位的越晚。app

HandlerExceptionResolver 有三种返回状况:url

  • 处理后返回 ModelAndView 指向错误视图spa

  • 若是异常在解析器中已经处理完,则返回空的 ModelAndView

  • 返回 null,代表异常仍未解决,则由后续解析器继续处理,若是异常最后还在,则容许冒泡到Servlet容器

2、异常处理

  • 直接实现 HandlerExceptionResolver
  • 使用@ExceptionHandler注解
  • @ControllerAdvice+@ExceptionHandler

一、使用@ExceptionHandler注解

@ExceptionHandler 方法是在 @Controller 和 @ControllerAdvice 类中定义的,用来处理来自控制器方法的异常

若是 @ExceptionHandler 方法是在控制器内部定义的,那么它会接收并处理由控制器(或其任何子类)中的 @RequestMapping 方法抛出的异常;若是是定义在 @ControllerAdvice 类中,那么它会处理相关控制器中抛出的异常

@Controller
public class SimpleController {

    // ...

    @ExceptionHandler
    public ResponseEntity<String> handle(IOException ex) {
        // ...
    }
}

@ExceptionHandler方法的方法参数和返回值能够很灵活。好比,在Servlet环境下方法能够接收HttpServletRequest参数。返回值能够是String类型(会被解析为视图名)、能够是ModelAndView类型的对象,也能够是ResponseEntity

@Controller
public class SimpleController {

    @ExceptionHandler(RuntimeException.class)
    public ModelAndView error(RuntimeException error, HttpServletRequest request) {
        ModelAndView mav = new ModelAndView();
        mav.setViewName("error");
        mav.addObject("param", "Runtime error");
        return mav;
    }

    @ExceptionHandler()
    public ModelAndView error(Exception error, HttpServletRequest request, HttpServletResponse response) {
        ModelAndView mav = new ModelAndView();
        mav.setViewName("error");
        mav.addObject("param", "Exception error");
        return mav;
    }
}

@ExceptionHandler 只能处理同一个 Controller 里的异常,想要设置全局的异常处理,可把 @ExceptionHandler 方法写在一个 BaseController 里面,让其余 Controller 继承它。另外还可使用 @ControllerAdvice+@ExceptionHandler

二、@ControllerAdvice+@ExceptionHandler

这里咱们使用 @RestControllerAdvice ,至关于 @ControllerAdvice@ResponseBody

同时处理 web 和 ajax 异常

@RestControllerAdvice
public class ExceptionHandle {

    @ExceptionHandler
    public Object handle(HttpServletRequest request, HttpServletResponse response,Exception e){
        if(request.getHeader("X-Requested-With")!=null
            &&"XMLHttpRequest".equals(request.getHeader("X-Requested-With").toString())){
            return JSONResult.error(e.getMessage());
        }else{
            ModelAndView mv = new ModelAndView();
            mv.addObject("exception",e);
            mv.addObject("url",request.getRequestURL());
            mv.setViewName("/error");
            return mv;
        }
    }
}

3、容器错误页面

若是异常最后未被任何 HandlerExceptionResolver 解决,而且所以将其传播或者若是响应状态设置为错误状态(即4xx,5xx),则Servlet容器能够在HTML中呈现默认错误页面。能够在 web.xml 中声明错误页面映射

web.xml

<error-page>
    <location>/error</location>
</error-page>
<error-page>
   <error-code>404</error-code>
   <location>/resources/error/404.html</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/resources/error/500.html</location>
</error-page>
相关文章
相关标签/搜索