當咱們開發spring web應用程序時,對於如IOException
,ClassNotFoundException
之類的檢查異常,每每編譯器會提示程序員採用try-catch
進行顯式捕獲,而對於像ClassCastException
,NullPointerException
這類非檢查異常,編譯器是不會提示你了,這每每也是能體現程序員代碼編寫能力的一個方面。html
在spring web特別是spring-boot應用中,當一個請求調用成功時,通常狀況下會返回json
格式的對象,就像下面圖所示:java
但若是請求拋出了一個RuntimeException
呢?若是咱們不作處理,再次調用時將出現下面的頁面:git
也就是說當調用出現錯誤時,spring-boot默認會將請求映射到/error
路徑中去,若是沒有相應的路徑請求處理器,那麼就會返回上面的Whitelabel
錯誤頁面。程序員
固然對運行時異常不作處理是不可能的啦!一般的作法是自定義統一錯誤頁面,而後返回。按照上面的思路,咱們實現一個請求路徑爲/error
的控制器,控制器返回一個資源路徑地址,定義請求映射路徑爲/error
的控制器並實現ErrorController
接口,代碼以下:github
MyErrorPageController
web
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
文件:spring
<!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
,以下:json
@ControllerAdvice
、@ResponseBody
、@ExceptionHandler
統一處理異常在spring中可使用上面3個註解進行統一異常處理,默認狀況下咱們能夠針對系統中出現的某種類型的異常定義一個統一的處理器handler,好比說系統拋出了一個NullPointerException
,那麼咱們能夠定義一個專門針對NullPointerException
的處理器,代碼以下:瀏覽器
getUserInfoWithNullPointerException
接口bash
/**
* 測試空指針錯誤的處理
* @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("出現空指針異常啦!");
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
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
/**
* 測試ArithmeticException錯誤的處理
* @return
* @throws ArithmeticException
*/
@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("算數處理出現異常!");
return errorObject;
}
}
複製代碼
瀏覽器執行 : http://localhost:7000/demo/getUserInfoWithArithmeticException.json
結果發現異常處理並無往上層的ExceptionHandler
傳送。
總結:對於既定義特定類型的處理器,又定義Exception
等父類型的處理器時要特別當心,並非全部的異常都會往上級處理,若是咱們想只減小處理器類的數量,不想爲每種特定類型的處理器添加類或者方法,那麼小編建議使用instanceof
關鍵字對異常類型進行判斷便可。
以下面的代碼,咱們只創建一個公共的異常處理器,處理Exception
異常,同時使用instanceof
進行判斷。
@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
的接口,以下:
本文代碼地址: github.com/SmallerCode…
謝謝閱讀,歡迎start,指正!