javascript
Spring Boot错误处理机制以及定制自己的错误页面
在我們使用Spring Boot的過程中肯定有遇到過發生錯誤的時候,這個時候可能頁面上出現的就是Spring Boot默認的錯誤界面,有的時候我們希望能顯示我們自己設置的錯誤界面,或者攜帶我們自己的錯誤響應參數,比如查詢用戶是否存在的時候,如果用戶不存在,控制器可以選擇拋出一個用戶不存在異常,這個時候我們希望錯誤響應參數可以攜帶一個message響應參數表示用戶不存在,而不是Spring Boot為我們配置好的那幾個參數,這個時候我們應該這么做呢,這就是本文的目的。
如果要配置自己的錯誤界面,首先我們需要先了解一下Spring Boot是如何處理錯誤的。Spring Boot在自動配置類ErrorMvcAutoConfiguration中為我們添加了4個錯誤處理相關的組件,具體可以在IDEA中使用Ctrl+N來查找這個類,他們的作用可以查看下面代碼中的注釋:
1、DefaultErrorAttributes
//幫我們設置錯誤響應參數; @Override public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,boolean includeStackTrace) {Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();errorAttributes.put("timestamp", new Date());addStatus(errorAttributes, requestAttributes);addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);addPath(errorAttributes, requestAttributes);return errorAttributes; }2、BasicErrorController
//處理/error請求,根據請求頭中的信息(Accept參數)來判斷優先返回html頁面,還是JSON數據 @Controller @RequestMapping("${server.error.path:${error.path:/error}}") public class BasicErrorController extends AbstractErrorController {@RequestMapping(produces = "text/html")//產生html類型的數據;瀏覽器發送的請求來到這個方法處理public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {HttpStatus status = getStatus(request);Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));response.setStatus(status.value());//去哪個頁面作為錯誤頁面;包含頁面地址和頁面內容ModelAndView modelAndView = resolveErrorView(request, response, status, model);return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);}@RequestMapping@ResponseBody //產生json數據,其他客戶端來到這個方法處理;public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {Map<String, Object> body = getErrorAttributes(request,isIncludeStackTrace(request, MediaType.ALL));HttpStatus status = getStatus(request);return new ResponseEntity<Map<String, Object>>(body, status);} }3、ErrorPageCustomizer
/** 配置錯誤發生后,到哪去。這里是系統出現錯誤以后來到error請求進行處理; 也就是到上面的BasicErrorController處理器,(相當于以前web.xml注冊的錯誤頁面規則)。 可以看到這個參數是可配置的。 **/ @Value("${error.path:/error}") private String path = "/error";4、DefaultErrorViewResolver
@Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,Map<String, Object> model) {ModelAndView modelAndView = resolve(String.valueOf(status), model);if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);}return modelAndView; }private ModelAndView resolve(String viewName, Map<String, Object> model) {//默認SpringBoot可以去找到一個頁面? 比如error/404String errorViewName = "error/" + viewName;//模板引擎可以解析這個頁面地址就用模板引擎解析TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);if (provider != null) {//模板引擎可用的情況下返回到errorViewName指定的視圖地址return new ModelAndView(errorViewName, model);}//模板引擎不可用,就在靜態資源文件夾下找errorViewName對應的頁面error/404.htmlreturn resolveResource(errorViewName, model); }錯誤響應步驟如下:
一但系統出現4xx或者5xx之類的錯誤;ErrorPageCustomizer就會生效(定制錯誤的響應規則);就會來到/error請求;就會被BasicErrorController處理;如果決定產生html數據,而不是直接返回JSON數據,就使用DefaultErrorViewResolver試圖解析器來解析我們的ModelAndView,最終決定返回哪個html文件。我們可以使用4xx和5xx作為錯誤頁面的文件名來匹配這種類型的所有錯誤,精確優先(優先尋找精確的狀態碼.html,比如發生404錯誤,有404.html就不去4xx.html了);我們將這些錯誤響應的.html文件放到靜態資源路徑下的/error文件夾下即可。
通過上面的描述如果需要返回自己的錯誤返回界面,直接在靜態資源文件夾下新建/error文件夾,將自己的錯誤響應.html文件放到里面即可,這些.html文件可能是4xx.html、404.html、5xx.html、500.html。具體響應哪個.html文件根據錯誤代碼來決定。如果需要自定義錯誤響應信息,那么你還需要像下面這樣做:
1、只響應JSON數據,而不管請求的是什么(比如請求.html頁面,也返回JSON數據)
首先新建@ControllerAdvice類,而后在其中寫@ExceptionHandler方法即可,如下:
@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;} }關于@ControllerAdvice注解更加詳細的解釋你可以看這里,在本文章中主要是結合@ExceptionHandler注解來處理錯誤。另外UserNotExistException是我們自定義的一個錯誤,由Controller拋出。
2、自適應響應
上面處理的方式有一個問題,就是不管是頁面請求,還是JSON數據請求,我們都是返回JSON數據,如何做到請求JSON數據就返回JSON數據,請求頁面就返回頁面呢?我們可以回到上面說到的BasicErrorController組件,這個組件會自適應的處理/error請求,所以我們可以轉發到/error界面,如下所示:
@ControllerAdvice public class MyExceptionHandler {@ExceptionHandler(UserNotExistException.class)public String handleException(Exception e, HttpServletRequest request){//傳入我們自己的錯誤狀態碼 4xx 5xx,否則就不會進入定制錯誤頁面的解析流程request.setAttribute("javax.servlet.error.status_code",500);//轉發到/errorreturn "forward:/error";} }但是,這個時候我們又無法響應我們自己定制的錯誤響應數據了,我們希望不但可以自適應,又可以攜帶我們自定義的數據。如果你足夠細心的話,可以發現,在上面BasicErrorController組件中,不論是響應HTML頁面還是反回JSON數據,都會調用getErrorAttributes這個方法,來設置錯誤響應數據,這個方法來自容器中的DefaultErrorAttributes組件,這個組件會在我們沒有在容器中添加ErrorAttributes組件的前提下添加到容器中作為默認的ErrorAttributes以返回錯誤響應數據;所以我們如果要響應我們自己的數據,我們就要寫一個ErrorAttributes,并且實現它的getErrorAttributes方法,然后加入到容器中,為了簡單起見我們直接,繼承DefaultErrorAttributes然后重寫getErrorAttributes方法即可:
//給容器中加入我們自己定義的ErrorAttributes @Component public class MyErrorAttributes extends DefaultErrorAttributes {@Overridepublic Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,boolean includeStackTrace) {//保留默認的錯誤處理數據Map<String, Object> map = super.getErrorAttributes(requestAttributes,includeStackTrace);//由具體的錯誤處理器填入的數據,第二個參數的意思是scope,也就是從哪個域中獲取,0:request,1:session, .....map.put("ext", RequestAttributes.getAttribute("ext", 0));//所有錯誤都會填入的錯誤響應數據map.put("company","BaiDu");return map;} }上面注釋中說到的 “由具體的錯誤處理器填入的數據” 的意思是如下:
@ControllerAdvice public class MyExceptionHandler {@ExceptionHandler(UserNotExistException.class)public String handleException(Exception e, HttpServletRequest request){//傳入我們自己的錯誤狀態碼 4xx 5xx,否則就不會進入定制錯誤頁面的解析流程request.setAttribute("javax.servlet.error.status_code",500);//填入額外的錯誤響應處理數據:Map<String,Object> map = new HashMap<>();map.put("code","user.notexist");map.put("message",e.getMessage());request.setAttribute("ext", map);//轉發到/errorreturn "forward:/error";} }這樣一來我們就不但可以自適應響應數據,還可以定制自己的錯誤響應信息了。
總結:
上面詳細講述了Spring Boot中發生錯誤后,如何處理的的流程,并且自定義錯誤響應數據和界面。讀者可以選擇自己需要的功能來選擇如何處理,主要是懂得原理,這些處理方式就能使用的游刃有余。簡單分為以下兩點:
- 不需要自定義錯誤響應數據,只要到我們自己的錯誤響應界面,則編寫錯誤代碼對應的HTML文件,并將這些錯誤響應的.html文件放到靜態資源路徑下的/error文件夾下即可。
- 需要自定義錯誤響應數據,并且自適應響應,則在容器中加入我們自己的ErrorAttributes組件即可。
總結
以上是生活随笔為你收集整理的Spring Boot错误处理机制以及定制自己的错误页面的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Boot注册Servlet
- 下一篇: gradle idea java ssm