官术网_书友最值得收藏!

4.5 自定義錯誤頁

4.4節向讀者介紹了Spring Boot中的全局異常處理。在處理異常時,開發者可以根據實際情況返回不同的頁面,但是這種異常處理方式一般用來處理應用級別的異常,有一些容器級別的錯誤就處理不了,例如Filter中拋出異常,使用@ControllerAdvice定義的全局異常處理機制就無法處理。因此,Spring Boot中對于異常的處理還有另外的方式,這就是本節要介紹的內容。

在Spring Boot中,默認情況下,如果用戶在發起請求時發生了404錯誤,Spring Boot會有一個默認的頁面展示給用戶,如圖4-10所示。

圖4-10

如果發起請求時發生了500錯誤,Spring Boot也會有一個默認的頁面展示給用戶,如圖4-11所示。

圖4-11

事實上,Spring Boot在返回錯誤信息時不一定返回HTML頁面,而是根據實際情況返回HTML頁面或者一段JSON(若開發者發起Ajax請求,則錯誤信息是一段JSON)。對于開發者而言,這一段HTML或者JSON都能夠自由定制。

Spring Boot中的錯誤默認是由BasicErrorController類來處理的,該類中的核心方法主要有兩個:

其中,errorHtml方法用來返回錯誤HTML頁面,error用來返回錯誤JSON,具體返回的是HTML還是JSON,則要看請求頭的Accept參數。返回JSON的邏輯很簡單,不必過多介紹,返回HTML的邏輯稍微有些復雜,在errorHtml方法中,通過調用resolveErrorView方法來獲取一個錯誤視圖的ModelAndView。而resolveErrorView方法的調用最終會來到DefaultErrorViewResolver類中。

DefaultErrorViewResolver類是Spring Boot中默認的錯誤信息視圖解析器,部分源碼如下:

從這一段源碼中可以看到,Spring Boot默認是在error目錄下查找4xx、5xx的文件作為錯誤視圖,當找不到時會回到errorHtml方法中,然后使用error作為默認的錯誤頁面視圖名,如果名為error的視圖也找不到,用戶就會看到本節一開始展示的兩個錯誤提示頁面。整個錯誤處理流程大致就是這樣的。

4.5.1 簡單配置

通過上面的介紹,讀者可能已經發現,要自定義錯誤頁面其實很簡單,提供4xx和5xx頁面即可。如果開發者不需要向用戶展示詳細的錯誤信息,那么可以把錯誤信息定義成靜態頁面,直接在resources/static目錄下創建error目錄,然后在error目錄中創建錯誤展示頁面。錯誤展示頁面的命名規則有兩種:一種是4xx.html、5xx.html;另一種是直接使用響應碼命名文件,例如404.html、405.html、500.html。第二種命名方式劃分得更細,當出錯時,不同的錯誤會展示不同的錯誤頁面,如圖4-12所示。

圖4-12

此時,當用戶訪問一個不存在的路徑時,就會展示404.html頁面中的內容,如圖4-13所示。

圖4-13

修改Controller,提供一個會拋異常的請求,代碼如下:

訪問該接口,就會展示500.html中的內容,如圖4-14所示。

圖4-14

這種定義都是使用了靜態HTML頁面,無法向用戶展示完整的錯誤信息,若采用視圖模板技術,則可以向用戶展示更多的錯誤信息。如果要使用HTML模板,那么先引入模板相關的依賴,這里以Thymeleaf為例,Thymeleaf頁面模板默認處于classpath:/templates/目錄下,因此在該目錄下先創建error目錄,再創建錯誤展示頁,如圖4-15所示。

圖4-15

由于模板頁面展示信息比較靈活,因此可以直接創建4xx.html、5xx.html。以4xx.html頁面為例,其內容如下:

Spring Boot在這里一共返回了5條錯誤相關的信息,分別是timestamp、status、error、message以及path。5xx.html頁面的內容與4xx.html頁面的內容一致。

此時,用戶訪問一個不存在的地址,4xx.html頁面中的內容將被展示出來,如圖4-16所示。

圖4-16

若用戶訪問一個會拋異常的地址,例如上文的/hello接口,則會展示5xx.html頁面的內容,如圖4-17所示。

圖4-17

注意

若用戶定義了多個錯誤頁面,則響應碼.html頁面的優先級高于4xx.html、5xx.html頁面的優先級,即若當前是一個404錯誤,則優先展示404.html而不是4xx.html;動態頁面的優先級高于靜態頁面,即若resources/templates和resources/static下同時定義了4xx.html,則優先展示resources/templates/4xx.html。

4.5.2 復雜配置

上面這種配置還是不夠靈活,只能定義HTML頁面,無法處理JSON的定制。Spring Boot中支持對Error信息的深度定制,接下來將從三個方面介紹深度定制:自定義Error數據、自定義Error視圖以及完全自定義。

1. 自定義Error數據

自定義Error數據就是對返回的數據進行自定義。經過4.5.1小節的介紹,讀者已經了解到Spring Boot返回的Error信息一共有5條,分別是timestamp、status、error、message以及path。在BasicErrorController的errorHtml方法和error方法中,都是通過getErrorAttributes方法獲取Error信息的。該方法最終會調用到DefaultErrorAttributes類的getErrorAttributes方法,而DefaultErrorAttributes類是在ErrorMvcAutoConfiguration中默認提供的。ErrorMvcAutoConfiguration類的errorAttributes方法源碼如下:

