在Spring MVC中,如果对异常不做任何处理,Spring MVC会将异常直接抛给容器。

例如下面的代码抛出了异常:

@GetMapping("e1")
public String exception() {int i = 1 / 0;return "exception";
}

浏览器页面上会显示500错误。

对异常的处理

@ExceptionHandler处理当前Controller的异常

@ExceptionHandler能对当前Controller中指定的异常进行处理,可以通过ModelAndView将异常信息传递给页面。

使用如下:

@GetMapping("e1")
public String exception() {int i = 1 / 0;return "exception";
}@ExceptionHandler(value = RuntimeException.class)
public ModelAndView handlerRuntimeException(Exception exception) {ModelAndView mv = new ModelAndView("error");mv.addObject("exception", exception);return mv;
}

@ExceptionHandler要注意异常的优先级,如果Controller中有如下的异常处理方法,那么还是会执行handlerArithmeticException()方法,因为ArithmeticException异常更加具体:

@ExceptionHandler(value = RuntimeException.class)
public ModelAndView handlerRuntimeException(Exception exception) {ModelAndView mv = new ModelAndView("error");mv.addObject("exception", exception);return mv;
}

@ControllerAdvice处理全局异常

@ExceptionHandler的作用域是当前Controller,如果想对全局的异常进行处理需要使用@ControllerAdvice。

使用如下:

@ControllerAdvice
public class ExceptionHandlerControllerAdvice {@ExceptionHandler(value = ArithmeticException.class)public ModelAndView handlerArithmeticException(Exception exception) {ModelAndView mv = new ModelAndView("error");mv.addObject("exception", exception);return mv;}}

如果Controller中使用了@ExceptionHandler处理异常,那么他的优先级比全局的异常处理高。

@ResponseStatus定制错误码和错误内容

可以使用@ResponseStatus加到异常类上,这样当这个异常抛出时,页面显示的是定制的错误消息。

异常类定义如下:

@ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "用户名和密码不匹配")
public class UsernameNotMatchPasswordException extends RuntimeException {}

在方法中抛出这个异常:

/*** 使用@ResponseStatus定义错误码和错误内容* @param i* @return*/
@GetMapping("e3")
public String exception3(int i) {if (13 == i) {throw new UsernameNotMatchPasswordException();}return "success";
}

页面显示的错误消息如下:

使用SimpleMappingExceptionResolver处理指定异常

注入SimpleMappingExceptionResolver,并指定要处理的异常与视图。

com.morris.spring.mvc.config.MVCConfig#extendHandlerExceptionResolvers

public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();Properties properties = new Properties();// 指定要处理的异常与视图properties.setProperty("java.lang.NullPointerException", "error");simpleMappingExceptionResolver.setExceptionMappings(properties);resolvers.add(simpleMappingExceptionResolver);}

在Controller中抛出指定的异常:

/*** 使用SimpleMappingExceptionResolver处理异常** @return*/
@GetMapping("e5")
public String exception5() {if(true) {throw new NullPointerException();}return "success";
}

这样就会跳到指定的视图error.jsp页面。

自定义HandlerExceptionResolver

如果觉得SpringMVC提供的异常处理不满足需求,可以实现HandlerExceptionResolver接口自定义异常处理。

package com.morris.spring.mvc.exception;import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class MyHandlerExceptionResolver extends AbstractHandlerExceptionResolver implements PriorityOrdered {@Overrideprotected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {if(ex instanceof ArrayIndexOutOfBoundsException) {ModelAndView mv = new ModelAndView("error");mv.addObject("exception", "MyHandlerExceptionResolver");return mv;}return null;}/*** 优先级设置高一点,否则会被@ControllerAdvice全局异常处理* @return*/@Overridepublic int getOrder() {return 1;}
}

总结:不管使用上面哪种异常处理方法,只能处理在请求到达了DispatcherServlet,并且出现了异常后进入processDispatchResult()方法。

下面的这两种异常场景不适用:

  1. 请求没有到达DispatcherServlet的核心流程,如在filter中抛出异常。
  2. 请求进入processDispatchResult()方法处理异常,但是在处理过程中有抛出了异常,如在@ControllerAdvice方法中抛出了异常。

源码分析

HandlerExceptionResolverComposite的调用过程

在处理controller的返回结果时,发现有异常就会调用异常处理的逻辑:

