日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
SpringMVC異常處理體系深入分析

SpringMVC 中針對(duì)異常問(wèn)題有一套完整的處理體系,這套體系非常好用,今天松哥就花點(diǎn)時(shí)間來(lái)和大家聊一聊 SpringMVC 中的異常處理體系,我們把 SpringMVC 中的異常體系從頭到尾梳理一下。

創(chuàng)新互聯(lián)公司專注于南召企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站,商城網(wǎng)站制作。南召網(wǎng)站建設(shè)公司,為南召等地區(qū)提供建站服務(wù)。全流程按需策劃設(shè)計(jì),專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務(wù)

1.異常解析器概覽

在 SpringMVC 的異常體系中,處于最頂層的大 Boss 是 HandlerExceptionResolver,這是一個(gè)接口,里邊只有一個(gè)方法:

 
 
 
 
  1. public interface HandlerExceptionResolver { 
  2.  @Nullable 
  3.  ModelAndView resolveException( 
  4.    HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex); 

resolveException 方法就用來(lái)解析請(qǐng)求處理過(guò)程中所產(chǎn)生的異常,并最終返回一個(gè) ModelAndView。

我們來(lái)看下 HandlerExceptionResolver 的實(shí)現(xiàn)類:

直接實(shí)現(xiàn) HandlerExceptionResolver 接口的類有三個(gè):

  • HandlerExceptionResolverComposite:這個(gè)一看又是一個(gè)組合,在最近的源碼分析中我們已經(jīng)多次見(jiàn)到 xxxComposite 了,這里就不再贅述。
  • DefaultErrorAttributes:這個(gè)用來(lái)保存異常屬性。
  • AbstractHandlerExceptionResolver:這個(gè)的子類比較多:
    • SimpleMappingExceptionResolver:通過(guò)提前配置好的異常類和 View 之間的對(duì)應(yīng)關(guān)系來(lái)解析異常。
    • AbstractHandlerMethodExceptionResolver:處理使用 @ExceptionHandler 注解自定義的異常類型。
    • DefaultHandlerExceptionResolver:按照不同類型來(lái)處理異常。
    • ResponseStatusExceptionResolver:處理含有 @ResponseStatus 注解的異常。

在 SpringMVC 中,大致的異常解析器就是這些,接下來(lái)我們來(lái)逐個(gè)學(xué)習(xí)這些異常解析器。

2.AbstractHandlerExceptionResolver

AbstractHandlerExceptionResolver 是真正干活的異常解析器的父類,我們就先從他的 resolveException 方法開(kāi)始看起。

 
 
 
 
  1. @Override 
  2. @Nullable 
  3. public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { 
  4.  if (shouldApplyTo(request, handler)) { 
  5.   prepareResponse(ex, response); 
  6.   ModelAndView result = doResolveException(request, response, handler, ex); 
  7.   if (result != null) { 
  8.    logException(ex, request); 
  9.   } 
  10.   return result; 
  11.  } 
  12.  else { 
  13.   return null; 
  14.  } 
  1. 首先調(diào)用 shouldApplyTo 方法判斷當(dāng)前解析器是否可以處理傳入的處理器所拋出的異常,如果不支持,則直接返回 null,這個(gè)異常將交給下一個(gè) HandlerExceptionResolver 去處理。
  2. 調(diào)用 prepareResponse 方法處理 response。
  3. 調(diào)用 doResolveException 方法實(shí)際處理異常,這是一個(gè)模版方法,具體的實(shí)現(xiàn)在子類中。
  4. 調(diào)用 logException 方法記錄異常日志信息。

記錄異常日志沒(méi)啥好說(shuō)的,doResolveException 則是一個(gè)空的模版方法,所以這里對(duì)我們來(lái)說(shuō)主要就是兩個(gè)方法:shouldApplyTo 和 prepareResponse,我們分別來(lái)看。

shouldApplyTo

 
 
 
 
  1. protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) { 
  2.  if (handler != null) { 
  3.   if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) { 
  4.    return true; 
  5.   } 
  6.   if (this.mappedHandlerClasses != null) { 
  7.    for (Class handlerClass : this.mappedHandlerClasses) { 
  8.     if (handlerClass.isInstance(handler)) { 
  9.      return true; 
  10.     } 
  11.    } 
  12.   } 
  13.  } 
  14.  return !hasHandlerMappings(); 

這里涉及到了兩個(gè)對(duì)象:mappedHandlers 和 mappedHandlerClasses:

  • mappedHandlers:存儲(chǔ)的是處理器對(duì)象(Controller 或者 Controller 中的方法)
  • mappedHandlerClasses:存儲(chǔ)的是處理器的 Class。

我們?cè)谂渲卯惓=馕銎鞯臅r(shí)候可以配置這兩個(gè)對(duì)象,進(jìn)而實(shí)現(xiàn)該異常處理器只為某一個(gè)處理器服務(wù),但是一般來(lái)說(shuō)沒(méi)這種需求,所以大家僅做了解即可。

