測試開發專題:spring-boot統一異常捕獲

java異常介紹

異常時相對於return的一種退出機制,能夠由系統觸發,也可由程序經過throw語句觸發,異常能夠經過try/catch語句進行捕獲並處理,若是沒有捕獲,則會致使程序退出並輸出異常棧信息,異常有不一樣的類型,全部異常類都有一個共同的父類Throwable,下面咱們先從Throwable開始介紹。html

Throwable

Throwable是全部異常類的父類,有四個構造方法java

public Throwable(Throwable cause)
public Throwable(String message, Throwable cause) 
public Throwable(String message)
public Throwable()

主要有兩個類,一個是message,表示異常的消息,一個是cause,表示觸發該異常的其餘異常,異常能夠造成一個異常鏈,上層的異常由底層到的異常觸發,cause表示底層異常。程序員

異常體系

java定義了很是多的異常類,來表示各類類型的異常,下面的圖示是部分的異常類:spring

image-20200508232051535

Throwable是全部異常類的基類,它有兩個子類:Error和Exception。數據庫

  • Error錯誤

操做系統或者虛擬機發生的錯誤,這個時候程序是跑不起來的,代碼是沒法處理的,通常表示系統錯誤或者資源耗盡,由java系統本身處理,好比圖示中給出的:虛擬機錯誤、棧溢出、內存溢出等錯誤瀏覽器

  • Exception

表示應用程序錯誤,是能夠經過代碼處理的,有兩大類:一類是受檢異常(checked exception),一類是非受檢異常(uncheck exception),也就是runtime異常,他兩的區別就在於java是如何對待他們的,受檢異常,java會要求強制進行處理,否則編譯時不經過的,對於非受檢異常則沒有這個強制性的要求。app

解釋函數

該怎麼理解受檢異常和非受檢異常呢,個人理解就是作某件事的時候咱們可以順利的按照咱們預期的作完,可是實際上呢可能會出現各類各樣的狀況,這種可能出現的狀況就把他稱之爲異常,這種異常有的咱們能處理,有的咱們不能處理,能處理的就把它稱做爲受檢異常,不能處理的稱做爲非受檢異常。spring-boot

好比說,客戶端發送一個請求,要查詢數據庫,那有可能找到有可能沒找到,沒找到的話,就應該拋出runtime異常,再好比要去讀取文件,文件多是不存在的,那就應該拋出checked exception,這其實就是bug,咱們應該去處理的。測試

怎麼理解呢,好比讀取文件,當文件不存在,發生異常,能處理麼,固然能夠處理啊,怎麼處理,把文件路徑改爲正確的不就好了。從某種意義上來講,checked異常是真正的bug

沒有辦法處理的狀況,好比說用戶輸入ID爲2,查詢記錄能找到,可是若是輸入2000就找不到了,這裏的找不到就是一種異常狀況,就須要產生一個運行時異常也就是非受檢異常。

已知異常和未知異常

上面咱們提到的受檢異常 unchecked exception和運行時異常 RuntimeException都是從java語法層面來講的,那從程序開發者的角度來講,分爲兩類:已知異常和未知異常。

已知異常和未知異常,其實就在於咱們程序員是否主動的去處理異常。

  • 未知異常:當代碼中未對一些狀況作出處理而引起的異常,這就是未知異常,通常這種異常都是由於服務端的代碼寫的有問題的,對於前段開發或者用戶,都是無心義的,記錄日誌供本身查看就好了。
  • 已知異常:更多的時候表示的是一種消息,用來提示用戶的輸入是否有問題,只不過這裏咱們用異常的形式來處理,固然也能夠經過其餘方式處理,好比當作結果去返回,也是能夠的,可是這種方式不如所有都看作異常,經過全局的異常處理器直接處理來的簡單。

Spring-Boot全局異常處理器

在使用spring-boot進行開發到的時候,有時咱們須要對程序中拋出的異常進行統一的處理,spring-boot預留了響應的擴展點,咱們只須要按照要求的方式去自定義本身的實現便可。

@ControllerAdvice
public class GlobalExceptionAdvice {

    @ExceptionHandler(value = Exception.class)
    public void handleHttpException(HttpServletRequest req, Exception ex){
  
    }
}

@ControllerAdvice代表GlobalExceptionAdvice是一個異常的處理類,具體的處理方法經過 @ExceptionHandler進行標記,經過value來指定可以處理的異常類型。異常的處理方法須要傳入兩個參數,一個是HttpServletRequest請求對象,能夠從這裏獲取請求相關的一些信息,好比請求的url或者參數等,另外一個是Exception就是拋出的異常。

模擬異常發生

咱們在異常的處理方法中打印一條語句

@ControllerAdvice
public class GlobalExceptionAdvice {

    @ExceptionHandler(value = Exception.class)
    public void handleHttpException(HttpServletRequest req, Exception ex){
        System.out.println("發生異常了");
    }
}

而後再Controller裏拋出一個異常

@RestController
public class BannerController {

    @RequestMapping(value = "/v2/banner", method = {RequestMethod.GET})
    public String test() throws Exception {
        throw new Exception("我拋出來的");
    }
}

啓動程序後在瀏覽器中訪問路由,能夠看到在控制檯中打印出了預期的信息

image-20200509001215452

固然在實際開發中,咱們可能要多異常進行區分,該拋出什麼類型的異常,異常處理函數可也不僅一個,還要對返回的異常信息進行自定義。

自定義異常類

當咱們須要自定義異常類的時候,是該繼承自exception呢,仍是繼承RuntimeException?下面咱們就來討論一下。

當用戶訪問一個不存在的資源的時候,很明顯這種狀況咱們是處理不了的,並且這種狀況咱們是能夠判斷出來的,因此這裏應該使用Runtime異常。

image-20200509100041018

HttpException是全部自定義運行時異常類的基類,這裏定義兩個狀態碼,一個code是咱們業務層面的定義,一個httpStatusCode是http請求的,資源不存在的異常定義爲 NotFoundException

image-20200509100342221

在controller裏面拋出這個異常,

image-20200509103228206

那以前定義的 GlobalExceptionAdvice可以監聽到這個異常呢?

固然能,NotFoundExceptionHttpException的子類,HttpExceptionRuntimeException的子類,RuntimeException又是 Exception的子類,@ExceptionHandler(value = Exception.class)全局異常處理器裏指定的可以處理的異常類是 Exception天然也能處理 NotFoundException

可是這裏也有不一樣的地方,咱們自定義的 HttpException是多了兩個擴展字段的,codehttpStatusCode,因此在全局異常處理器裏須要對異常的類型進行判斷,若是是自定義的就須要添加這兩個字段。

這裏呢有兩種方式進行處理:一種是在以前的異常處理方法裏面,進行類型判斷,另外一種呢是能夠再添加一個異常處理方法,專門處理自定義異常類

image-20200509104418301

這裏咱們能夠考慮一下,當咱們拋出 NotFoundException異常的時候,是會進入哪個異常處理方法裏?仍是說兩個都進呢?

咱們能夠來試驗一下,啓動程序後,看看在控制檯打印的是什麼

image-20200509165843525

在瀏覽器裏訪問路由之後,控制檯顯示了handleHttpException異常處理方法裏到的打印語句輸出的內容。

能夠看到多個異常處理方法時能夠同時存在的,各自處理本身所能處理的異常類。

下篇文章,咱們來探討一下,如何自定義異常的返回信息,敬請關注,博客原文

歡迎你們去 個人博客 瞅瞅,裏面有更多關於測試實戰的內容哦!!
相關文章
相關標籤/搜索