org.springframework.web.servlet.DispatcherServlet#processDispatchResult

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {boolean errorView = false;if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);mv = ((ModelAndViewDefiningException) exception).getModelAndView();}else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);// 异常处理mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}
... ...

org.springframework.web.servlet.DispatcherServlet#processHandlerException

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,@Nullable Object handler, Exception ex) throws Exception {// Success and error responses may use different content typesrequest.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);// Check registered HandlerExceptionResolvers...ModelAndView exMv = null;if (this.handlerExceptionResolvers != null) {/*** handlerExceptionResolvers什么时候初始化的?* @see DispatcherServlet#initHandlerExceptionResolvers(org.springframework.context.ApplicationContext)** @see AbstractHandlerExceptionResolver#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)* @see HandlerExceptionResolverComposite#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)*/for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {exMv = resolver.resolveException(request, response, handler, ex);if (exMv != null) {break;}}}if (exMv != null) {if (exMv.isEmpty()) {request.setAttribute(EXCEPTION_ATTRIBUTE, ex);return null;}// We might still need view name translation for a plain error model...if (!exMv.hasView()) {String defaultViewName = getDefaultViewName(request);if (defaultViewName != null) {exMv.setViewName(defaultViewName);}}if (logger.isTraceEnabled()) {logger.trace("Using resolved error view: " + exMv, ex);}else if (logger.isDebugEnabled()) {logger.debug("Using resolved error view: " + exMv);}WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());return exMv;}throw ex;
}

handlerExceptionResolvers何时被初始化的?

org.springframework.web.servlet.DispatcherServlet#initHandlerExceptionResolvers

private void initHandlerExceptionResolvers(ApplicationContext context) {this.handlerExceptionResolvers = null;if (this.detectAllHandlerExceptionResolvers) {/*** HandlerExceptionResolver在WebMvcConfigurationSupport中注入了*/// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());// We keep HandlerExceptionResolvers in sorted order.AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);}}else {try {HandlerExceptionResolver her =context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);this.handlerExceptionResolvers = Collections.singletonList(her);}catch (NoSuchBeanDefinitionException ex) {// Ignore, no HandlerExceptionResolver is fine too.}}// Ensure we have at least some HandlerExceptionResolvers, by registering// default HandlerExceptionResolvers if no other resolvers are found.if (this.handlerExceptionResolvers == null) {// 默认ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolverthis.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}
}

handlerExceptionResolvers是从在SpringMVC容器中获取所有的HandlerExceptionResolver实例,那么这些实例是什么时候注入的呢?

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#handlerExceptionResolver

@Bean
public HandlerExceptionResolver handlerExceptionResolver(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();configureHandlerExceptionResolvers(exceptionResolvers);if (exceptionResolvers.isEmpty()) {// 添加默认的HandlerExceptionResolveraddDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);}extendHandlerExceptionResolvers(exceptionResolvers);HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();composite.setOrder(0);composite.setExceptionResolvers(exceptionResolvers);return composite;
}protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers,ContentNegotiationManager mvcContentNegotiationManager) {// 添加ExceptionHandlerExceptionResolverExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);exceptionHandlerResolver.setMessageConverters(getMessageConverters());exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());if (jackson2Present) {exceptionHandlerResolver.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));}if (this.applicationContext != null) {exceptionHandlerResolver.setApplicationContext(this.applicationContext);}exceptionHandlerResolver.afterPropertiesSet();exceptionResolvers.add(exceptionHandlerResolver);// 添加ResponseStatusExceptionResolverResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();responseStatusResolver.setMessageSource(this.applicationContext);exceptionResolvers.add(responseStatusResolver);// 添加DefaultHandlerExceptionResolverexceptionResolvers.add(new DefaultHandlerExceptionResolver());
}

默认注册了三个HandlerExceptionResolver:

  • ExceptionHandlerExceptionResolver
  • ResponseStatusExceptionResolver
  • DefaultHandlerExceptionResolver

我们可以通过实现WebMvcConfigurer接口extendHandlerExceptionResolvers()方法注入自己的HandlerExceptionResolver,也可以通过向SpringMVC容器中注入HandlerExceptionResolver实例。

最后ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver以及通过实现WebMvcConfigurer接口的extendHandlerExceptionResolvers()方法注入的HandlerExceptionResolver都会包装到HandlerExceptionResolverComposite中。

最后异常处理都会调用HandlerExceptionResolverComposite#resolveException

org.springframework.web.servlet.handler.HandlerExceptionResolverComposite#resolveException

public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {if (this.resolvers != null) {for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {/*** @see AbstractHandlerExceptionResolver#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)*/ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);if (mav != null) {return mav;}}}return null;
}