如果開(kāi)發(fā)者一開(kāi)始配置了 mappedHandlers 或者 mappedHandlerClasses,則用這兩個(gè)和處理器去比較,否則就直接返回 true,表示支持該異常處理。

prepareResponse

prepareResponse 方法比較簡(jiǎn)單,主要是處理一下響應(yīng)頭的緩存字段。

 
 
 
 
  1. protected void prepareResponse(Exception ex, HttpServletResponse response) { 
  2.  if (this.preventResponseCaching) { 
  3.   preventCaching(response); 
  4.  } 
  5. protected void preventCaching(HttpServletResponse response) { 
  6.  response.addHeader(HEADER_CACHE_CONTROL, "no-store"); 

這是 AbstractHandlerExceptionResolver 的大致內(nèi)容,可以看到還是非常 easy 的,接下來(lái)我們來(lái)看它的實(shí)現(xiàn)類。

2.1 AbstractHandlerMethodExceptionResolver

AbstractHandlerMethodExceptionResolver 主要是重寫了 shouldApplyTo 方法和 doResolveException 方法,一個(gè)一個(gè)來(lái)看。

shouldApplyTo

 
 
 
 
  1. @Override 
  2. protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) { 
  3.  if (handler == null) { 
  4.   return super.shouldApplyTo(request, null); 
  5.  } 
  6.  else if (handler instanceof HandlerMethod) { 
  7.   HandlerMethod handlerMethod = (HandlerMethod) handler; 
  8.   handler = handlerMethod.getBean(); 
  9.   return super.shouldApplyTo(request, handler); 
  10.  } 
  11.  else if (hasGlobalExceptionHandlers() && hasHandlerMappings()) { 
  12.   return super.shouldApplyTo(request, handler); 
  13.  } 
  14.  else { 
  15.   return false; 
  16.  } 

這塊感覺(jué)沒(méi)啥好說(shuō)的,判斷邏輯基本上都還是調(diào)用父類的 shouldApplyTo 方法去處理。

doResolveException

 
 
 
 
  1. @Override 
  2. @Nullable 
  3. protected final ModelAndView doResolveException( 
  4.   HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { 
  5.  HandlerMethod handlerMethod = (handler instanceof HandlerMethod ? (HandlerMethod) handler : null); 
  6.  return doResolveHandlerMethodException(request, response, handlerMethod, ex); 
  7. @Nullable 
  8. protected abstract ModelAndView doResolveHandlerMethodException( 
  9.   HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception ex); 

doResolveException 是具體的異常處理方法,但是它里邊卻沒(méi)有實(shí)質(zhì)性操作,具體的事情交給 doResolveHandlerMethodException 方法去做了,而該方法是一個(gè)抽象方法,具體的實(shí)現(xiàn)在子類中。

2.1.1 ExceptionHandlerExceptionResolver

AbstractHandlerMethodExceptionResolver 只有一個(gè)子類就是 ExceptionHandlerExceptionResolver,來(lái)看下它的 doResolveHandlerMethodException 方法:

 
 
 
 
  1. @Override 
  2. @Nullable 
  3. protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, 
  4.   HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) { 
  5.  ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception); 
  6.  if (exceptionHandlerMethod == null) { 
  7.   return null; 
  8.  } 
  9.  if (this.argumentResolvers != null) { 
  10.   exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); 
  11.  } 
  12.  if (this.returnValueHandlers != null) { 
  13.   exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); 
  14.  } 
  15.  ServletWebRequest webRequest = new ServletWebRequest(request, response); 
  16.  ModelAndViewContainer mavContainer = new ModelAndViewContainer(); 
  17.  ArrayList exceptions = new ArrayList<>(); 
  18.  try { 
  19.   if (logger.isDebugEnabled()) { 
  20.    logger.debug("Using @ExceptionHandler " + exceptionHandlerMethod); 
  21.   } 
  22.   // Expose causes as provided arguments as well 
  23.   Throwable exToExpose = exception; 
  24.   while (exToExpose != null) { 
  25.    exceptions.add(exToExpose); 
  26.    Throwable cause = exToExpose.getCause(); 
  27.    exToExpose = (cause != exToExpose ? cause : null); 
  28.   } 
  29.   Object[] arguments = new Object[exceptions.size() + 1]; 
  30.   exceptions.toArray(arguments);  // efficient arraycopy call in ArrayList 
  31.   arguments[arguments.length - 1] = handlerMethod; 
  32.   exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments); 
  33.  } 
  34.  catch (Throwable invocationEx) { 
  35.   // Any other than the original exception (or a cause) is unintended here, 
  36.   // probably an accident (e.g. failed assertion or the like). 
  37.   if (!exceptions.contains(invocationEx) && logger.isWarnEnabled()) { 
  38.    logger.warn("Failure in @ExceptionHandler " + exceptionHandlerMethod, invocationEx); 
  39.   } 
  40.   // Continue with default processing of the original exception... 
  41.   return null; 
  42.  } 
  43.  if (mavContainer.isRequestHandled()) { 
  44.   return new ModelAndView(); 
  45.  } 
  46.  else { 
  47.   ModelMap model = mavContainer.getModel(); 
  48.   HttpStatus status = mavContainer.getStatus(); 
  49.   ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status); 
  50.   mav.setViewName(mavContainer.getViewName()); 
  51.   if (!mavContainer.isViewReference()) { 
  52.    mav.setView((View) mavContainer.getView()); 
  53.   } 
  54.   if (model instanceof RedirectAttributes) { 
  55.    Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); 
  56.    RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); 
  57.   } 
  58.   return mav; 
  59.  } 