從這段源碼中可以看出,當系統沒有提供ErrorAttributes時才會采用DefaultErrorAttributes。因此自定義錯誤提示時,只需要自己提供一個ErrorAttributes即可,而DefaultErrorAttributes是ErrorAttributes的子類,因此只需要繼承DefaultErrorAttributes即可,代碼如下:

代碼解釋:


? 自定義MyErrorAttribute繼承自DefaultErrorAttributes,重寫DefaultErrorAttributes中的getErrorAttributes方法。MyErrorAttribute類添加@Component注解,該類將被注冊到Spring容器中。

? 第6、7行通過super.getErrorAttributes獲取Spring Boot默認提供的錯誤信息,然后在此基礎上添加Error信息或者移除Error信息。


此時,當系統拋出異常時,錯誤信息將被修改,以4.5.1節中的動態頁面模板404.html為例,修改404.html,代碼如下:

在第9~12行添加了custommsg屬性,此時訪問一個不存在的路徑,就能看到自定義的Error信息,并且可以看到默認的error被移除了,如圖4-18所示。

圖4-18

如果通過Postman等工具來發起這個請求,那么返回的JSON數據中也是如此,如圖4-19所示。

圖4-19

2. 自定義Error視圖

Error視圖是展示給用戶的頁面,在BasicErrorController的errorHtml方法中調用resolveErrorView方法獲取一個ModelAndView實例。resolveErrorView方法是由ErrorViewResolver提供的,通過ErrorMvcAutoConfiguration類的源碼可以看到Spring Boot默認采用的ErrorViewResolver是DefaultErrorViewResolver。ErrorMvcAutoConfiguration部分源碼如下:

從這一段源碼可以看到,如果用戶沒有定義ErrorViewResolver,那么默認使用的ErrorViewResolver是DefaultErrorViewResolver,正是在DefaultErrorViewResolver中配置了默認去error目錄下尋找4xx.html、5xx.html。因此,開發者想要自定義Error視圖,只需要提供自己的ErrorViewResolver即可,代碼如下:

代碼解釋:


? 自定義MyErrorViewResolver實現ErrorViewResolver接口并實現接口中的resolveErrorView方法,使用@Component注解將該類注冊到Spring容器中。

? 在resolveErrorView方法中,最后一個Map參數就是Spring Boot提供的默認的5條Error信息(可以按照前面自定義Error數據的步驟對這5條消息進行修改)。在resolveErrorView方法中,返回一個ModelAndView,在ModelAndView中設置Error視圖和Error數據。

? 理論上,開發者也可以通過實現ErrorViewResolver接口來實現Error數據的自定義,但是如果只是單純地想自定義Error數據,還是建議繼承DefaultErrorAttributes。


接下來在resources/templates目錄下提供errorPage.html視圖,內容如下:

在errorPage.html中,除了展示Spring Boot提供的5條Error信息外,也展示了開發者自定義的Error信息。此時,無論請求發生4xx的錯誤(如圖4-20所示)還是發生5xx的錯誤(如圖4-21所示),都會來到errorPage.html頁面。

圖4-20

圖4-21

3. 完全自定義

前面提到的兩種自定義方式都是對BasicErrorController類中的某個環節進行修補。查看Error自動化配置類ErrorMvcAutoConfiguration,讀者可以發現BasicErrorController本身只是一個默認的配置,相關源碼如下:

從這段源碼中可以看到,若開發者沒有提供自己的ErrorController,則Spring Boot提供BasicErrorController作為默認的ErrorController。因此,如果開發者需要更加靈活地對Error視圖和數據進行處理,那么只需要提供自己的ErrorController即可。提供自己的ErrorController有兩種方式:一種是實現ErrorController接口,另一種是直接繼承BasicErrorController。由于ErrorController接口只提供一個待實現的方法,而BasicErrorController已經實現了很多功能,因此這里選擇第二種方式,即通過繼承BasicErrorController來實現自己的ErrorController。具體定義如下:

代碼解釋:


? 自定義MyErrorController繼承自BasicErrorController并添加@Controller注解,將MyErrorController注冊到Spring MVC容器中。

? 由于BasicErrorController沒有無參構造方法,因此在創建BasicErrorController實例時需要傳遞參數,在MyErrorController的構造方法上添加@Autowired注解注入所需參數。

? 參考BasicErrorController中的實現,重寫errorHtml和error方法,對Error的視圖和數據進行充分的自定義。

最后,在resources/templates目錄下提供myErrorPage.html頁面作為視圖頁面,代碼如下:

訪問一個不存在的頁面,就可以看到自定義的錯誤提示了,如圖4-22所示。

圖4-22

如果通過Postman等工具發起這個請求,那么返回數據為一段JSON,如圖4-23所示。

圖4-23

Spring Boot中對異常的處理還是非常容易的,Spring Boot雖然提供了非常豐富的自動化配置方案,但是也允許開發者根據實際情況進行完全的自定義,開發者在使用過程中可以結合具體情況選擇合適的Error處理方案。

主站蜘蛛池模板: 将乐县| 舞阳县| 长海县| 文化| 铜陵市| 林芝县| 南漳县| 康乐县| 东乌珠穆沁旗| 佳木斯市| 九寨沟县| 和平区| 清苑县| 岳西县| 太仓市| 从化市| 濮阳县| 安丘市| 仁化县| 浙江省| 右玉县| 微博| 台湾省| 尼木县| 阳西县| 周宁县| 武乡县| 钟祥市| 平罗县| 南川市| 弋阳县| 凤山市| 烟台市| 顺昌县| 尉氏县| 静乐县| 弥勒县| 龙井市| 搜索| 毕节市| 明水县|