您好,登錄后才能下訂單哦!
在 Spring Boot 項(xiàng)目中 ,異常統(tǒng)一處理,可以使用 Spring 中 @ControllerAdvice 來(lái)統(tǒng)一處理,也可以自己來(lái)定義異常處理方案。Spring Boot 中,對(duì)異常的處理有一些默認(rèn)的策略,我們分別來(lái)看。
默認(rèn)情況下,Spring Boot 中的異常頁(yè)面 是這樣的:
我們從這個(gè)異常提示中,也能看出來(lái),之所以用戶看到這個(gè)頁(yè)面,是因?yàn)殚_(kāi)發(fā)者沒(méi)有明確提供一個(gè) /error 路徑,如果開(kāi)發(fā)者提供了 /error 路徑 ,這個(gè)頁(yè)面就不會(huì)展示出來(lái),不過(guò)在 Spring Boot 中,提供 /error 路徑實(shí)際上是下下策,Spring Boot 本身在處理異常時(shí),也是當(dāng)所有條件都不滿足時(shí),才會(huì)去找 /error 路徑。那么我們就先來(lái)看看,在 Spring Boot 中,如何自定義 error 頁(yè)面,整體上來(lái)說(shuō),可以分為兩種,一種是靜態(tài)頁(yè)面,另一種是動(dòng)態(tài)頁(yè)面。
靜態(tài)異常頁(yè)面
自定義靜態(tài)異常頁(yè)面,又分為兩種,第一種 是使用 HTTP 響應(yīng)碼來(lái)命名頁(yè)面,例如 404.html、405.html、500.html ....,另一種就是直接定義一個(gè) 4xx.html,表示400-499 的狀態(tài)都顯示這個(gè)異常頁(yè)面,5xx.html 表示 500-599 的狀態(tài)顯示這個(gè)異常頁(yè)面。
默認(rèn)是在 classpath:/static/error/
路徑下定義相關(guān)頁(yè)面:
此時(shí),啟動(dòng)項(xiàng)目,如果項(xiàng)目拋出 500 請(qǐng)求錯(cuò)誤,就會(huì)自動(dòng)展示 500.html 這個(gè)頁(yè)面,發(fā)生 404 就會(huì)展示 404.html 頁(yè)面。如果異常展示頁(yè)面既存在 5xx.html,也存在 500.html ,此時(shí),發(fā)生500異常時(shí),優(yōu)先展示 500.html 頁(yè)面。
動(dòng)態(tài)異常頁(yè)面
動(dòng)態(tài)的異常頁(yè)面定義方式和靜態(tài)的基本 一致,可以采用的頁(yè)面模板有 jsp、freemarker、thymeleaf。動(dòng)態(tài)異常頁(yè)面,也支持 404.html 或者 4xx.html ,但是一般來(lái)說(shuō),由于動(dòng)態(tài)異常頁(yè)面可以直接展示異常詳細(xì)信息,所以就沒(méi)有必要挨個(gè)枚舉錯(cuò)誤了 ,直接定義 4xx.html(這里使用thymeleaf模板)或者 5xx.html 即可。
注意,動(dòng)態(tài)頁(yè)面模板,不需要開(kāi)發(fā)者自己去定義控制器,直接定義異常頁(yè)面即可 ,Spring Boot 中自帶的異常處理器會(huì)自動(dòng)查找到異常頁(yè)面。
頁(yè)面定義如下:
頁(yè)面內(nèi)容如下:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>5xx</h2> <table border="1"> <tr> <td>path</td> <td th:text="${path}"></td> </tr> <tr> <td>error</td> <td th:text="${error}"></td> </tr> <tr> <td>message</td> <td th:text="${message}"></td> </tr> <tr> <td>timestamp</td> <td th:text="${timestamp}"></td> </tr> <tr> <td>status</td> <td th:text="${status}"></td> </tr> </table> </body> </html>
默認(rèn)情況下,完整的異常信息就是這5條,展示 效果如下 :
如果動(dòng)態(tài)頁(yè)面和靜態(tài)頁(yè)面同時(shí)定義了異常處理頁(yè)面,例如 classpath:/static/error/404.html
和 classpath:/templates/error/404.html
同時(shí)存在時(shí),默認(rèn)使用動(dòng)態(tài)頁(yè)面。即完整的錯(cuò)誤頁(yè)面查找方式應(yīng)該是這樣:
發(fā)生了500錯(cuò)誤-->查找動(dòng)態(tài) 500.html 頁(yè)面-->查找靜態(tài) 500.html --> 查找動(dòng)態(tài) 5xx.html-->查找靜態(tài) 5xx.html。
自定義異常數(shù)據(jù)
默認(rèn)情況下,在Spring Boot 中,所有的異常數(shù)據(jù)其實(shí)就是上文所展示出來(lái)的5條數(shù)據(jù),這5條數(shù)據(jù)定義在 org.springframework.boot.web.reactive.error.DefaultErrorAttributes
類中,具體定義在 getErrorAttributes
方法中 :
@Override public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) { Map<String, Object> errorAttributes = new LinkedHashMap<>(); errorAttributes.put("timestamp", new Date()); errorAttributes.put("path", request.path()); Throwable error = getError(request); HttpStatus errorStatus = determineHttpStatus(error); errorAttributes.put("status", errorStatus.value()); errorAttributes.put("error", errorStatus.getReasonPhrase()); errorAttributes.put("message", determineMessage(error)); handleException(errorAttributes, determineException(error), includeStackTrace); return errorAttributes; }
DefaultErrorAttributes 類本身則是在org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration 異常自動(dòng)配置類中定義的,如果開(kāi)發(fā)者沒(méi)有自己提供一個(gè) ErrorAttributes 的實(shí)例的話,那么 Spring Boot 將自動(dòng)提供一個(gè)ErrorAttributes 的實(shí)例,也就是 DefaultErrorAttributes 。
基于此 ,開(kāi)發(fā)者自定義 ErrorAttributes 有兩種方式 :
具體定義如下:
@Component public class MyErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace); if ((Integer)map.get("status") == 500) { map.put("message", "服務(wù)器內(nèi)部錯(cuò)誤!"); } return map; } }
定義好的 ErrorAttributes 一定要注冊(cè)成一個(gè) Bean ,這樣,Spring Boot 就不會(huì)使用默認(rèn)的 DefaultErrorAttributes 了,運(yùn)行效果如下圖:
自定義異常視圖
異常視圖默認(rèn)就是前面所說(shuō)的靜態(tài)或者動(dòng)態(tài)頁(yè)面,這個(gè)也是可以自定義的,首先 ,默認(rèn)的異常視圖加載邏輯在 org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController 類的 errorHtml 方法中,這個(gè)方法用來(lái)返回異常頁(yè)面+數(shù)據(jù),還有另外一個(gè) error 方法,這個(gè)方法用來(lái)返回異常數(shù)據(jù)(如果是 ajax 請(qǐng)求,則該方法會(huì)被觸發(fā))。
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes( request, isIncludeStackTrace(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); }
在該方法中 ,首先會(huì)通過(guò) getErrorAttributes 方法去獲取異常數(shù)據(jù)(實(shí)際上會(huì)調(diào)用到 ErrorAttributes 的實(shí)例 的 getErrorAttributes 方法),然后調(diào)用 resolveErrorView 去創(chuàng)建一個(gè) ModelAndView ,如果這里創(chuàng)建失敗,那么用戶將會(huì)看到默認(rèn)的錯(cuò)誤提示頁(yè)面。
正常情況下, resolveErrorView 方法會(huì)來(lái)到 DefaultErrorViewResolver 類的 resolveErrorView 方法中:
@Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { ModelAndView modelAndView = resolve(String.valueOf(status.value()), model); if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) { modelAndView = resolve(SERIES_VIEWS.get(status.series()), model); } return modelAndView; }
在這里,首先以異常響應(yīng)碼作為視圖名分別去查找動(dòng)態(tài)頁(yè)面和靜態(tài)頁(yè)面,如果沒(méi)有查找到,則再以 4xx 或者 5xx 作為視圖名再去分別查找動(dòng)態(tài)或者靜態(tài)頁(yè)面。
要自定義異常視圖解析,也很容易 ,由于 DefaultErrorViewResolver 是在 ErrorMvcAutoConfiguration 類中提供的實(shí)例,即開(kāi)發(fā)者沒(méi)有提供相關(guān)實(shí)例時(shí),會(huì)使用默認(rèn)的 DefaultErrorViewResolver ,開(kāi)發(fā)者提供了自己的 ErrorViewResolver 實(shí)例后,默認(rèn)的配置就會(huì)失效,因此,自定義異常視圖,只需要提供 一個(gè) ErrorViewResolver 的實(shí)例即可:
@Component public class MyErrorViewResolver extends DefaultErrorViewResolver { public MyErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties) { super(applicationContext, resourceProperties); } @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { return new ModelAndView("/aaa/123", model); } }
實(shí)際上,開(kāi)發(fā)者也可以在這里定義異常數(shù)據(jù)(直接在 resolveErrorView 方法重新定義一個(gè) model ,將參數(shù)中的model 數(shù)據(jù)拷貝過(guò)去并修改,注意參數(shù)中的 model 類型為 UnmodifiableMap,即不可以直接修改),而不需要自定義MyErrorAttributes。定義完成后,提供一個(gè)名為123的視圖,如下圖:
如此之后,錯(cuò)誤試圖就算定義成功了。
總結(jié)
實(shí)際上也可以自定義異??刂破?BasicErrorController ,不過(guò)松哥覺(jué)得這樣太大動(dòng)干戈了,沒(méi)必要,前面幾種方式已經(jīng)可以滿足我們的大部分開(kāi)發(fā)需求了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。