然后会调用各个HandlerExceptionResolver的doResolveException()进行异常处理。

org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#resolveException

public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {if (shouldApplyTo(request, handler)) {prepareResponse(ex, response);/*** @see DefaultHandlerExceptionResolver#doResolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)* @see ResponseStatusExceptionResolver#doResolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)* @see SimpleMappingExceptionResolver#doResolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)* @see AbstractHandlerMethodExceptionResolver#doResolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)**/// 让所有的ExceptionResolver按顺序挨个处理,有视图返回就救赎ModelAndView result = doResolveException(request, response, handler, ex);if (result != null) {// Print debug message when warn logger is not enabled.if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));}// Explicitly configured warn logger in logException method.logException(ex, request);}return result;}else {return null;}
}

ExceptionHandlerExceptionResolver

ExceptionHandlerExceptionResolver从名字就可以看出是处理@ExceptionHandler注解的。

首先看下ExceptionHandlerExceptionResolver的afterPropertiesSet方法,主要解析@ControllerAdvice注解的类中的带有@ExceptionHandler的方法,建议异常与方法之间的映射关系,注意这里只解析了@ControllerAdvice注解的类中的带有@ExceptionHandler注解的方法,并没有解析Controller中带有ExceptionHandler注解的方法。

org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#afterPropertiesSet

public void afterPropertiesSet() {// Do this first, it may add ResponseBodyAdvice beans// 解析带有@ControllerAdvice注解的类initExceptionHandlerAdviceCache();if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}
}private void initExceptionHandlerAdviceCache() {if (getApplicationContext() == null) {return;}// 从容器中查找所有带有ControllerAdvice注解的类List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());for (ControllerAdviceBean adviceBean : adviceBeans) {Class<?> beanType = adviceBean.getBeanType();if (beanType == null) {throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);}// 解析类中带有@ExceptionHandler的方法ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);if (resolver.hasExceptionMappings()) {this.exceptionHandlerAdviceCache.put(adviceBean, resolver);}if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {this.responseBodyAdvice.add(adviceBean);}}if (logger.isDebugEnabled()) {int handlerSize = this.exceptionHandlerAdviceCache.size();int adviceSize = this.responseBodyAdvice.size();if (handlerSize == 0 && adviceSize == 0) {logger.debug("ControllerAdvice beans: none");}else {logger.debug("ControllerAdvice beans: " +handlerSize + " @ExceptionHandler, " + adviceSize + " ResponseBodyAdvice");}}
}

ExceptionHandlerExceptionResolver对异常的处理就是找到@ExceptionHandler注解的方法,并进行反射调用。

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {// 不管是Controller中的@ExceptionHandler,还是ControllerAdvice中的@ExceptionHandler// 最终异常的处理都是要找到带有@ExceptionHandler注解的方法进行调用ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);if (exceptionHandlerMethod == null) {return null;}if (this.argumentResolvers != null) {exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);}if (this.returnValueHandlers != null) {exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);}ServletWebRequest webRequest = new ServletWebRequest(request, response);ModelAndViewContainer mavContainer = new ModelAndViewContainer();try {if (logger.isDebugEnabled()) {logger.debug("Using @ExceptionHandler " + exceptionHandlerMethod);}Throwable cause = exception.getCause();if (cause != null) {// Expose cause as provided argument as wellexceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);}else {// Otherwise, just the given exception as-isexceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);}}catch (Throwable invocationEx) {// Any other than the original exception (or its cause) is unintended here,// probably an accident (e.g. failed assertion or the like).if (invocationEx != exception && invocationEx != exception.getCause() && logger.isWarnEnabled()) {logger.warn("Failure in @ExceptionHandler " + exceptionHandlerMethod, invocationEx);}// Continue with default processing of the original exception...return null;}if (mavContainer.isRequestHandled()) {return new ModelAndView();}else {ModelMap model = mavContainer.getModel();HttpStatus status = mavContainer.getStatus();ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status);mav.setViewName(mavContainer.getViewName());if (!mavContainer.isViewReference()) {mav.setView((View) mavContainer.getView());}if (model instanceof RedirectAttributes) {Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);}return mav;}
}@Nullable
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(@Nullable HandlerMethod handlerMethod, Exception exception) {Class<?> handlerType = null;if (handlerMethod != null) {// Local exception handler methods on the controller class itself.// To be invoked through the proxy, even in case of an interface-based proxy.handlerType = handlerMethod.getBeanType();ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);if (resolver == null) {// 解析controller中带有@ExceptionHandler注解的方法resolver = new ExceptionHandlerMethodResolver(handlerType);this.exceptionHandlerCache.put(handlerType, resolver);}// 根据异常找到@ExceptionHandler注解的方法Method method = resolver.resolveMethod(exception);if (method != null) {return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);}// For advice applicability check below (involving base packages, assignable types// and annotation presence), use target class instead of interface-based proxy.if (Proxy.isProxyClass(handlerType)) {handlerType = AopUtils.getTargetClass(handlerMethod.getBean());}}// 这里@ControllerAdvice全局异常的处理// exceptionHandlerAdviceCache属性在afterProperties()方法中初始化for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {ControllerAdviceBean advice = entry.getKey();if (advice.isApplicableToBeanType(handlerType)) {ExceptionHandlerMethodResolver resolver = entry.getValue();// 根据异常找到@ExceptionHandler注解的方法Method method = resolver.resolveMethod(exception);if (method != null) {return new ServletInvocableHandlerMethod(advice.resolveBean(), method);}}}return null;
}

ResponseStatusExceptionResolver

ResponseStatusExceptionResolver主要是要拿到异常类上面的@ResponseStatus注解,然后将response的状态和内容设置为@ResponseStatus注解中的内容。

org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#doResolveException

protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {try {if (ex instanceof ResponseStatusException) {return resolveResponseStatusException((ResponseStatusException) ex, request, response, handler);}// 拿到异常上面的@ResponseStatus注解ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);if (status != null) {// 设置错误码和错误内容return resolveResponseStatus(status, request, response, handler, ex);}if (ex.getCause() instanceof Exception) {return doResolveException(request, response, handler, (Exception) ex.getCause());}}catch (Exception resolveEx) {if (logger.isWarnEnabled()) {logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", resolveEx);}}return null;
}

DefaultHandlerExceptionResolver

DefaultHandlerExceptionResolver是用来处理spring mvc内部异常,如HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException等异常。

protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {// 处理spring内部异常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, response, handler);}}catch (Exception handlerEx) {if (logger.isWarnEnabled()) {logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", handlerEx);}}return null;
}

SimpleMappingExceptionResolver

我们在构造SimpleMappingExceptionResolver时就会指定异常与视图的映射关系,在处理异常时只需要在映射map中获取即可。

protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {// Expose ModelAndView for chosen error view.// 将异常与属性exceptionMappings、excludedExceptions进行匹配,拿到视图名称String viewName = determineViewName(ex, request);if (viewName != null) {// Apply HTTP status code for error views, if specified.// Only apply it if we're processing a top-level request.Integer statusCode = determineStatusCode(request, viewName);if (statusCode != null) {applyStatusCodeIfPossible(request, response, statusCode);}return getModelAndView(viewName, ex, request);}else {return null;}
}protected String determineViewName(Exception ex, HttpServletRequest request) {String viewName = null;if (this.excludedExceptions != null) {// 与传入的异常的类型进行匹配for (Class<?> excludedEx : this.excludedExceptions) {if (excludedEx.equals(ex.getClass())) {return null;}}}// Check for specific exception mappings.if (this.exceptionMappings != null) {// 与传入的异常的名字进行匹配viewName = findMatchingViewName(this.exceptionMappings, ex);}// Return default error view else, if defined.if (viewName == null && this.defaultErrorView != null) {if (logger.isDebugEnabled()) {logger.debug("Resolving to default view '" + this.defaultErrorView + "'");}viewName = this.defaultErrorView;}return viewName;
}

【springmvc】九大组件之HandlerExceptionResolver相关推荐

  1. springMVC九大组件及一次请求流程

    一.九大组件 HandlerMapping(处理器映射器) HandlerMapping 是⽤来查找Handler的,也就是处理器,具体的表现形式可以是类,也可以是⽅法.⽐如,标注了@RequestM ...

  2. springmvc十六:九大组件

    DispatcherServlet中有九个引用类型的属性,这就是springmvc的九大组件. springmvc在工作的时候,关键位置都是由这些组件完成的. /** MultipartResolve ...

  3. Openstack九大组件

    云是服务 云,本身没有资源,只是去管理和调度资源 虚拟化是技术 虚拟化提供资源,在云的世界里,虚拟化提供底层的计算.存储.网络资源,由云来接管 云的五大特征: 按需自助服务 广泛的网络接入 资源池化 ...

  4. 一个字稳,云原生产品家族支撑冬奥会九大业务场景,打造云上奥运新体验

    北京冬奥会已经成为收视最高的一届冬奥会,在转播时长.技术.内容制作方式等多方面都书写了新记录.云技术的应用,是本届北京冬奥会赛事转播的一大特色. 而云原生作为云计算的新界面,如何稳定支撑北京冬奥会多个 ...

  5. 避免踩坑:易盾安全老司机起底Android九大漏洞,附解决建议

    Android应用会遇到各种各样的漏洞,如何从细节上了解各种安全隐患,积极采取适当的防御措施便变得尤为重要.为了让大家对Android漏洞有一个非常全面的认识,网易云易盾资深安全工程师徐从祥为大家详细 ...

  6. 《微服务》九大特性重读笔记

    今天重读了Martin Fowler的<Microservices>,在此记录一下对九大特性的理解. 服务组件化 组件,是一个可以独立更换和升级的单元.就像PC中的CPU.内存.显卡.硬盘 ...

  7. Linux 系统日常运维九大技能和运维网络知识总结

    一.Linux 系统日常运维九大技能 1.安装部署 方式:U盘,光盘和网络安装 其中网络安装已经成为了目前批量部署的首选方式:主要工具有Cobbler和PXE+kickstart 可以参考如下链接内容 ...

  8. 未来中国智能制造九大趋势

    智能制造(Intelligent Manufacturing,IM)是一种由智能机器和人类专家共同组成的人机一体化智能系统,它在制造过程中能进行智能活动,诸如分析.推理.判断.构思和决策等.它包含智能 ...

  9. 专题 | 项目管理知识、方法论、工具NO.9:你应该知道的项目管理的五个过程组和九大知识领域

    我们都想做一个优秀的项目经理,但是很多项目经理常陷入问题的泥淖中出不来.计划有问题.人员能力不足.进度赶不上.质量不达标.客户不满意,项目开始不到一个月,项目经理被各种问题缠的透不过气来,自己乱了阵脚 ...

最新文章

  1. 三态门有一个信号控制端en_W25Q32JVSSIQ|哪些PCB设计会影响信号质量?
  2. linux创建隐藏进程6,在Linux 2.6内核下实现进程隐藏
  3. 互联网性能与容量评估的方法论和典型案例
  4. leetcode 上的Counting Bits 总结
  5. 灵魂拷问:你和大佬,技术差距有多大?
  6. TCP三次握手及四次挥手详细图解(转)
  7. Qt工作笔记-使用QGraphicsItem绘制复杂的图形
  8. linux 系统内如何查看当前CPU详细信息
  9. php token 表单重复提交,PHP生成token防止表单重复提交2个例子
  10. Combobox绑定数据源DataSet
  11. Mybatis与JDBC的对比超详细笔记
  12. 如何用axure绘制图表_用Python绘制手绘风格的图表
  13. 比Google Map更加清晰的网络地图——RealBird
  14. ant组件中select默认选中某一项
  15. Aurora使用教程 第一讲
  16. Android使用Github Actions持续集成并自动上传apk到蒲公英App内测分发平台(含证书密码脱敏)
  17. 微信小程序项目实例——食堂吃哪个
  18. define和sbit的区别
  19. 【Mac 教程系列第 16 篇】如何查看 Apple 产品的真伪
  20. 抖音影视解说制作,一般用什么必备工具?

热门文章

  1. apk包反编译,签名
  2. PHP 5.6.6 上运行 ecshop 2.7.3 不兼容问题整合
  3. BQ25504芯片解析
  4. 企业如何与客户建立良好的客户关系
  5. 计算机系统——buflab
  6. 竟成408计算机考研辅导书介绍
  7. 基于88E6095的链路冗余协议开发(四)
  8. OpenWRT安装及配置
  9. Linux安装informatica报错ld-linux-x86-64.so.2+0x14d70
  10. 华工大学计算机基础题库,华工大学计算机基础操作练习题.docx