小編這次要給大家分享的是如何實現Springboot錯誤處理機制,文章內容豐富,感興趣的小伙伴可以來了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。
1.默認的錯誤機制
默認效果
①在瀏覽器中訪問不存在的請求時,springboot默認返回一個空白頁面

瀏覽器的請求頭

②客戶端訪問時,返回json數據
{
"timestamp": "2020-03-24T02:49:56.572+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/"
}客戶端訪問的請求頭

原理
可以參照 ErrorMvcAutoConfiguration 錯誤處理的自動配置
給容器中添加了以下組件
1.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;
}@RequestMapping(
produces = {"text/html"}
)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = this.getStatus(request);
//處理頁面的請求返回給前臺數據 model 的獲取 ,調用
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);
}
//調用 AbstractErrorController#getErrorAttributes
protected Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
WebRequest webRequest = new ServletWebRequest(request);
return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
}
最終調用DefaultErrorAttributes#getErrorAttributes
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {2.BasicErrorController : 處理默認的 /error 請求
@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {
private final ErrorProperties errorProperties;
public String getErrorPath() {
return this.errorProperties.getPath();
}
@RequestMapping(
produces = {"text/html"} //產生html類型的數據,瀏覽器發送的請求來到這個方法處理
)
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 //產生json類型的數據, 其他客戶端發送的請求來到這個方法處理
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = this.getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity(status);
} else {
Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
return new ResponseEntity(body, status);
}
}3.ErrorPageCustomizer
public class ErrorProperties {
@Value("${error.path:/error}")
private String path = "/error"; //系統出現錯誤請求之后來到 /error 請求進行處理 ,(類似于以前 web.xml 中注冊的錯誤頁面規則)4.DefaultErrorViewResolver
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
private ModelAndView resolve(String viewName, Map<String, Object> model) { //默認 springboot 可以找到這個頁面 error/404
String errorViewName = "error/" + viewName; //模板引擎可以解析這個頁面地址就用模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext); //模板引擎可用的情況下就返回到 errorViewName 指定的視圖地址
return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
}
//模板引擎不可用就在靜態資源文件夾里面找 errorViewName 對應的頁面 error/404.html
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
String[] var3 = this.resourceProperties.getStaticLocations();
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
try {
Resource resource = this.applicationContext.getResource(location);
resource = resource.createRelative(viewName + ".html"); //如果靜態資源文件中由 這個資源就直接使用,否則返回為空
if (resource.exists()) {
return new ModelAndView(new DefaultErrorViewResolver.HtmlResourceView(resource), model);
}
} catch (Exception var8) {
}
}
return null;
}步驟:
一旦系統出現 4xx 或者 5xx 之類的錯誤,ErrorPageCustomizer 就會生效(定制錯誤的響應規則),就會來到 /error 請求,會被BasicErrorController
處理。
①響應頁面 去哪個頁面由 DefaultErrorViewResolver 決定
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
Iterator var5 = this.errorViewResolvers.iterator(); //解析所有的 ErrorViewResolver 得到 modelAndView
ModelAndView modelAndView;
do {
if (!var5.hasNext()) {
return null;
}
ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
modelAndView = resolver.resolveErrorView(request, status, model);
} while(modelAndView == null);
return modelAndView;
}2.錯誤信息的定制
①如何定制錯誤頁面
1>有模板引擎的情況下: error/狀態碼 ;【將錯誤頁面命名為 錯誤碼.html 放在模板引擎文件夾下的 error 文件夾下】,發生此狀態碼的錯誤就來到
對應的頁面;
我們可以使用 4xx 和 5xx 作為錯誤頁面的文件名來匹配這種類型的所欲錯誤,精確優先(優先尋找精確的 狀態碼.html );
頁面能夠獲取到的信息
timestamp :時間戳
status : 狀態碼
exception : 異常對象
message : 異常消息
errors : JSR303數據校驗的錯誤都在這兒
2>.沒有模板引擎(模板引擎找不到這個頁面),靜態資源文件夾下找
3>.以上都沒有錯誤頁面,就默認來到 springboot 默認的錯誤頁面
②、自定義異常處理&返回定制json數據;
@ControllerAdvice
public class MyExceptionHandler {
@ResponseBody
@ExceptionHandler(UserNotExistException.class)
public Map<String,Object> handleException(Exception e){
Map<String,Object> map = new HashMap<>();
map.put("code","user.notexist");
map.put("message",e.getMessage());
return map;
}
}
//通過異常處理器,但沒有自適應效果(瀏覽器返回頁面,客戶端訪問返回json數據)2)、轉發到/error進行自適應響應效果處理
@RequestMapping(
produces = {"text/html"}
)
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()); //依據錯誤狀態碼解析錯誤試圖,如果直接轉發,不指定錯誤狀態碼則試圖解析出錯(直接轉發狀態碼為 200 ,到不了定制的 4xx 5xx 的頁面)
ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
return modelAndView != null ? modelAndView : new ModelAndView("error", model);
}@ExceptionHandler(UserNotExistException.class)
public String handleException(Exception e, HttpServletRequest request){
Map<String,Object> map = new HashMap<>();
<strong>//傳入我們自己的錯誤狀態碼 4xx 5xx,否則就不會進入定制錯誤頁面的解析流程</strong>
/**
* Integer statusCode = (Integer) request
.getAttribute("javax.servlet.error.status_code");
*/
request.setAttribute("javax.servlet.error.status_code",500);
map.put("code","user.notexist");
map.put("message",e.getMessage());
//轉發到/error
return "forward:/error";
}3)、將我們的定制數據攜帶出去;======》即修改model中的值即可
出現錯誤以后,會來到/error請求,會被BasicErrorController處理,響應出去可以獲取的數據是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)規定的方法);
1、完全來編寫一個ErrorController的實現類【或者是編寫AbstractErrorController的子類】,放在容器中;
2、頁面上能用的數據,或者是json返回能用的數據都是通過errorAttributes.getErrorAttributes得到;
容器中DefaultErrorAttributes.getErrorAttributes();默認進行數據處理的;
自定義ErrorAttributes
//給容器中加入我們自己定義的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
map.put("company","atguigu");
return map;
}
}最終的效果:響應是自適應的,可以通過定制ErrorAttributes改變需要返回的內容,

看完這篇關于如何實現Springboot錯誤處理機制的文章,如果覺得文章內容寫得不錯的話,可以把它分享出去給更多人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。