這篇文章主要為大家展示了“SpringBoot統(tǒng)一異常處理的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學習一下“SpringBoot統(tǒng)一異常處理的示例分析”這篇文章吧。
站在用戶的角度思考問題,與客戶深入溝通,找到長清網(wǎng)站設(shè)計與長清網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗,讓設(shè)計與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:成都網(wǎng)站設(shè)計、成都網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、域名注冊、網(wǎng)頁空間、企業(yè)郵箱。業(yè)務覆蓋長清地區(qū)。
區(qū)分請求方式
其實 Spring Boot 本身是內(nèi)置了一個異常處理機制的, 會判斷請求頭的參數(shù)來區(qū)分要返回 JSON 數(shù)據(jù)還是錯誤頁面. 源碼為: org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController
, 他會處理 /error 請求. 核心處理代碼如下:
@RequestMapping( produces = {"text/html"} ) // 如果請求頭是 text/html, 則找到錯誤頁面, 并返回 public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { // 1. 獲取 HTTP 錯誤狀態(tài)碼 HttpStatus status = this.getStatus(request); // 2. 調(diào)用 getErrorAttributes 獲取響應的 map 結(jié)果集. Mapmodel = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML))); // 3. 設(shè)置響應頭的狀態(tài)碼 response.setStatus(status.value()); // 4. 獲取錯誤頁面的路徑 ModelAndView modelAndView = this.resolveErrorView(request, response, status, model); return modelAndView != null ? modelAndView : new ModelAndView("error", model); } @RequestMapping @ResponseBody public ResponseEntity
這兩個方法的共同點是: 他們都調(diào)用了 this.getErrorAttributes(…) 方法來獲取響應信息.
然后來看看他默認情況下對于 AJAX 請求和 HTML 請求, 分別的返回結(jié)果是怎樣的:
對于返回錯誤頁面, 其中還調(diào)用了一個非常重要的方法: this.resolveErrorView(...)
方法, 源碼我就不帶大家看了, 他的作用就是根據(jù) HTTP 狀態(tài)碼來去找錯誤頁面, 如 500 錯誤會去找 /error/500.html, 403 錯誤回去找 /error/403.html, 如果找不到則再找 /error/4xx.html 或 /error/5xx.html 頁面. 還找不到的話, 則會去找 /error.html 頁面, 如果都沒有配置, 則會使用 Spring Boot 默認的頁面. 即:
看到這里, 應該就清楚了, 我們主要需要做四件事:
發(fā)送異常后, 重定向到 BasicErrorController 來處理 (既然Spring Boot 都已經(jīng)寫好了區(qū)分請求的功能, 我們就不必要再寫這些判斷代碼了)
自定義 HTTP 錯誤狀態(tài)碼
他返回的信息格式可能不是我們想要的, 所以必須要改造 getErrorAttributes(...)
方法, 以自定義我們向頁面返回的數(shù)據(jù). (自定義錯誤信息)
創(chuàng)建我們自己的 /error/4xx.html 或 /error/5xx.html 等頁面, (自定義錯誤頁面)
BasicErrorController
第一點很簡單, BasicErrorController 他處理 /error 請求, 我們只需要將頁面重定向到 /error 即可, 在 ControllerAdvice 中是這樣的:
@ControllerAdvice public class WebExceptionHandler { @ExceptionHandler public String methodArgumentNotValid(BindException e) { // do something return "/error"; } }
自定義 HTTP 錯誤狀態(tài)碼
我們來看下 this.getStatus(request); 的源碼, 看他原來時如何獲取錯誤狀態(tài)碼的:
protected HttpStatus getStatus(HttpServletRequest request) { Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code"); if (statusCode == null) { return HttpStatus.INTERNAL_SERVER_ERROR; } else { try { return HttpStatus.valueOf(statusCode); } catch (Exception var4) { return HttpStatus.INTERNAL_SERVER_ERROR; } } }
簡單來說就是從 request 域中獲取 javax.servlet.error.status_code 的值, 如果為 null 或不合理的值, 都返回 500. 既然如何在第一步, 重定向到 /error 之前將其配置到 request 域中即可, 如:
@ControllerAdvice public class WebExceptionHandler { @ExceptionHandler public String methodArgumentNotValid(BindException e, HttpServletRequest request) { request.setAttribute("javax.servlet.error.status_code", 400); // do something return "forward:/error"; } }
自定義錯誤信息
也就是 getErrorAttributes 方法, 默認的代碼是這樣的:
public MapgetErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { Map errorAttributes = new LinkedHashMap(); errorAttributes.put("timestamp", new Date()); this.addStatus(errorAttributes, webRequest); this.addErrorDetails(errorAttributes, webRequest, includeStackTrace); this.addPath(errorAttributes, webRequest); return errorAttributes; }
他獲取了時間戳, 錯誤狀態(tài)碼, 錯誤信息, 錯誤路徑等信息, 和我們之前看到默認的返回內(nèi)容是一致的:
{ "timestamp": "2019-01-27T07:08:30.011+0000", "status": 500, "error": "Internal Server Error", "message": "/ by zero", "path": "/user/index" }
同樣的思路, 我們將錯誤信息也放到 request 域中, 然后在 getErrorAttributes 中從 request 域中獲取:
@ControllerAdvice public class WebExceptionHandler { @ExceptionHandler public String methodArgumentNotValid(BindException e, HttpServletRequest request) { request.setAttribute("javax.servlet.error.status_code", 400); request.setAttribute("code", 1); request.setAttribute("message", "參數(shù)校驗失敗, xxx"); // do something return "forward:/error"; } }
再繼承 DefaultErrorAttributes 類, 重寫 getErrorAttributes 方法:
//@Component public class MyDefaultErrorAttributes extends DefaultErrorAttributes { @Override //重寫 getErrorAttributes方法-添加自己的項目數(shù)據(jù) public MapgetErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { Map map = new HashMap<>(); // 從 request 域中獲取 code Object code = webRequest.getAttribute("code", RequestAttributes.SCOPE_REQUEST); // 從 request 域中獲取 message Object message = webRequest.getAttribute("message", RequestAttributes.SCOPE_REQUEST); map.put("code", code); map.put("message", message); return map; } }
自定義錯誤頁面
我們遵循 SpringBoot 的規(guī)則, 在 /error/ 下建立 400.html, 500.html 等頁面細粒度的錯誤, 并配置一個 /error.html 用來處理細粒度未處理到的其他錯誤.
/error/400.html
400 400
/error/500.html
500 500
/error.html
系統(tǒng)出現(xiàn)了錯誤 ERROR PAGE
測試效果
到此位置, 大功告成, 然后來創(chuàng)造一個異常來測試一下效果:
前端 error 處理
現(xiàn)在使用了 HTTP 狀態(tài)碼, 所以 Ajax 請求出現(xiàn)錯誤后, 需要在每個 Ajax 請求方法中都寫 error: function() {}
方法, 甚至麻煩. 好在 jQuery 為我們提供了全局處理 Ajax 的 error 結(jié)果的方法 ajaxError() :
$(document).ajaxError(function(event, response){ console.log("錯誤響應狀態(tài)碼: ",response.status); console.log("錯誤響應結(jié)果: ",response.responseJSON); alert("An error occurred!"); });
以上是“SpringBoot統(tǒng)一異常處理的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!