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

現(xiàn)在再去訪問(wèn)不存在路徑時(shí)效果如下,因?yàn)槭?04錯(cuò)誤

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

2、錯(cuò)誤數(shù)據(jù)
2.1 默認(rèn)錯(cuò)誤數(shù)據(jù)
頁(yè)面搞定了,那默認(rèn)的錯(cuò)誤數(shù)據(jù)有哪些呢?響應(yīng)瀏覽器或者移動(dòng)端錯(cuò)誤請(qǐng)求的兩個(gè)方法中都同時(shí)用到了getErrorAttributes方法,這個(gè)方法就是用來(lái)獲取錯(cuò)誤數(shù)據(jù)的。
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);
}
這個(gè)方法是屬于DefaultErrorAttributes類(lèi)的,用來(lái)定義默認(rèn)錯(cuò)誤屬性。
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;
}
從這個(gè)方法及其里面調(diào)用其他幾個(gè)方法跟蹤可以知道有如下錯(cuò)誤屬性:
timestamp:時(shí)間戳status:錯(cuò)誤碼error:錯(cuò)誤名exception:異常類(lèi)型message:異常信息trace:錯(cuò)誤棧path:錯(cuò)誤路徑


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

移動(dòng)端:

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

