峰哥說技術系列-10 Spring Boot異常處理方案源碼解析與實踐


峰哥說技術系列-10 Spring Boot異常處理方案源碼解析與實踐

日前,教育部、國家發展改革委、財政部三部門近日聯合發佈《關於“雙一流”建設高校促進學科融合加快人工智能領域研究生培養的若干意見》,《意見》為廣大畢業生帶來利好消息,將把人工智能納入“國家關鍵領域急需高層次人才培養專項招生計劃”支持範圍,擴大研究生培養規模,計劃安排研究生尤其是博士生招生計劃專項增量,並將引導高校精準擴大人工智能相關學科高層次人才培養規模。


峰哥說技術系列-10 Spring Boot異常處理方案源碼解析與實踐

由此可見,國家對於IT人才的需求,那麼你進入到IT領域了嗎?

如果還在猶豫,就跟著峰哥一起來學習吧!


峰哥帶來的今日份主題

Spring Boot異常處理方案源碼解析與實踐

雖然我們可以@ControllerAdvice註解配置@ExceptionHandler來處理全局異常。但是也可以有自己的方案,在Spring Boot中對異常的處理有一些默認的策略,我們可以通過一個案例來看。

案例:構造一個工程,訪問http://localhost:8080/hello。在接口方法如下。

步驟:

01.創建包,編寫HelloController.代碼如下:

@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
int i=1/0;
return "hello,Spring boot!";
}


}

02.在瀏覽器中輸入:http://localhost:8080/hello.結果如下:


峰哥說技術系列-10 Spring Boot異常處理方案源碼解析與實踐

錯誤分析,明顯的可以看到當除數為零的時候出現了異常,自動映射到/error路徑,而在程序中沒有/error路徑。所以到了整個頁面。不過在 Spring Boot 中,提供 /error 路徑實際上是下下策,Spring Boot 本身在處理異常時,也是當所有條件都不滿足時,才會去找 /error 路徑。那麼我們就先來看看,在 Spring Boot 中,如何自定義 error 頁面,整體上來說,可以分為兩種,一種是靜態頁面,另一種是動態頁面。那麼該怎麼使用?相信經過這麼多次課程的學習,我們想到的一定是找源碼。

其實在Spring Boot中,有一個類ErrorMvcAutoConfiguration的配置類,在該類中我們首先看源碼中的靜態類DefaultErrorViewResolverConfiguration



@Configuration(
proxyBeanMethods = false
)
static class DefaultErrorViewResolverConfiguration {
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
DefaultErrorViewResolverConfiguration(ApplicationContext applicationContext, ResourceProperties resourceProperties) {
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
}
@Bean
@ConditionalOnBean({DispatcherServlet.class})
@ConditionalOnMissingBean({ErrorViewResolver.class})
DefaultErrorViewResolver conventionErrorViewResolver() {
return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
}
}



紅色字體部分的DefaultErrorViewResolver對象很顯然定義的默認的錯誤視圖解析器,那麼錯誤的視圖肯定跟這個解析器有關。下面研究這個類。在該類中有一個方法。



public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<string> model) {
ModelAndView modelAndView =this.resolve(String.valueOf(status.value()), model);
if (modelAndView == null &&SERIES_VIEWS.containsKey(status.series())) {
modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);


}
return modelAndView;
}/<string>



很顯然是來解析錯誤視圖的方法,如果去跟蹤status.series()方法,在這裡,首先以異常響應碼作為視圖名分別去查找動態頁面和靜態頁面,如果沒有查找到,則再以 4xx 或者 5xx 作為視圖名再去分別查找動態或者靜態頁面。然後觀察第2處紅色字體部分。我們發現有一段靜態代碼塊,

代碼如下:



static {

Map<series> views = new EnumMap(Series.class);
views.put(Series.CLIENT_ERROR, "4xx");
views.put(Series.SERVER_ERROR, "5xx");/<series>


SERIES_VIEWS = Collections.unmodifiableMap(views);
}



很顯然,動態錯誤視圖的名稱是4xx.html或者5xx.html。然後再跟進第2處紅色字體方法。

代碼如下:



private ModelAndView resolve(String viewName, Map<string> model) {
String errorViewName = "error/" + viewName;
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
return provider != null ? new ModelAndView(errorViewName, model) :this.resolveResource(errorViewName, model);
}/<string>



第1處紅色字體部分,很明顯說明視圖有前綴error,而且是固定格式。第2處紅色部分是解析資源的代碼。我們繼續跟進去。



private ModelAndView resolveResource(String viewName, Map<string> model) {
String[] var3 = this.resourceProperties.getStaticLocations();
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
try {
Resource resource = this.applicationContext.getResource(location);
resource = resource.createRelative(viewName + ".html");
if (resource.exists()) {
return new ModelAndView(new DefaultErrorViewResolver.HtmlResourceView(resource), model);
}
} catch (Exception var8) {
;
}
}
return null;
}/<string>



我們繼續追蹤第1處紅色字體,很容易就進入了ResourceProperties類中。可以看到它實際就是前面的靜態資源的位置。



private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};



那我們答案就呼之欲出了,我們定義的錯誤頁面就是放上面靜態資源的的路徑下面的error文件夾下面。而且它的擴展名必須是.html.

A.自定義靜態異常頁面

01.在static下面創建error文件夾,添加500.html







<title>Title/<title>


500錯誤頁





02.在templates下面創建error文件夾,添加500.html







<title>Title/<title>


templates-500錯誤頁





03.測試:在瀏覽器輸入http://localhost:8080/hello


峰哥說技術系列-10 Spring Boot異常處理方案源碼解析與實踐

很顯然使用的是static/error文件夾下面的頁面。刪除後,會使用templeates/error文件夾下面的頁面。大家可以自行測試即可。

B.自定義動態異常頁面

01.在static下面創建error文件夾,添加5xx.html







<title>Title/<title>


5xx錯誤頁





02.在templates下面創建error文件夾,添加5xx.html







<title>Title/<title>


templates-5xx錯誤頁





03

測試:將static/error文件夾下的500.html改成500-bak.html,在瀏覽器輸入http://localhost:8080/hello


峰哥說技術系列-10 Spring Boot異常處理方案源碼解析與實踐


發生了500錯誤-->查找動態 500.html 頁面-->查找靜態 500.html --> 查找動態 5xx.html-->查找靜態 5xx.html。



分享到:


相關文章: