SpringBoot自定義/error路徑失效的解決
SpringBoot自定義/error路徑失效
背景
最近使用SpringBoot做controller統(tǒng)一異常處理的時候,配置好映射路徑(/error),使用SpringBoot自帶的異常通知注解@ControllerAdvice配置好異常處理類,按理說在Controller發(fā)生異常的時候重定向到自定義錯誤頁面(這里是重定向到SpringMVC的映射路徑),可實際調(diào)試的時候卻定向到了SpringBoot默認(rèn)的錯誤頁面。
配置信息
此處配置只是一個小示例,省略了對異常的處理。
@ControllerAdvice(annotations = Controller.class) public class ExceptionAdvice { @ExceptionHandler({Exception.class}) // 此方法參數(shù)有多個,具體可參考相關(guān)文檔 public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException { response.sendRedirect(request.getContextPath() + "/error"); } }
@Controller public class HomeController { @GetMapping("/error") public String getErrorPage(){ // 此處使用了Thymeleaf模板,返回的是頁面 return "/site/error/500"; } }
解決思路
由于我在controller中配置了/error的映射路徑,我通過網(wǎng)頁路徑直接訪問該路徑也是上面那個錯誤頁面,斷點調(diào)試也沒有進入我自定義的controller。
再看頁面顯示的狀態(tài)碼,不是404,說明該路徑是沒有問題的。
這個問題困惑了我很久,一開始沒轉(zhuǎn)過彎來。
說下我的解決思路,因為我在使用的SpringBoot配置文件是application.yml,這個文件在idea中會有提示,我在該配置文件中輸入了error,如下圖:
這里有一個server.error.path=/error,看到這個就大概知道原因了,路徑?jīng)_突了,我在SpringMVC中配置的映射路徑也是error。
嘗試驗證一下,將SpringMVC的路徑修改了一下,果然可以正常訪問了。
有沒有可以不改變SpringMVC路徑的方法呢?我一開始是在application.yml中加入下面這段配置:
server: error: # 此處可隨便寫一個路徑,或者留空也行,只有不和自定義的error路徑?jīng)_突 path:
這樣確實可以解決路徑?jīng)_突的問題,可是這只是去忽略它,而不是去修改它。
通過查閱資料發(fā)現(xiàn),SpringBoot會為我們創(chuàng)建一個叫BasicErrorController的類,該類由Spring創(chuàng)建并默認(rèn)用來處理Controller中的異常,如果能替換掉該類,就可以解決我們的問題。
如何替換?Spring提供的方法提供一個類型實現(xiàn)ErrorController接口,其實BasicErrorController也是實現(xiàn)了該類。
所有我們只需要將我們自定義ExceptionAdvice類實現(xiàn)該接口,實現(xiàn)相應(yīng)方法即可,修改后代碼如下:
@ControllerAdvice(annotations = Controller.class) public class ExceptionAdvice implements ErrorController{ private static final String ERROR_PATH = "/error"; @ExceptionHandler({Exception.class}) // 此方法參數(shù)有多個,具體可參考相關(guān)文檔 public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException { response.sendRedirect(request.getContextPath() + "/error"); } @Override public String getErrorPath() { return ERROR_PATH; } }
小結(jié):其實就是一個很簡單的問題,而我在一開始的時候卻在糾結(jié)是不是注解使用錯誤之類的事,debug方向是對的,就是一時間沒轉(zhuǎn)過彎來,導(dǎo)致這個問題困擾了我挺長的時間,好在及時理清思路后能解決該問題。
SpringBoot的/error的自定義處理
在springboot項目里,如果沒有統(tǒng)一異常處理,或者如果沒有處理全面,又或者在springCloud zuul中調(diào)用微服務(wù)接口出錯時,spring會自動把錯誤轉(zhuǎn)發(fā)到默認(rèn)給/error處理。
正常情況下,可以配置錯誤頁面來給用戶提示錯誤,如404,500等。但是在前后分離項目中,可能更期望給前臺返回一個特定格式的json來展示錯誤信息。所以可以用代碼來自定義異常錯誤信息。
/error端點的實現(xiàn)來源于SpringBoot的org.springframework.boot.autoconfigure.web.BasicErrorController,
它的具體定義如下
@RequestMapping @ResponseBody 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);}
通過調(diào)用 getErrorAtt豆butes 方法來根據(jù)請求參數(shù)組織錯誤信息的返回結(jié)果,而這里的 getErrorAtt豆bu七es 方法會將具體組織邏輯委托給 org.springframework.boot.autoconfigure.web.ErrorAttributes接口提供的 ge七ErrorAttributes 來實現(xiàn)。
在 Spring Boot 的自動化配置機制中,默認(rèn)會采用 org.springframework.boot.autoconfigure.web.DefaultErrorAttribut作為該接口的實現(xiàn)。
在spring注冊這個bean的時候,使用了注解@ConditionalOnMissingBean(value = ErrorAttributes.class, search =SearchStrategy.CURRENT)
說明只有在不存在ErrorAttributes的bean的時候,才會使用DefaultErrorAttributes來處理,如果我們可以自定義一個,就可以使用我們的類來處理異常了。
編寫一個類繼承DefaultErrorAttributes
他有三個方法
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) public Throwable getError(RequestAttributes requestAttributes)
他們的執(zhí)行順序就如上述順序。
我們可以在getErrorAttributes方法中拿到所有的異常信息,展示如下:
{"timestamp":1528190975129,"status":200,"error":"OK","exception":"java.lang.RuntimeException","message":"error............","path":"/a/b"}
可以在resolveException中拿到異常信息,如果需要返回json,則可以利用response來輸出到前臺,比如:
/* 使用response返回 */ ?? ??? ?response.setStatus(HttpStatus.OK.value()); // 設(shè)置狀態(tài)碼 ?? ??? ?response.setContentType(MediaType.APPLICATION_JSON_VALUE); // 設(shè)置ContentType ?? ??? ?response.setCharacterEncoding("UTF-8"); // 避免亂碼 ?? ??? ?response.setHeader("Cache-Control", "no-cache, must-revalidate"); ? ?? ??? ?try { ?? ??? ??? ?response.getWriter().print("json.........."); ?? ??? ??? ?response.getWriter().flush(); ?? ??? ?} catch (IOException e) { ?? ??? ??? ?e.printStackTrace(); ?? ??? ?} finally { ?? ??? ??? ?try { ?? ??? ??? ??? ?response.getWriter().close(); ?? ??? ??? ?} catch (IOException e) { ?? ??? ??? ??? ?e.printStackTrace(); ?? ??? ??? ?} ?? ??? ?}
這樣,當(dāng)有異常發(fā)生時,就可以在前臺收到異常的json信息,而這個也可以代替統(tǒng)一異常處理使用。同時在springCloud zuul中可以用來自定義異常。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Boot項目利用Redis實現(xiàn)session管理實例
本篇文章主要介紹了Spring Boot項目利用Redis實現(xiàn)session管理實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06理解 MyBatis 是如何在 Spring 容器中初始化的
這篇文章主要介紹了理解 MyBatis 是如何在 Spring 容器中初始化的,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Security中的WebSecurityConfigurerAdapter詳解
這篇文章主要介紹了Security中的WebSecurityConfigurerAdapter詳解,今天我們要進一步的的學(xué)習(xí)如何自定義配置Spring?Security,本文結(jié)合實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07java 出現(xiàn)問題javax.servlet.http.HttpServlet was not found解決方法
這篇文章主要介紹了java 出現(xiàn)問題javax.servlet.http.HttpServlet was not found解決方法的相關(guān)資料,需要的朋友可以參考下2016-11-11