SpringBoot-定製錯誤頁面
錯誤頁面
1. 檔案路徑
classpath:templates/error
:模板存放地址
classpath:static/error
:靜態頁面存放地址
- 無需額外配置,Spring-Boot自動識別
- 檔名error,沒有需要手動建立
spring.server.error.path
配置可以替換error
,看情況配置- 優先採用模板,沒有再找靜態資料夾
2. 檔案格式
- 指定錯誤頁
# 404跳轉頁面
404.html
# 500跳轉頁面
500.html
檔名格式:
code
.html
- 預設錯誤頁
# 4XX錯誤統一錯誤頁面
4xx.html
# 5xx錯誤統一頁面
5xx.html
- 有詳細錯誤頁面404.html,優先採用詳細錯誤頁面,沒有則採用4xx.html
- 40x.html之類的沒試過,可以看看行不行
3. 自動路由
存在錯誤頁面就行了,多餘的不需要再進行配置,能夠直接生效。
4. 模板渲染
-
靜態頁面
不論是
classpath:static
或者classpath:templates
都能夠被系統對映並利用。 -
模板渲染
但是系統為模板注入了幾個錯誤的顯示資訊:
timestamp
:時間戳status
:狀態碼error
:錯誤資訊exception
:異常物件message
:提示資訊errors
:JSR303
當採用模板編寫錯誤頁面時,可以直接引入這些已經注入的錯誤資訊。
但是如果錯誤頁面在
classpath:static
靜態資料夾下的話,是取不到這些資訊的。
5. 預設提示
如果都沒有配置,那就是Spring-Boot自己的預設提示頁了。
錯誤資料
1. 自定義異常
public class MyException extends Exception{
public MyException(){
super("MyException");
}
}
2. json輸出
@ControllerAdvice
public class MyHandlerException {
@ResponseBody
@ExceptionHandler(MyException.class)
public Map<String,Object> handlerException(Exception e){
Map<String ,Object> map = new HashMap<>();
map.put("myMessage","自定義資訊" );
return map;
}
}
@ControllerAdvice
:錯誤跳轉控制器
@ResponseBody
:返回內容
@ExceptionHandler
:處理的異常類,針對指定異常進行處理
Map
:返回資訊,自動放進域內
- 直接返回的
json
資訊,只包含自動一內容myMessage
- Spring-Boot預設資料未注入
- 瀏覽器和介面訪問都只返回
json
3. 適配輸出
@ControllerAdvice
public class MyHandlerException {
@ExceptionHandler(MyException.class)
public String handlerException(Exception e, HttpServletRequest request){
Map<String, Object> map = new HashMap<>();
map.put("msg","error");
request.setAttribute("javax.servlet.error.status_code", 400);
return "redirect:/error";
}
}
redirect:/error
:Spring-Boot自動維護一個BasicErrorController
,redirect:/error
會轉發到那讓它自動處理
request
:BasicErrorcontroller
從請求域中識別錯誤型別
javax.servlet.error.status_code
:為了讓BasicErrorController
能夠識別,需要傳入該屬性,設定錯誤碼
redirect:/error
:為了流程完整,再說一遍,轉發BasicErrorController
進行處理
- 轉發
BasicErrorController
的話,就會自動識別瀏覽器和介面,自動跳轉頁面和返回json
了- 但是攜帶的只有Spring-Boot定製的基本資訊,我們可以修改,但是新增的資訊不回傳達到顯示
4. 資訊攜帶
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
map.put("add_msg","this is new add msg");
map.put("company", "godme");
Map<String, Object> myMessage = (Map<String, Object>) webRequest.getAttribute("myMsg", RequestAttributes.SCOPE_REQUEST);
map.put("myMessage", myMessage);
return map;
}
}
DefaultErrorAttributes
:BasicErrorController
取的資訊都是從DefaultErrorAttributes
中取得,所以需要我們進行注入
company
:一般開發的話,總有公司想要注入公司名稱。
webReqeust
:這個是從web中去獲取資料的請求物件
getAttribute
:從域中獲取資料,需要指定key
,和scope
儲存的域,從指定域中獲取物件
return
:返回的map
,BasicErrorController
會自動處理的啦,自動寫入json
,也會自動注入模板
5. 錯誤糾正
為了方便,一直說的是BasicErrorController
,顧名思義,它只是Controller
而已。真正的處理不是它,而是路由到的指定處理器。
如果有想法,可以順著邏輯去翻一翻原始碼。
6. 總結梳理
1. 一般配置
- 頁面位置
classpath:templates/error
claspath:static/error
模板位置可以配置:
spring.server.error.path
-
檔名稱
- 錯誤頁面:
code.html
- 預設頁面:
nxx.html
- 錯誤頁面:
-
模板資料
static
;無資料注入templates
:自動注入資料
BasicErrorController
自動路由
2. 自定資料
- 定義異常
public class MyException extends Exception{
public MyException(){
super("MyException");
}
}
- 資訊注入
@ControllerAdvice
public class MyHandlerException {
@ExceptionHandler(MyException.class)
public String handlerException(Exception e, HttpServletRequest request){
Map<String, Object> map = new HashMap<>();
request.setAttribute("myMessage",e.getMessage());
request.setAttribute("javax.servlet.error.status_code", 400);
return "redirect:/error";
}
}
@ControllerAdvice
:異常訪問
ExceptionHandler
:異常捕捉
request.setAttribute("myMessage",e.getMessage())
:資訊注入
request.setAttribute("javax.servlet.error.status_code", 400)
:路由標記
- 資訊提取
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
map.put("add_msg","this is new add msg");
map.put("company", "godme");
Map<String, Object> myMessage = (Map<String, Object>) webRequest.getAttribute("myMsg", RequestAttributes.SCOPE_REQUEST);
map.put("myMessage", myMessage);
return map;
}
}
DefaultErrorAttributes
:預設採用資訊
map.put("company", "godme")
:注入額外資訊
webRequest.getAttribute("myMsg", RequestAttributes.SCOPE_REQUEST)
:提取注入資訊
map.put("myMessage", myMessage)
:新增到處理引數
@Component
:別忘記標記,交給Spring
3. 流程總結
- 三重路由
- 頁面訪問
- 程式異常處理
- 錯誤轉發
BasicErrorController
- 資料注入
- 頁面資料不相關
- 異常處理時注入新資訊
BasicErrorController
提取新資訊並設定
-
關鍵步驟
- 入口
@ControllerAdvice
:控制錯誤跳轉- 注入
@ExceptionHandler
:處理異常,完成資訊注入
和錯誤轉發
- 交由
BasicErrorController
處理,注意注入錯誤資訊,便於路由
- 提取
DefaultErrorAttributes
重寫getErrorAttributes
getErrorAttributes
:提取上層注入資訊,注入@Component
:Spring管理
三種程度
1. 簡單配置
簡單新增頁面,無需配置,利用程度不高,具體資訊無法獲取。
2. 手動修改
自定義資訊,不論訪問方式,都是json
返回,無頁面路由,瀏覽器頁面不友好。
3. 嫁接方案
- 異常攔截
- 請求轉發
通過攔截異常,把請求轉發BasicErrorController。
利用Spring-Boot自己自動路由功能完成頁面和介面的差異化適配。
request.setAttribute
DefaultAttributes
通過scope
設定域引數,再注入到BasicErrorController
中,讓自定義引數得以處理。
本質上來說,三種處理方式如下
- 入口提供路由頁面,Spring-Boot自動路由
- 手動路由,新引數注入但未適配客戶端
- 修改Spring-Boot錯誤路由,提供頁面,手動路由,注入引數
第三種方式關鍵點在於
手動路由
和引數注入
手動路由
:讓Spring-Boot自動適配客戶端
引數注入
:讓Spring-Boot能夠採用新引數