這個(gè)方法雖然比較長(zhǎng),但是很好理解:

  1. 首先查找到帶有 @ExceptionHandler 注解的方法,封裝成一個(gè) ServletInvocableHandlerMethod 對(duì)象(關(guān)于 ServletInvocableHandlerMethod 對(duì)象,松哥在之前的文章中已經(jīng)介紹過(guò)了,具體參見(jiàn):Spring Boot 定義接口的方法是否可以聲明為 private?)。
  2. 如果找到了對(duì)應(yīng)的方法,則為 exceptionHandlerMethod 配置參數(shù)解析器、視圖解析器等,關(guān)于這些解析器,參考松哥之前的文章:SpringBoot 中如何自定義參數(shù)解析器?、深入分析 SpringMVC 參數(shù)解析器、Spring Boot 中如何統(tǒng)一 API 接口響應(yīng)格式?。
  3. 接下來(lái)定義一個(gè) exceptions 數(shù)組,如果發(fā)生的異常存在異常鏈,則將整個(gè)異常鏈存入 exceptions 數(shù)組中。
  4. exceptions 數(shù)組再加上 handlerMethod,共同組成方法參數(shù),調(diào)用 exceptionHandlerMethod.invokeAndHandle 完成自定義異常方法的執(zhí)行,執(zhí)行結(jié)果被保存再 mavContainer 中。
  5. 如果請(qǐng)求到此結(jié)束,則直接構(gòu)造一個(gè) ModelAndView 返回。
  6. 否則從 mavContainer 中取出各項(xiàng)信息,構(gòu)建新的 ModelAndView 返回。同時(shí),如果存在重定向參數(shù),也將之保存下來(lái)(關(guān)于重定向參數(shù),參見(jiàn):SpringMVC 中的參數(shù)還能這么傳遞?漲姿勢(shì)了!)。

這就是 ExceptionHandlerExceptionResolver 的大致工作流程,可以看到,還是非常 easy 的。

2.2 DefaultHandlerExceptionResolver

