您好,登錄后才能下訂單哦!
小編這次要給大家分享的是如何實現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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。