SpringMVC入門之十:異常的優化處理


處理異常


在請求的過程中,錯誤往往是不可避免的,那麼發生異常時,該給客戶端什麼響應呢?Servlet請求的輸出和輸入均是一個Servlet響應。因此,異常必須要以某種方式轉換為響應。Spring提供多種方式將異常轉換為響應:



  • a、特定的Spring異常將會自動映射為指定的HTTP狀態碼。

  • [email protected],從而將其映射為某一個HTTP狀態碼;

  • [email protected],使其用來處理異常。


將異常映射為HTTP狀態碼


Spring提供瞭一種機制,[email protected]��實例如下;

在SpittleController中通常會有一個根據ID查詢用戶的處理器方法,如下:


@RequestMapping(value="/{spittleId}",method=GET)
public String spittle(@PathVariable("spittleId") long spittleId, Model model){
Spittle spittle=spittleRepository.findOne(spittleId);
if(spittle == null)
{
throw new SpittleNotFoundException();
}
model.addAttribute(spittle);
return "spittle";
}

需要註意的是當spittle為空的時候,會拋出一個SpittleNotFoundException()異常,這個異常是我們自定義的異常:


package spittr.exception;
public class SpittleNotFoundException extends RuntimeException{}

如果調用spittle()方法來處理請求,並且給定ID獲取到的結果為空,那麼SpittleNotFoundException(默認)將會產生500狀態碼(Internal Server Error)的響應。實際上,如果出現任何沒有映射的異常,響應都會帶有500狀態碼,但是,我們可以通過映射SpittleNotFoundException對這種默認行為進行變更。

當拋出SpittleNotFoundException異常時,這是一種請求資源沒有找到的場景。如果資源沒有找到的話,HTTP狀態碼404是最為精確的響應狀態碼。所以,[email protected]�射為HTTP狀態碼404。


package spittr.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="Spittle Not Found")
public class SpittleNotFoundException extends RuntimeException{}

[email protected],如果控制器方法拋出SpittleNotFoundException異常的話,響應將會具有404狀態碼,這是因為SpittleNotFound。


編寫異常處理的方法


假設有這樣一個場景,用戶視圖創建的Spittle與已創建的Spittle文本完全相同,那麼SpittleRepository的save()方法將會拋出DuplicateSpittle Exception異常。這意味著SpittleController的saveSpittle()方法可能需要處理這個異常。如下的程序清單處理瞭這個異常:


public String saveSpittle(SpittleForm form,Model model){
try{
spittleRepository.save(new Spittle(null,form.getMessage(),new Date(),form.getLongitude(),form.getLatitude()));
return "redirect:/spittles";
}catch(DuplicateSpittleException e)
{
return "error/duplicate";
}
}

這是java中處理異常的樣例,但是這樣讓代碼看起來很冗雜,並且讓方法多瞭一個路徑。如果能讓saveSpittle()方法之關註正確的路徑,而讓其他方法處理異常的話,那麼它就能簡單一些。

現在我們想將saveSpittle()方法中的異常處理方法剝離掉:


public String saveSpittle(SpittleForm form,Model model){
spittleRepository.save(new Spittle(null,form.getMessage(),new Date(),form.getLongitude(),form.getLatitude()));
return "redirect:/spittles";
}

這樣,該方法就可以隻關註正確的邏輯。現在,我們為SpittleController添加一個新的方法,它會處理拋出DuplicateSpittleException的情況:


@ExceptionHandler(DuplicateSpittleException.class)
public String handleDuplicateSpittle(){
return "error/duplicate";
}

當該控制器中的任意一個方法拋出瞭DuplicateSpittleException後,都會委托該方法來處理。我們不用在每一個可能拋出該異常的地方添加異常處理方法,這樣無疑能省去不少的冗餘代碼,我們的代碼看起來也會更加整潔。

那麼,更進一步,既然已經有覆蓋一個控制器的公用異常處理方法瞭,那有沒有覆蓋所有控制器的異常處理方法呢?答案是肯定的,我們隻需要將其定義到控制器通知類中即可。


為控制器添加通知


如果控制器的特定切面能夠運用到整個應用程序的所有控制器中,那麼這將會便利很多。控制器通知(Controller advice)[email protected],這個類會包含一個或多個如下類型的方法:



  • [email protected];

  • [email protected];

  • [email protected]

    [email protected],[email protected]�[email protected]@[email protected],一次可以被自動掃描獲取到。

    @[email protected]eptionHandler方法收集到一個類中,這樣所有控制器的異常就能在一個地方進行一致的處理。如下程序1清單所示:



package spitter.web;
import rog.springframework.web.bind.annotation.ControllerAdvice;
@ControllerAdvice
public class webWideExceptionHandler{
@ExceptionHandler(DuplicateSpittleException,class)
public String duplicateSpittleHandler(){
return "error/duplicate";
}
}

現在,如果任意的控制器方法拋出瞭DuplicateSpittleException,不管這個方法位於哪個控制器中,都會調用這個duplicateSpittleHandler()方法來處理異常。




上一篇:SpringMVC入門之九:multipart文件上傳

下一篇:SpringMVC入門之十一:跨重定向請求傳遞數據

0 個評論

要回覆文章請先登錄註冊