這個(gè)看名字就知道是一個(gè)默認(rèn)的異常處理器,用來(lái)處理一些常見(jiàn)的異常類型,我們來(lái)看一下它的 doResolveException 方法:

 
 
 
 
  1. @Override 
  2. @Nullable 
  3. protected ModelAndView doResolveException( 
  4.   HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { 
  5.  try { 
  6.   if (ex instanceof HttpRequestMethodNotSupportedException) { 
  7.    return handleHttpRequestMethodNotSupported( 
  8.      (HttpRequestMethodNotSupportedException) ex, request, response, handler); 
  9.   } 
  10.   else if (ex instanceof HttpMediaTypeNotSupportedException) { 
  11.    return handleHttpMediaTypeNotSupported( 
  12.      (HttpMediaTypeNotSupportedException) ex, request, response, handler); 
  13.   } 
  14.   else if (ex instanceof HttpMediaTypeNotAcceptableException) { 
  15.    return handleHttpMediaTypeNotAcceptable( 
  16.      (HttpMediaTypeNotAcceptableException) ex, request, response, handler); 
  17.   } 
  18.   else if (ex instanceof MissingPathVariableException) { 
  19.    return handleMissingPathVariable( 
  20.      (MissingPathVariableException) ex, request, response, handler); 
  21.   } 
  22.   else if (ex instanceof MissingServletRequestParameterException) { 
  23.    return handleMissingServletRequestParameter( 
  24.      (MissingServletRequestParameterException) ex, request, response, handler); 
  25.   } 
  26.   else if (ex instanceof ServletRequestBindingException) { 
  27.    return handleServletRequestBindingException( 
  28.      (ServletRequestBindingException) ex, request, response, handler); 
  29.   } 
  30.   else if (ex instanceof ConversionNotSupportedException) { 
  31.    return handleConversionNotSupported( 
  32.      (ConversionNotSupportedException) ex, request, response, handler); 
  33.   } 
  34.   else if (ex instanceof TypeMismatchException) { 
  35.    return handleTypeMismatch( 
  36.      (TypeMismatchException) ex, request, response, handler); 
  37.   } 
  38.   else if (ex instanceof HttpMessageNotReadableException) { 
  39.    return handleHttpMessageNotReadable( 
  40.      (HttpMessageNotReadableException) ex, request, response, handler); 
  41.   } 
  42.   else if (ex instanceof HttpMessageNotWritableException) { 
  43.    return handleHttpMessageNotWritable( 
  44.      (HttpMessageNotWritableException) ex, request, response, handler); 
  45.   } 
  46.   else if (ex instanceof MethodArgumentNotValidException) { 
  47.    return handleMethodArgumentNotValidException( 
  48.      (MethodArgumentNotValidException) ex, request, response, handler); 
  49.   } 
  50.   else if (ex instanceof MissingServletRequestPartException) { 
  51.    return handleMissingServletRequestPartException( 
  52.      (MissingServletRequestPartException) ex, request, response, handler); 
  53.   } 
  54.   else if (ex instanceof BindException) { 
  55.    return handleBindException((BindException) ex, request, response, handler); 
  56.   } 
  57.   else if (ex instanceof NoHandlerFoundException) { 
  58.    return handleNoHandlerFoundException( 
  59.      (NoHandlerFoundException) ex, request, response, handler); 
  60.   } 
  61.   else if (ex instanceof AsyncRequestTimeoutException) { 
  62.    return handleAsyncRequestTimeoutException( 
  63.      (AsyncRequestTimeoutException) ex, request, response, handler); 
  64.   } 
  65.  } 
  66.  catch (Exception handlerEx) { 
  67.  } 
  68.  return null; 

可以看到,這里實(shí)際上就是根據(jù)不同的異常類型,然后調(diào)用不同的類去處理該異常。這里相關(guān)的處理都比較容易,以 HttpRequestMethodNotSupportedException 為例,異常處理就是對(duì) response 對(duì)象做一些配置,如下:

 
 
 
 
  1. protected ModelAndView handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, 
  2.   HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException { 
  3.  String[] supportedMethods = ex.getSupportedMethods(); 
  4.  if (supportedMethods != null) { 
  5.   response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", ")); 
  6.  } 
  7.  response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ex.getMessage()); 
  8.  return new ModelAndView(); 

配置響應(yīng)頭,然后 sendError,最后返回一個(gè)空的 ModelAndView 對(duì)象。

