當我們開發spring web應用程序時,對于如 ioexception
, classnotfoundexception
之類的檢查異常,往往編譯器會提示程序員采用 try-catch
進行顯式捕獲,而對于像 classcastexception
, nullpointerexception
這類非檢查異常,編譯器是不會提示你了,這往往也是能體現程序員代碼編寫能力的一個方面。
在spring web特別是spring-boot應用中,當一個請求調用成功時,一般情況下會返回 json
格式的對象,就像下面圖所示:

但如果請求拋出了一個 runtimeexception
呢?如果我們不做處理,再次調用時將出現下面的頁面:

也就是說當調用出現錯誤時,spring-boot默認會將請求映射到 /error
路徑中去,如果沒有相應的路徑請求處理器,那么就會返回上面的 whitelabel
錯誤頁面。
1、自定義錯誤處理頁面
當然對運行時異常不做處理是不可能的啦!通常的做法是自定義統一錯誤頁面,然后返回。按照上面的思路,我們實現一個請求路徑為 /error
的控制器,控制器返回一個資源路徑地址,定義請求映射路徑為 /error
的控制器并實現 errorcontroller
接口,代碼如下:
myerrorpagecontroller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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:自定義錯誤頁面 * * @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
文件:
1
2
3
4
5
6
7
8
9
10
|
<!doctype html> <html> <head> <meta charset= "utf-8" > <title>insert title here</title> </head> <body> <h1>這是個錯誤頁面!存放在resources/ static 目錄下,spring-boot發生錯誤時默認調用</h1> </body> </html> |
再次請求 http://localhost:7000/demo/getuserinfowithnohandler.json
,如下:

@controlleradvice
、 @responsebody
、 @exceptionhandler
統一處理異常
在spring中可以使用上面3個注解進行統一異常處理,默認情況下我們可以針對系統中出現的某種類型的異常定義一個統一的處理器handler,比如說系統拋出了一個 nullpointerexception
,那么我們可以定義一個專門針對 nullpointerexception
的處理器,代碼如下:
getuserinfowithnullpointerexception
接口
1
2
3
4
5
6
7
8
9
|
/** * 測試空指針錯誤的處理 * @return * @throws nullpointerexception */ @requestmapping (value = "getuserinfowithnullpointerexception.json" , method = requestmethod.get) public student getuserinfowithnullpointerexception() throws nullpointerexception { throw new nullpointerexception(); } |
nullpointerexceptionhandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
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( "出現空指針異常啦!" ); return error; } } |
瀏覽器執行: http://localhost:7000/demo/getuserinfowithnullpointerexception.json

同樣的道理,如果我們還需要為其他的運行時異常提供統一的處理器,那么也可以像上面一樣為每一個異常類型定義一個處理器,比如我們又想為 arithmeticexception
定義處理器,那么我們只需要建立一個類或者方法,然后在方法上的 @exceptionhanler
注解內加上 arithmeticexception.class
指定異常類型即可。
不過你有沒有發現,這樣為每種異常類型定義一個異常處理類或者方法,因為運行時異常類型特別多,不可能為每種類型都指定一個處理器類或方法,針對這種情況,spring也是可以解決的。如果我們沒有為某種特定類型異常,如 arithmeticexception
定義處理器,那么我們可以定義一個 exception
或者 throwable
處理器統一處理。
這樣做的好處是,減少了處理器類的數量,同時將異常處理轉移到父類上面去,這也是繼承的一大優勢吧!但是,當你既定義了特定類型的異常,同時又定義了 exception
異常的處理器,那么要小心了,這里不一定有優先級的關系,也就是說不一定會出現只執行父異常處理器的情況,可能是只執行a處理器,而不執行b處理器或者只執行b處理器,不執行a處理器。如 nullpointerexceptionhandler
異常會向 exception
異常傳遞(但 arithmeticexception
不會向 exception
傳遞)
現在假設我們既定義上面的 nullpointerexceptionhandler
,又定義了下面的 exceptionthrowablehandler
,那么當發生 nullpointerexception
時,就會默認執行 exceptionthrowablehandler
的方法。
exceptionthrowablehandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
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:有些異常會向高級別異常傳遞(但arithmeticexception不會向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; } } |
瀏覽器執行 : http://localhost:7000/demo/getuserinfowithnullpointerexception.json

可以發現只執行 exception
的處理器,沒有執行空指針的處理器,也就是異常處理往上傳送了。下面再來看看拋出 arithmeticexception
的情況:
getuserinfowitharithmeticexception.json
1
2
3
4
5
6
7
8
9
|
/** * 測試空指針錯誤的處理 * @return * @throws nullpointerexception */ @requestmapping (value = "getuserinfowitharithmeticexception.json" , method = requestmethod.get) public student getuserinfowitharithmeticexception() throws arithmeticexception { throw new arithmeticexception(); } |
arithmeticexceptionhandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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( "算數處理出現異常!" ); return errorobject; } } |
瀏覽器執行 : http://localhost:7000/demo/getuserinfowitharithmeticexception.json

結果發現異常處理并沒有往上層的 exceptionhandler
傳送。
總結:對于既定義特定類型的處理器,又定義 exception
等父類型的處理器時要特別小心,并不是所有的異常都會往上級處理,如果我們想只減少處理器類的數量,不想為每種特定類型的處理器添加類或者方法,那么小編建議使用 instanceof
關鍵字對異常類型進行判斷即可。
如下面的代碼,我們只建立一個公共的異常處理器,處理 exception
異常,同時使用 instanceof
進行判斷。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@exceptionhandler (exception. class ) @responsebody public errorreturn dealcommonexception(exception e) { errorreturn error = new errorreturn(); // 此處可以采用 instanceof 判斷異常類型 if (e instanceof arithmeticexception) { error.setreturncode( "-1" ); error.setdesc( "算數異常處理!" ); return error; } system.err.println( "exception" ); error.setreturncode( "-1" ); error.setdesc( "公共異常處理!" ); return error; } |
瀏覽器執行拋出 arithmeticexception
的接口,如下:

本文代碼地址: https://github.com/smallercoder/spring_exceptionhandler
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://juejin.im/post/5b2101716fb9a01e80785be2