@ResponseStatus
處理自定義異常try {…} catch
手動捕獲異常@ExceptionHandler
處理自定義異常@ControllerAdvice
註解處理全部的異常在Spring中,有一些異常會默認映射爲HTTP狀態碼,不須要程序處理。下表列出Spring的默認處理異常:java
Spring異常 | HTTP狀態碼 |
---|---|
BindException | 400 - Bad Request |
ConversionNotSupportedException | 500 - Internal Server Error |
HttpMediaTypeNotAcceptableException | 406 - Not Acceptable |
HttpMediaTypeNotSupportedException | 415 - Unsupported Media Type |
HttpMessageNotReadableException | 400 - Bad Request |
HttpMessageNotWritableException | 500 - Internal Server Error |
HttpRequestMethodNotSupportedException | 405 - Method Not Allowed |
MethodArgumentNotValidException | 400 - Bad Request |
MissingServletRequestParameterException | 400 - Bad Request |
MissingServletRequestPartException | 400 - Bad Request |
NoSuchRequestHandlingMethodException | 404 - Not Found |
TypeMismatchException | 400 - Bad Request |
上表中的異常會由Spring自身拋出,若是DispatcherServlet
處理過程當中或執行校驗時出現問題時則直接返回。例如,若是DispatcherServlet
沒法找到適合處理請求的控制器方法,那麼將會拋出NoSuchRequestHandlingMethodException
異常,最終的結果就是產生404狀態碼的響應(Not Found)。web
@ResponseStatus
處理自定義異常但對於應用程序內部拋出的自定義異常,它就不能處理了。好比service中拋出了一個自定義異常(NullOrgException
),咱們對NullOrgException
異常添加@ResponseStatus
註解,對其指定狀態碼便可。spring
以下面的代碼:mvc
package com.rebecca.springmvc.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/** * 自定義異常 * @Author: Rebecca * @Description: * @Date: Created in 2019/6/14 17:04 * @Modified By: */
@ResponseStatus(value = HttpStatus.NO_CONTENT, reason = "No Content")
public class NullOrgException extends RuntimeException {
}
複製代碼
try {…} catch
手動捕獲異常定義了上述異常後,只要應用程序中有拋出NullOrgException
異常,就會被捕獲並映射爲對應的狀態碼。那麼若是程序不單單須要狀態碼,還要包含所產生的錯誤,那該怎麼辦呢?此時的話,咱們就不能將異常視爲HTTP錯誤了,而是要按照處理請求的方式來處理異常了。app
package com.rebecca.springmvc.controller.exception;
import com.rebecca.springmvc.org.bean.Org;
import com.rebecca.springmvc.org.service.OrgService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("test/exception")
public class ExceptionTestController {
private Logger logger = LoggerFactory.getLogger(ExceptionTestController.class);
@Autowired
private OrgService service;
@RequestMapping(value = "orgs", method = RequestMethod.GET)
@ResponseBody
public List<Org> getOrgs () {
List<Org> orgs = null;
try {
orgs = service.getOrgs();
} catch (NullOrgException e) {
logger.error("無組織機構相關數據!",e);
}
return orgs;
}
}
複製代碼
好比上面代碼中的NullOrgException
異常,在Spring中沒有默認映射,那最簡單的辦法就是try {…} catch (NullOrgException e) {…}
。ide
@ExceptionHandler
處理自定義異常上述try {…} catch
方式不利於代碼維護,好在Spring提供了一種機制,能夠用@ExceptionHandler
註解將異常映射爲HTTP狀態碼。下面是使用@ExceptionHandler
註解後的方式:spa
package com.rebecca.springmvc.controller.exception;
import com.rebecca.springmvc.org.bean.Org;
import com.rebecca.springmvc.org.service.OrgService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("test/exception")
public class ExceptionTestController {
private Logger logger = LoggerFactory.getLogger(ExceptionTestController.class);
@Autowired
private OrgService service;
@RequestMapping(value = "orgs", method = RequestMethod.GET)
@ResponseBody
public List<Org> getOrgs () {
List<Org> orgs = service.getOrgs();
return orgs;
}
@ExceptionHandler(NullOrgException.class)
public String handleNullOrgException() {
return "無組織機構相關數據!";
}
}
複製代碼
上面代碼咱們在handleNullOrgException()
方法上添加了@ExceptionHandler
註解,當程序拋出NullOrgException
異常時,將會委託該方法來處理。它的返回值是String,你也能夠改成其它的返回類型以知足應用程序須要。對於用@ExceptionHandler
註解標註的方法來講,它能處理同一個控制器(Controller)中全部處理器方法所拋出的異常。code
爲了不在多個控制器中編寫重複的@ExceptionHandler
註解方法,咱們會建立一個基礎的控制器類,全部控制器類要擴展這個類,從而 繼承 通用的@ExceptionHandler
方法。繼承
@ControllerAdvice
註解處理全部的異常前面咱們說使用@ExceptionHandler
註解只能處理一個控制器(Controller)中全部處理器方法所拋出的異常,那麼有沒有一種方法不用集成就可以處理全部控制器中處理器方法所拋出的異常呢?ip
答案是:有!從Spring 3.2開始,這確定是可以實現的,咱們只需將其定義到控制器通知類中便可。
在Spring 3.2以後,爲這類問題引入了一個新的解決方案:控制器通知。
控制器通知(controller advice)是指任意帶有@ControllerAdvice
註解的類。
這個類會包含一個或多個以下類型的方法:
@ExceptionHandler
註解標註的方法;@InitBinder
註解標註的方法;@ModelAttribute
註解標註的方法。在帶有@ControllerAdvice
註解的類中,上述的這些方法會運用到整個應用程序全部控制器中帶有@RequestMapping
註解的方法上。@ControllerAdvice
註解自己已經使用了@Component
,所以@ControllerAdvice
註解所標註的類將會自動被組件掃描獲取到,和有@Component
註解的類同樣。@ControllerAdvice
最爲實用的一個場景就是將全部的@ExceptionHandler
方法收集到一個類中,這樣全部控制器的異常就能在一個地方進行統一處理。例如,咱們想將NullOrgException
的處理方法用到整個應用程序的全部控制器上。以下的程序清單展示的AppWideExceptionHandler
就能完成這一任務,這是一個帶有@ControllerAdvice
註解的類。下面代碼使用@ControllerAdvice
,爲全部的控制器處理異常:
package com.rebecca.springmvc.controller.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/** * 控制器通知類 * @Author: Rebecca * @Description: * @Date: Created in 2019/6/14 16:30 * @Modified By: */
@ControllerAdvice // 定義控制器類
public class AppWideException {
// 定義異常處理方法
@ExceptionHandler(NullOrgException.class)
public String handleNullOrgException() {
return "無組織機構相關數據!";
}
}
複製代碼
如今,若是任意的控制器方法拋出了DuplicateSpittleException,無論這個方法位於哪一個控制器中,都會調用這個duplicateSpittleHandler()方法來處理異常。咱們能夠像編寫@RequestMapping註解的方法那樣來編寫@ExceptionHandler註解的方法。如程序清單7.10所示,它返回「error/duplicate」做爲邏輯視圖名,所以將會爲用戶展示一個友好的出錯頁面。
Spring中的異常處理:
@ResponseStatus
註解,從而將其映射爲某一個HTTP狀態碼;@ExceptionHandler
註解,使其用來處理異常。@ExceptionHandler
註解的異常方法提取到@ControllerAdvice
註解的類中,整個應用程序生效(該方式只適用於Spring3.2+)。處理異常的最簡單方式就是將其映射到HTTP狀態碼上,進而放到響應之中。
《Spring實戰第4版》