其實(shí)這里哥哥異常處理方法都大同小異,松哥就不再贅述啦。

2.3 ResponseStatusExceptionResolver

這個(gè)用來(lái)處理 ResponseStatusException 類型的異常,或者使用了 @ResponseStatus 注解標(biāo)記的普通異常類。我們來(lái)看下它的 doResolveException 方法:

 
 
 
 
  1. @Override 
  2. @Nullable 
  3. protected ModelAndView doResolveException( 
  4.   HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { 
  5.  try { 
  6.   if (ex instanceof ResponseStatusException) { 
  7.    return resolveResponseStatusException((ResponseStatusException) ex, request, response, handler); 
  8.   } 
  9.   ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class); 
  10.   if (status != null) { 
  11.    return resolveResponseStatus(status, request, response, handler, ex); 
  12.   } 
  13.   if (ex.getCause() instanceof Exception) { 
  14.    return doResolveException(request, response, handler, (Exception) ex.getCause()); 
  15.   } 
  16.  } 
  17.  catch (Exception resolveEx) { 
  18.  } 
  19.  return null; 

可以看到,首先判斷異常類型是不是 ResponseStatusException,如果是,則直接調(diào)用 resolveResponseStatusException 方法進(jìn)行異常信息處理,如果不是,則去查找到異常類上的 @ResponseStatus 注解,并從中查找出相關(guān)的異常信息,然后調(diào)用 resolveResponseStatus 方法進(jìn)行處理。

可以看到,ResponseStatusExceptionResolver 處理的異常類型有兩種:

  • 直接繼承自 ResponseStatusException 的異常類,這種異常類可以直接從里邊提取出來(lái)想要的信息。
  • 通過(guò) @ResponseStatus 注解的普通異常類,這種情況下異常信息從 @ResponseStatus 注解中提取出來(lái)。

這個(gè)比較簡(jiǎn)單,沒(méi)啥好說(shuō)的。

2.4 SimpleMappingExceptionResolver

SimpleMappingExceptionResolver 則是根據(jù)不同的異常顯示不同的 error 頁(yè)面。可能有的小伙伴還沒(méi)用過(guò) SimpleMappingExceptionResolver,所以松哥這里先簡(jiǎn)單說(shuō)一下用法。

SimpleMappingExceptionResolver 的配置非常簡(jiǎn)單,直接提供一個(gè) SimpleMappingExceptionResolver 的實(shí)例即可,如下:

 
 
 
 
  1. @Bean 
  2. SimpleMappingExceptionResolver simpleMappingExceptionResolver() { 
  3.     SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver(); 
  4.     Properties mappings = new Properties(); 
  5.     mappings.put("java.lang.ArithmeticException", "11"); 
  6.     mappings.put("java.lang.NullPointerException", "22"); 
  7.     resolver.setExceptionMappings(mappings); 
  8.     Properties statusCodes = new Properties(); 
  9.     statusCodes.put("11", "500"); 
  10.     statusCodes.put("22", "500"); 
  11.     resolver.setStatusCodes(statusCodes); 
  12.     return resolver; 

在 mappings 中配置異常和 view 之間的對(duì)應(yīng)關(guān)系,要寫異常類的全路徑,后面的 11、22 則表示視圖名稱;statusCodes 中配置了視圖和響應(yīng)狀態(tài)碼之間的映射關(guān)系。配置完成后,如果我們的項(xiàng)目在運(yùn)行時(shí)拋出了 ArithmeticException 異常,則會(huì)展示出 11 視圖,如果我們的項(xiàng)目在運(yùn)行時(shí)拋出了 NullPointerException 異常,則會(huì)展示出 22 視圖。

這是用法,了解了用法之后我們?cè)賮?lái)看源碼,就容易理解了,我們直接來(lái)看 doResolveException 方法:

 
 
 
 
  1. @Override 
  2. @Nullable 
  3. protected ModelAndView doResolveException( 
  4.   HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { 
  5.  String viewName = determineViewName(ex, request); 
  6.  if (viewName != null) { 
  7.   Integer statusCode = determineStatusCode(request, viewName); 
  8.   if (statusCode != null) { 
  9.    applyStatusCodeIfPossible(request, response, statusCode); 
  10.   } 
  11.   return getModelAndView(viewName, ex, request); 
  12.  } 
  13.  else { 
  14.   return null; 
  15.  } 
  1. 首先調(diào)用 determineViewName 方法確定視圖的名稱。
  2. 接下來(lái)調(diào)用 determineStatusCode 查看視圖是否有對(duì)應(yīng)的 statusCode。
  3. 調(diào)用 applyStatusCodeIfPossible 方法將 statusCode 設(shè)置到 response 上,這個(gè)方法很簡(jiǎn)單,不多說(shuō)。
  4. 調(diào)用 getModelAndView 方法構(gòu)造一個(gè) ModelAndView 對(duì)象返回,在構(gòu)造時(shí),同時(shí)設(shè)置異常參數(shù),異常的信息的 key 默認(rèn)就是 exception。

在上面這個(gè)過(guò)程中,有兩個(gè)比較長(zhǎng)的方法,松哥這里需要和大家額外多說(shuō)兩句。

determineViewName

這個(gè)就是根據(jù)異常類型找到視圖名,我們來(lái)看下具體的查找方式:

 
 
 
 
  1. @Nullable 
  2. protected String determineViewName(Exception ex, HttpServletRequest request) { 
  3.  String viewName = null; 
  4.  if (this.excludedExceptions != null) { 
  5.   for (Class excludedEx : this.excludedExceptions) { 
  6.    if (excludedEx.equals(ex.getClass())) { 
  7.     return null; 
  8.    } 
  9.   } 
  10.  } 
  11.  if (this.exceptionMappings != null) { 
  12.   viewName = findMatchingViewName(this.exceptionMappings, ex); 
  13.  } 
  14.  if (viewName == null && this.defaultErrorView != null) { 
  15.   viewName = this.defaultErrorView; 
  16.  } 
  17.  return viewName; 
  1. 如果當(dāng)前異常包含在 excludedExceptions 中,則直接返回 null(意思是當(dāng)前異常被忽略處理了,直接按照默認(rèn)方式來(lái))。
  2. 如果 exceptionMappings 不為 null,則直接調(diào)用 findMatchingViewName 方法查找異常對(duì)應(yīng)的視圖名(exceptionMappings 變量就是前面我們配置的映射關(guān)系),具體的查找方式就是遍歷我們前面配置的映射表。
  3. 如果沒(méi)找到對(duì)應(yīng)的 viewName,并且用戶配置了 defaultErrorView,則將 defaultErrorView 賦值給 viewName,并將 viewName 返回。

determineStatusCode

 
 
 
 
  1. @Nullable 
  2. protected Integer determineStatusCode(HttpServletRequest request, String viewName) { 
  3.  if (this.statusCodes.containsKey(viewName)) { 
  4.   return this.statusCodes.get(viewName); 
  5.  } 
  6.  return this.defaultStatusCode; 

這個(gè)就比較容易,直接去 statusCodes 中查看是否有視圖對(duì)應(yīng)的狀態(tài)碼,如果有則直接返回,如果沒(méi)有,就返回一個(gè)默認(rèn)的。

3.HandlerExceptionResolverComposite

最后,還有一個(gè) HandlerExceptionResolverComposite 需要和大家介紹下,這是一個(gè)組合的異常處理器,用來(lái)代理哪些真正干活的異常處理器。

 
 
 
 
  1. @Override 
  2. @Nullable 
  3. public ModelAndView resolveException( 
  4.   HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { 
  5.  if (this.resolvers != null) { 
  6.   for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) { 
  7.    ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex); 
  8.    if (mav != null) { 
  9.     return mav; 
  10.    } 
  11.   } 
  12.  } 
  13.  return null; 

它的 resolveException 方法就比較簡(jiǎn)單了,這種寫法我們已經(jīng)見(jiàn)到過(guò)很多次了,不再贅述。

4.小結(jié)

好啦,今天就和大家簡(jiǎn)單聊一聊 SpringMVC 中的異常處理體系,整體來(lái)說(shuō)并不難,小伙伴們可以仔細(xì)品一品。

本文轉(zhuǎn)載自微信公眾號(hào)「江南一點(diǎn)雨」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系江南一點(diǎn)雨公眾號(hào)。


標(biāo)題名稱:SpringMVC異常處理體系深入分析
本文URL:http://www.5511xx.com/article/coiesio.html