异常处理流程
进入视图解析流程,并渲染页面,发生异常时,参数mv
为空,传入捕获的异常dispatchException
处理handler
发生的异常,处理完成返回ModelAndView
① DefaultErrorAttributes
先来处理异常,把异常信息保存到request
域并返回null
(5)如果没有任何解析器能够处理当前异常,最终就会发送/error
请求,将保存的异常信息转发到/error
。BasicErrorController
专门来处理/error
请求,BasicErrorController
会遍历所有的ErrorViewResolver
解析错误视图,如果没有自定义的错误视图解析器,就会使用默认的DefaultErrorViewResolver
,会把响应码作为错误页的地址,模板引擎最终响应这个页面。
几种异常处理方式及原理
1.自定义错误页,error/404.html
、error/5xx.html
。有精确的错误状态码页面就匹配精确,没有就找 4xx.html
,如果都没有就触发白页
2.使用@ControllerAdvice
和@ExceptionHandler
处理全局异常,底层是ExceptionHandlerExceptionResolver
支持的
3.使用@ResponseStatus
和自定义异常。底层是 ResponseStatusExceptionResolver
,底层调用 response.sendError(statusCode, resolvedReason)
,Tomcat会收到一个error
。请求最后new
一个空的ModelAndView
返回,这样任何处理解析器都处理不了当前的异常,最终就会发送/error
请求,BasicErrorController
专门来处理/error
请求,适配4xx.html
或者5xx.html
页面
4.Spring底层的异常,如参数类型转换异常。底层是DefaultHandlerExceptionResolver
处理框架底层的异常,底层也是response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE)
,Tomcat会收到一个error
。请求最后new
一个空的ModelAndView
返回,这样任何处理解析器都处理不了当前的异常,最终就会发送/error
请求,BasicErrorController
专门来处理/error
请求,适配4xx.html
或者5xx.html
页面
protected ModelAndView doResolveException( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { try { if (ex instanceof HttpRequestMethodNotSupportedException) { return handleHttpRequestMethodNotSupported( (HttpRequestMethodNotSupportedException) ex, request, response, handler); } else if (ex instanceof HttpMediaTypeNotSupportedException) { return handleHttpMediaTypeNotSupported( (HttpMediaTypeNotSupportedException) ex, request, response, handler); } else if (ex instanceof HttpMediaTypeNotAcceptableException) { return handleHttpMediaTypeNotAcceptable( (HttpMediaTypeNotAcceptableException) ex, request, response, handler); } else if (ex instanceof MissingPathVariableException) { return handleMissingPathVariable( (MissingPathVariableException) ex, request, response, handler); } else if (ex instanceof MissingServletRequestParameterException) { return handleMissingServletRequestParameter( (MissingServletRequestParameterException) ex, request, response, handler); } else if (ex instanceof ServletRequestBindingException) { return handleServletRequestBindingException( (ServletRequestBindingException) ex, request, response, handler); } else if (ex instanceof ConversionNotSupportedException) { return handleConversionNotSupported( (ConversionNotSupportedException) ex, request, response, handler); } else if (ex instanceof TypeMismatchException) { return handleTypeMismatch( (TypeMismatchException) ex, request, response, handler); } else if (ex instanceof HttpMessageNotReadableException) { return handleHttpMessageNotReadable( (HttpMessageNotReadableException) ex, request, response, handler); } else if (ex instanceof HttpMessageNotWritableException) { return handleHttpMessageNotWritable( (HttpMessageNotWritableException) ex, request, response, handler); } else if (ex instanceof MethodArgumentNotValidException) { return handleMethodArgumentNotValidException( (MethodArgumentNotValidException) ex, request, response, handler); } else if (ex instanceof MissingServletRequestPartException) { return handleMissingServletRequestPartException( (MissingServletRequestPartException) ex, request, response, handler); } else if (ex instanceof BindException) { return handleBindException((BindException) ex, request, response, handler); } else if (ex instanceof NoHandlerFoundException) { return handleNoHandlerFoundException( (NoHandlerFoundException) ex, request, response, handler); } else if (ex instanceof AsyncRequestTimeoutException) { return handleAsyncRequestTimeoutException( (AsyncRequestTimeoutException) ex, request, res<strong style="color:transparent">本文来源gaodai#ma#com搞@@代~&码*网/</strong>ponse, handler); } } catch (Exception handlerEx) { if (logger.isWarnEnabled()) { logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", handlerEx); } } return null; }