您好,登錄后才能下訂單哦!
當(dāng)我們開(kāi)發(fā)spring web應(yīng)用程序時(shí),對(duì)于如 IOException
, ClassNotFoundException
之類的檢查異常,往往編譯器會(huì)提示程序員采用 try-catch
進(jìn)行顯式捕獲,而對(duì)于像 ClassCastException
, NullPointerException
這類非檢查異常,編譯器是不會(huì)提示你了,這往往也是能體現(xiàn)程序員代碼編寫(xiě)能力的一個(gè)方面。
在spring web特別是spring-boot應(yīng)用中,當(dāng)一個(gè)請(qǐng)求調(diào)用成功時(shí),一般情況下會(huì)返回 json
格式的對(duì)象,就像下面圖所示:
但如果請(qǐng)求拋出了一個(gè) RuntimeException
呢?如果我們不做處理,再次調(diào)用時(shí)將出現(xiàn)下面的頁(yè)面:
也就是說(shuō)當(dāng)調(diào)用出現(xiàn)錯(cuò)誤時(shí),spring-boot默認(rèn)會(huì)將請(qǐng)求映射到 /error
路徑中去,如果沒(méi)有相應(yīng)的路徑請(qǐng)求處理器,那么就會(huì)返回上面的 Whitelabel
錯(cuò)誤頁(yè)面。
1、自定義錯(cuò)誤處理頁(yè)面
當(dāng)然對(duì)運(yùn)行時(shí)異常不做處理是不可能的啦!通常的做法是自定義統(tǒng)一錯(cuò)誤頁(yè)面,然后返回。按照上面的思路,我們實(shí)現(xiàn)一個(gè)請(qǐng)求路徑為 /error
的控制器,控制器返回一個(gè)資源路徑地址,定義請(qǐng)求映射路徑為 /error
的控制器并實(shí)現(xiàn) ErrorController
接口,代碼如下:
MyErrorPageController
package com.example.demo.controller.handler.errorpage; import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * * The class MyErrorPageController. * * Description:自定義錯(cuò)誤頁(yè)面 * * @author: huangjiawei * @since: 2018年6月13日 * @version: $Revision$ $Date$ $LastChangedBy$ * */ @Controller public class MyErrorPageController implements ErrorController { @RequestMapping("/error") public String handleError() { return "error.html"; // 該資源位于resources/static目錄下 } @Override public String getErrorPath() { return null; } }
然后在 reosurces/static
目錄下建立 error.html
文件:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h2>這是個(gè)錯(cuò)誤頁(yè)面!存放在resources/static目錄下,spring-boot發(fā)生錯(cuò)誤時(shí)默認(rèn)調(diào)用</h2> </body> </html>
再次請(qǐng)求 http://localhost:7000/demo/getUserInfoWithNoHandler.json
,如下:
2、使用 @ControllerAdvice
、 @ResponseBody
、 @ExceptionHandler
統(tǒng)一處理異常
在spring中可以使用上面3個(gè)注解進(jìn)行統(tǒng)一異常處理,默認(rèn)情況下我們可以針對(duì)系統(tǒng)中出現(xiàn)的某種類型的異常定義一個(gè)統(tǒng)一的處理器handler,比如說(shuō)系統(tǒng)拋出了一個(gè) NullPointerException
,那么我們可以定義一個(gè)專門針對(duì) NullPointerException
的處理器,代碼如下:
getUserInfoWithNullPointerException
接口
/** * 測(cè)試空指針錯(cuò)誤的處理 * @return * @throws NullPointerException */ @RequestMapping(value = "getUserInfoWithNullPointerException.json", method = RequestMethod.GET) public Student getUserInfoWithNullPointerException() throws NullPointerException { throw new NullPointerException(); }
NullPointerExceptionHandler.java
package com.example.demo.controller.handler; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.example.demo.pojo.ErrorReturn; /** * * The class NullPointerExceptionHandler. * * Description:處理空指針 * * @author: huangjiawei * @since: 2018年6月13日 * @version: $Revision$ $Date$ $LastChangedBy$ * */ @ControllerAdvice public class NullPointerExceptionHandler { @ExceptionHandler(NullPointerException.class) @ResponseBody public ErrorReturn dealNullPointerException() { e.printStackTrace(); ErrorReturn error = new ErrorReturn(); error.setReturnCode("-1"); error.setDesc("出現(xiàn)空指針異常啦!"); return error; } }
瀏覽器執(zhí)行: http://localhost:7000/demo/getUserInfoWithNullPointerException.json
同樣的道理,如果我們還需要為其他的運(yùn)行時(shí)異常提供統(tǒng)一的處理器,那么也可以像上面一樣為每一個(gè)異常類型定義一個(gè)處理器,比如我們又想為 ArithmeticException
定義處理器,那么我們只需要建立一個(gè)類或者方法,然后在方法上的 @ExceptionHanler
注解內(nèi)加上 ArithmeticException.class
指定異常類型即可。
不過(guò)你有沒(méi)有發(fā)現(xiàn),這樣為每種異常類型定義一個(gè)異常處理類或者方法,因?yàn)檫\(yùn)行時(shí)異常類型特別多,不可能為每種類型都指定一個(gè)處理器類或方法,針對(duì)這種情況,spring也是可以解決的。如果我們沒(méi)有為某種特定類型異常,如 ArithmeticException
定義處理器,那么我們可以定義一個(gè) Exception
或者 Throwable
處理器統(tǒng)一處理。
這樣做的好處是,減少了處理器類的數(shù)量,同時(shí)將異常處理轉(zhuǎn)移到父類上面去,這也是繼承的一大優(yōu)勢(shì)吧!但是,當(dāng)你既定義了特定類型的異常,同時(shí)又定義了 Exception
異常的處理器,那么要小心了,這里不一定有優(yōu)先級(jí)的關(guān)系,也就是說(shuō)不一定會(huì)出現(xiàn)只執(zhí)行父異常處理器的情況,可能是只執(zhí)行A處理器,而不執(zhí)行B處理器或者只執(zhí)行B處理器,不執(zhí)行A處理器。如 NullPointerExceptionHandler
異常會(huì)向 Exception
異常傳遞(但 ArithmeticException
不會(huì)向 Exception
傳遞)
現(xiàn)在假設(shè)我們既定義上面的 NullPointerExceptionHandler
,又定義了下面的 ExceptionThrowableHandler
,那么當(dāng)發(fā)生 NullPointerException
時(shí),就會(huì)默認(rèn)執(zhí)行 ExceptionThrowableHandler
的方法。
ExceptionThrowableHandler.java
package com.example.demo.controller.handler; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.example.demo.pojo.ErrorReturn; /** * * The class ExceptionThrowableHandler. * * Description:有些異常會(huì)向高級(jí)別異常傳遞(但ArithmeticException不會(huì)向Exception傳送) * * @author: huangjiawei * @since: 2018年6月13日 * @version: $Revision$ $Date$ $LastChangedBy$ * */ @ControllerAdvice public class ExceptionThrowableHandler { @ExceptionHandler(Throwable.class) @ResponseBody public ErrorReturn dealThrowable() { ErrorReturn error = new ErrorReturn(); error.setDesc("處理Throwable!"); error.setReturnCode("-1"); return error; } @ExceptionHandler(Exception.class) @ResponseBody public ErrorReturn dealCommonException() { ErrorReturn error = new ErrorReturn(); error.setReturnCode("-1"); error.setDesc("公共異常處理!"); return error; } }
瀏覽器執(zhí)行 : http://localhost:7000/demo/getUserInfoWithNullPointerException.json
可以發(fā)現(xiàn)只執(zhí)行 Exception
的處理器,沒(méi)有執(zhí)行空指針的處理器,也就是異常處理往上傳送了。下面再來(lái)看看拋出 ArithmeticException
的情況:
getUserInfoWithArithmeticException.json
/** * 測(cè)試空指針錯(cuò)誤的處理 * @return * @throws NullPointerException */ @RequestMapping(value = "getUserInfoWithArithmeticException.json", method = RequestMethod.GET) public Student getUserInfoWithArithmeticException() throws ArithmeticException { throw new ArithmeticException(); }
ArithmeticExceptionHandler.java
package com.example.demo.controller.handler; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.example.demo.pojo.ErrorReturn; @ControllerAdvice public class ArithmeticExceptionHandler { /** * 處理ArithmeticException異常 * @return */ @ResponseBody @ExceptionHandler(ArithmeticException.class) public ErrorReturn dealArithmeticException() { ErrorReturn errorObject = new ErrorReturn(); errorObject.setReturnCode("-1"); errorObject.setDesc("算數(shù)處理出現(xiàn)異常!"); return errorObject; } }
瀏覽器執(zhí)行 : http://localhost:7000/demo/getUserInfoWithArithmeticException.json
結(jié)果發(fā)現(xiàn)異常處理并沒(méi)有往上層的 ExceptionHandler
傳送。
總結(jié):對(duì)于既定義特定類型的處理器,又定義 Exception
等父類型的處理器時(shí)要特別小心,并不是所有的異常都會(huì)往上級(jí)處理,如果我們想只減少處理器類的數(shù)量,不想為每種特定類型的處理器添加類或者方法,那么小編建議使用 instanceof
關(guān)鍵字對(duì)異常類型進(jìn)行判斷即可。
如下面的代碼,我們只建立一個(gè)公共的異常處理器,處理 Exception
異常,同時(shí)使用 instanceof
進(jìn)行判斷。
@ExceptionHandler(Exception.class) @ResponseBody public ErrorReturn dealCommonException(Exception e) { ErrorReturn error = new ErrorReturn(); // 此處可以采用 instanceof 判斷異常類型 if (e instanceof ArithmeticException) { error.setReturnCode("-1"); error.setDesc("算數(shù)異常處理!"); return error; } System.err.println("exception"); error.setReturnCode("-1"); error.setDesc("公共異常處理!"); return error; }
瀏覽器執(zhí)行拋出 ArithmeticException
的接口,如下:
本文代碼地址: https://github.com/SmallerCoder/spring_exceptionHandler
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。