Springboot錯誤頁面和錯誤信息定制操作
前面一片已經介紹了springboot錯誤處理的機制,其實從整個分析過程中我們已經大概知道如何定制了。
1、錯誤頁面自定義
springboot有個默認的錯誤頁面,但是開發(fā)時錯誤頁面肯定是自己定義的。那該如何定義?
在DefaultErrorViewResolver類中有下面幾個方法,
private ModelAndView resolve(String viewName, Map<String, Object> model) {
// 定義視圖名,這里我們可以確定視圖名:error/錯誤碼,例如:error/404,
String errorViewName = "error/" + viewName;
// 這里結合上面的errorViewName,其實就是在template目錄下的error目錄進行查找
// 我們默認情況下是沒有error目錄,這里的provide最終值為null,代碼較多就不一一展示,有興趣的可以跟下去
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
// 根據判定,這里會接著調用下面的resolveResource方法
return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
}
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
// getStaticLocations()獲取的是靜態(tài)資源路徑:"classpath:/META-INF/resources/", "classpath:/resources/","classpath:/static/", "classpath:/public/"
String[] var3 = this.resourceProperties.getStaticLocations();
int var4 = var3.length;
// 遍歷上面的4個靜態(tài)資源路徑
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
try {
Resource resource = this.applicationContext.getResource(location);
// 創(chuàng)建resource對象,例如error/404.html
resource = resource.createRelative(viewName + ".html");
// 查找在對應靜態(tài)資源目錄下是否有上面的這個資源對象,有就創(chuàng)建視圖對象
if (resource.exists()) {
return new ModelAndView(new DefaultErrorViewResolver.HtmlResourceView(resource), model);
}
} catch (Exception var8) {
;
}
}
// 都沒找到就返回null,默認情況下是不存在error目錄的,所以這里最終返回null
return null;
}
在解析錯誤視圖界面時,會依次去這幾個目錄:template/、 classpath:/META-INF/resources/ 、 classpath:/resources/、 classpath:/static/ 、classpath:/public/,在這些目錄下的error目錄里找文件名是錯誤狀態(tài)碼的頁面文件(404、500…)。
所以我們可以在這些目錄下創(chuàng)建error目錄,在里面創(chuàng)建HTML頁面,但是在template下面的頁面才能被thymeleaf模板引擎識別。

現(xiàn)在再去訪問不存在路徑時效果如下,因為是404錯誤

但是,錯誤狀態(tài)碼是很多的,不可能將所有的頁面全部寫出來,在DefaultErrorViewResolver類中有下面一段靜態(tài)代碼:
static {
Map<Series, String> views = new EnumMap(Series.class);
views.put(Series.CLIENT_ERROR, "4xx");
views.put(Series.SERVER_ERROR, "5xx");
SERIES_VIEWS = Collections.unmodifiableMap(views);
}
向map中添加了兩個數(shù)據"4xx"、“5xx”,這個表示4開頭或者5開頭的錯誤,并且看到下面的:
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
// 按狀態(tài)碼精確查找
ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);
// 若精確查找未找到再來模糊查找
// status.series()方法可以自己看一下,就是在獲取錯誤碼的首位
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
上面注釋寫的很清楚了,springboot首先按錯誤精確查找,若為找到再以錯誤碼首位模糊查找,所以我們也可以將錯誤頁面文件定義成 4xx.html 或者 5xx.html。

2、錯誤數(shù)據
2.1 默認錯誤數(shù)據
頁面搞定了,那默認的錯誤數(shù)據有哪些呢?響應瀏覽器或者移動端錯誤請求的兩個方法中都同時用到了getErrorAttributes方法,這個方法就是用來獲取錯誤數(shù)據的。
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = this.getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
return modelAndView != null ? modelAndView : new ModelAndView("error", model);
}
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = this.getStatus(request);
return new ResponseEntity(body, status);
}
這個方法是屬于DefaultErrorAttributes類的,用來定義默認錯誤屬性。
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap();
errorAttributes.put("timestamp", new Date());
this.addStatus(errorAttributes, webRequest);
this.addErrorDetails(errorAttributes, webRequest, includeStackTrace);
this.addPath(errorAttributes, webRequest);
return errorAttributes;
}
從這個方法及其里面調用其他幾個方法跟蹤可以知道有如下錯誤屬性:
timestamp:時間戳status:錯誤碼error:錯誤名exception:異常類型message:異常信息trace:錯誤棧path:錯誤路徑


