SpringBoot自定義/error路徑失效的解決
SpringBoot自定義/error路徑失效
背景
最近使用SpringBoot做controller統(tǒng)一異常處理的時(shí)候,配置好映射路徑(/error),使用SpringBoot自帶的異常通知注解@ControllerAdvice配置好異常處理類(lèi),按理說(shuō)在Controller發(fā)生異常的時(shí)候重定向到自定義錯(cuò)誤頁(yè)面(這里是重定向到SpringMVC的映射路徑),可實(shí)際調(diào)試的時(shí)候卻定向到了SpringBoot默認(rèn)的錯(cuò)誤頁(yè)面。

配置信息
此處配置只是一個(gè)小示例,省略了對(duì)異常的處理。
@ControllerAdvice(annotations = Controller.class)
public class ExceptionAdvice {
@ExceptionHandler({Exception.class})
// 此方法參數(shù)有多個(gè),具體可參考相關(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模板,返回的是頁(yè)面
return "/site/error/500";
}
}
解決思路
由于我在controller中配置了/error的映射路徑,我通過(guò)網(wǎng)頁(yè)路徑直接訪(fǎng)問(wèn)該路徑也是上面那個(gè)錯(cuò)誤頁(yè)面,斷點(diǎn)調(diào)試也沒(méi)有進(jìn)入我自定義的controller。
再看頁(yè)面顯示的狀態(tài)碼,不是404,說(shuō)明該路徑是沒(méi)有問(wèn)題的。
這個(gè)問(wèn)題困惑了我很久,一開(kāi)始沒(méi)轉(zhuǎn)過(guò)彎來(lái)。
說(shuō)下我的解決思路,因?yàn)槲以谑褂玫腟pringBoot配置文件是application.yml,這個(gè)文件在idea中會(huì)有提示,我在該配置文件中輸入了error,如下圖:

這里有一個(gè)server.error.path=/error,看到這個(gè)就大概知道原因了,路徑?jīng)_突了,我在SpringMVC中配置的映射路徑也是error。
嘗試驗(yàn)證一下,將SpringMVC的路徑修改了一下,果然可以正常訪(fǎng)問(wèn)了。
有沒(méi)有可以不改變SpringMVC路徑的方法呢?我一開(kāi)始是在application.yml中加入下面這段配置:
server:
error:
# 此處可隨便寫(xiě)一個(gè)路徑,或者留空也行,只有不和自定義的error路徑?jīng)_突
path:
這樣確實(shí)可以解決路徑?jīng)_突的問(wèn)題,可是這只是去忽略它,而不是去修改它。
通過(guò)查閱資料發(fā)現(xiàn),SpringBoot會(huì)為我們創(chuàng)建一個(gè)叫BasicErrorController的類(lèi),該類(lèi)由Spring創(chuàng)建并默認(rèn)用來(lái)處理Controller中的異常,如果能替換掉該類(lèi),就可以解決我們的問(wèn)題。
如何替換?Spring提供的方法提供一個(gè)類(lèi)型實(shí)現(xiàn)ErrorController接口,其實(shí)BasicErrorController也是實(shí)現(xiàn)了該類(lèi)。
所有我們只需要將我們自定義ExceptionAdvice類(lèi)實(shí)現(xiàn)該接口,實(shí)現(xiàn)相應(yīng)方法即可,修改后代碼如下:
@ControllerAdvice(annotations = Controller.class)
public class ExceptionAdvice implements ErrorController{
private static final String ERROR_PATH = "/error";
@ExceptionHandler({Exception.class})
// 此方法參數(shù)有多個(gè),具體可參考相關(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é):其實(shí)就是一個(gè)很簡(jiǎn)單的問(wèn)題,而我在一開(kāi)始的時(shí)候卻在糾結(jié)是不是注解使用錯(cuò)誤之類(lèi)的事,debug方向是對(duì)的,就是一時(shí)間沒(méi)轉(zhuǎn)過(guò)彎來(lái),導(dǎo)致這個(gè)問(wèn)題困擾了我挺長(zhǎng)的時(shí)間,好在及時(shí)理清思路后能解決該問(wèn)題。
SpringBoot的/error的自定義處理
在springboot項(xiàng)目里,如果沒(méi)有統(tǒng)一異常處理,或者如果沒(méi)有處理全面,又或者在springCloud zuul中調(diào)用微服務(wù)接口出錯(cuò)時(shí),spring會(huì)自動(dòng)把錯(cuò)誤轉(zhuǎn)發(fā)到默認(rèn)給/error處理。
正常情況下,可以配置錯(cuò)誤頁(yè)面來(lái)給用戶(hù)提示錯(cuò)誤,如404,500等。但是在前后分離項(xiàng)目中,可能更期望給前臺(tái)返回一個(gè)特定格式的json來(lái)展示錯(cuò)誤信息。所以可以用代碼來(lái)自定義異常錯(cuò)誤信息。
/error端點(diǎn)的實(shí)現(xiàn)來(lái)源于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);}通過(guò)調(diào)用 getErrorAtt豆butes 方法來(lái)根據(jù)請(qǐng)求參數(shù)組織錯(cuò)誤信息的返回結(jié)果,而這里的 getErrorAtt豆bu七es 方法會(huì)將具體組織邏輯委托給 org.springframework.boot.autoconfigure.web.ErrorAttributes接口提供的 ge七ErrorAttributes 來(lái)實(shí)現(xiàn)。
在 Spring Boot 的自動(dòng)化配置機(jī)制中,默認(rèn)會(huì)采用 org.springframework.boot.autoconfigure.web.DefaultErrorAttribut作為該接口的實(shí)現(xiàn)。
在spring注冊(cè)這個(gè)bean的時(shí)候,使用了注解@ConditionalOnMissingBean(value = ErrorAttributes.class, search =SearchStrategy.CURRENT)
說(shuō)明只有在不存在ErrorAttributes的bean的時(shí)候,才會(huì)使用DefaultErrorAttributes來(lái)處理,如果我們可以自定義一個(gè),就可以使用我們的類(lèi)來(lái)處理異常了。
編寫(xiě)一個(gè)類(lèi)繼承DefaultErrorAttributes
他有三個(gè)方法
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來(lái)輸出到前臺(tái),比如:
/* 使用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ā)生時(shí),就可以在前臺(tái)收到異常的json信息,而這個(gè)也可以代替統(tǒng)一異常處理使用。同時(shí)在springCloud zuul中可以用來(lái)自定義異常。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot詳解自定義Stater的應(yīng)用
Springboot的出現(xiàn)極大的簡(jiǎn)化了開(kāi)發(fā)人員的配置,而這之中的一大利器便是springboot的starter,starter是springboot的核心組成部分,springboot官方同時(shí)也為開(kāi)發(fā)人員封裝了各種各樣方便好用的starter模塊2022-07-07
Java中常用的數(shù)據(jù)庫(kù)連接池_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
數(shù)據(jù)庫(kù)連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫(kù)連接,它允許應(yīng)用程序重復(fù)使用一個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)連接,而不是再重新建立一個(gè);釋放空閑時(shí)間超過(guò)最大空閑時(shí)間的數(shù)據(jù)庫(kù)連接來(lái)避免因?yàn)闆](méi)有釋放數(shù)據(jù)庫(kù)連接而引起的數(shù)據(jù)庫(kù)連接遺漏2017-08-08
深入理解Java注解類(lèi)型(@Annotation)
這篇文章主要介紹了深入理解Java注解類(lèi)型(@Annotation),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
IDEA提示:Boolean method ‘xxx‘ is always&nb
這篇文章主要介紹了IDEA提示:Boolean method ‘xxx‘ is always inverted問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
idea快速實(shí)現(xiàn)將SpringBoot項(xiàng)目打包Docker鏡像并部署
本文主要介紹了idea快速實(shí)現(xiàn)將SpringBoot項(xiàng)目打包Docker鏡像并部署,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
Swagger2配置Security授權(quán)認(rèn)證全過(guò)程
這篇文章主要介紹了Swagger2配置Security授權(quán)認(rèn)證全過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
Jenkins環(huán)境搭建實(shí)現(xiàn)過(guò)程圖解
這篇文章主要介紹了Jenkins環(huán)境搭建實(shí)現(xiàn)過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09