2.2 自定義錯誤數(shù)據
下面模擬一個場景,發(fā)起一個請求,然后觸發(fā)一個自定義異常,自己添加一些錯誤信息,在頁面上顯示出來。 exception:
public class MyException extends RuntimeException {
public MyException() {
super("發(fā)生異常了");
}
}
Controller:
@ResponseBody
@RequestMapping("/hello")
public String hello(@RequestParam("username") String username){
// 當username值為aaa是拋出異常
if(username.equals("aaa")){
throw new MyException();
}
return "hello";
}
為了處理異常還要定義個異常處理器,關鍵點1:注意設置狀態(tài)碼的注釋:
@ControllerAdvice
public class ExceptionController {
@ExceptionHandler(MyException.class)
public String f(HttpServletRequest request){
// 這里要更改狀態(tài)碼,前面訪問路徑是沒有問題的,所以狀態(tài)碼為200
// 若想要進入springboot錯誤處理流程,必須重設狀態(tài)碼
// 并且其key值為:javax.servlet.error.status_code
request.setAttribute("javax.servlet.error.status_code",500);
// 這里可以添加信息到request中,到后面的取出添加到map中
request.setAttribute("data","我的錯誤消息");
// 轉發(fā)到 /error請求,交給springboot處理
return "forward:/error";
}
}
關鍵點2,因為我們的錯誤信都是在DefaultErrorAttributes類中的getErrorAttributes方法中獲取的,若只是到上面步驟為止,那么在移動端將無法獲取到添加的data,所以為止同時使用瀏覽器和移動端,我們還必須創(chuàng)建一個類繼承DefaultErrorAttributes類,重寫getErrorAttributes方法,在這里才是真正的添加自定義的數(shù)據。
MyErrorAttribute:
// 注意,給類必須添加到容器中,否則不生效
// 添加后將會覆蓋原有的DefaultErrorAttributes,采用我們自己的MyErrorAtribute
@Component
public class MyErrorAtribute extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
// 獲取包含錯誤信息的map
Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
// 添加自己的錯誤數(shù)據
map.put("company","lr");
//獲取轉發(fā)過來時添加的數(shù)據
// 第二個參數(shù)表示在哪個域中獲取,0:request,1:session
String data = (String)webRequest.getAttribute("data", 0);
map.put("data",data); // 添加到map
return map;
}
}
然后我們測試,瀏覽器端:

移動端:

這樣,我們錯誤頁面,錯誤消息自定義,瀏覽器和移動端適配都解決了。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
springboot多模塊多環(huán)境配置文件問題(動態(tài)配置生產和開發(fā)環(huán)境)
這篇文章主要介紹了springboot多模塊多環(huán)境配置文件問題(動態(tài)配置生產和開發(fā)環(huán)境),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04
Java日志logback的使用配置和logback.xml解讀
這篇文章主要介紹了Java日志logback的使用配置和logback.xml解讀,具有很好的價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
SpringBoot環(huán)境下junit單元測試速度優(yōu)化方式
這篇文章主要介紹了SpringBoot環(huán)境下junit單元測試速度優(yōu)化方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
一篇文章教你如何在SpringCloud項目中使用OpenFeign
這篇文章主要介紹了SpringCloud 使用Open feign 優(yōu)化詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-08-08
解決Springboot啟動報錯:類文件具有錯誤的版本61.0,應為?52.0
這篇文章主要給大家介紹了關于解決Springboot啟動報錯:類文件具有錯誤的版本?61.0,應為?52.0的相關資料,這是查閱了網上的很多資料才解決的,分享給大家,需要的朋友可以參考下2023-01-01
基于MybatisPlus插件TenantLineInnerInterceptor實現(xiàn)多租戶功能
這篇文章主要介紹了基于MybatisPlus插件TenantLineInnerInterceptor實現(xiàn)多租戶功能,需要的朋友可以參考下2021-11-11

