SpringBoot系列(十)統(tǒng)一異常處理與統(tǒng)一結(jié)果返回
往期推薦
SpringBoot系列(一)idea新建Springboot項目
SpringBoot系列(四)web靜態(tài)資源配置詳解
Springboot系列(七) 集成接口文檔swagger最仑,使用,測試
SpringBoot系列(八)分分鐘學(xué)會Springboot多種解決跨域方式
目錄
引言:
?日常開發(fā)過程中赠潦,難免有的程序會因為某些原因拋出異常聘鳞,而這些異常一般都是利用try ,catch的方式處理異常或者throw析蝴,throws的方式拋出異常不管撩匕。這種方法對于程序員來說處理也比較麻煩鹰晨,對客戶來說也不太友好,所以我們希望既能方便程序員編寫代碼止毕,不用過多的自己去處理各種異常編寫重復(fù)的代碼又能提升用戶的體驗模蜡,這時候全局異常處理就顯得很重要也很便捷了,是一種不錯的選擇扁凛。
1. 全局異常捕獲與處理
?因為現(xiàn)在主流的都是前后端分離的項目忍疾,所以我們的異常處理也根據(jù)前后端分離來講述。
?Springboot對于異常的處理也做了不錯的支持谨朝,它提供了一個 @ControllerAdvice注解以及 @ExceptionHandler注解卤妒,前者是用來開啟全局的異常捕獲甥绿,后者則是說明捕獲哪些異常,對那些異常進行處理则披。
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(value =Exception.class)
public String exceptionHandler(Exception e){
System.out.println("發(fā)生了一個異常"+e);
return e.getMessage();
}
}
?上面這段代碼就是說共缕,只要是代碼運行過程中有異常就會進行捕獲,并輸出出這個異常士复。然后我們隨便編寫一個會發(fā)生異常的代碼图谷,測試出來的異常是這樣的。
?這對于我們前后端分離來說并不好阱洪,前后端分離之后唯一的交互就是json了便贵,我們也希望將后端的異常變成json返回給前端處理。下面我們看看統(tǒng)一結(jié)果處理冗荸。
2. 統(tǒng)一結(jié)果返回與統(tǒng)一異常
代碼:
public class Result<T> {
//是否成功
private Boolean success;
//狀態(tài)碼
private Integer code;
//提示信息
private String msg;
//數(shù)據(jù)
private T data;
public Result() {
}
//自定義返回結(jié)果的構(gòu)造方法
public Result(Boolean success,Integer code, String msg,T data) {
this.success = success;
this.code = code;
this.msg = msg;
this.data = data;
}
//自定義異常返回的結(jié)果
public static Result defineError(DefinitionException de){
Result result = new Result();
result.setSuccess(false);
result.setCode(de.getErrorCode());
result.setMsg(de.getErrorMsg());
result.setData(null);
return result;
}
//其他異常處理方法返回的結(jié)果
public static Result otherError(ErrorEnum errorEnum){
Result result = new Result();
result.setMsg(errorEnum.getErrorMsg());
result.setCode(errorEnum.getErrorCode());
result.setSuccess(false);
result.setData(null);
return result;
}
}
?說明:其中省略了get承璃,set方法。另外方法之中包含了一個自定義的枚舉俏竞。代碼如下:
public enum ErrorEnum {
// 數(shù)據(jù)操作錯誤定義
SUCCESS(200, "nice"),
NO_PERMISSION(403,"你沒得權(quán)限"),
NO_AUTH(401,"你能不能先登錄一下"),
NOT_FOUND(404, "未找到該資源!"),
INTERNAL_SERVER_ERROR(500, "服務(wù)器跑路了"),
;
/** 錯誤碼 */
private Integer errorCode;
/** 錯誤信息 */
private String errorMsg;
ErrorEnum(Integer errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public Integer getErrorCode() {
return errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
}
?說明:枚舉類中定義了常見的錯誤碼以及錯誤的提示信息绸硕。
這里我們就定義好了統(tǒng)一的結(jié)果返回,其中里面的靜態(tài)方法是用來當(dāng)程序異常的時候轉(zhuǎn)換成異常返回規(guī)定的格式魂毁。
?然后我們需要自定義異常處理類玻佩。代碼如下:
public class DefinitionException extends RuntimeException{
protected Integer errorCode;
protected String errorMsg;
public DefinitionException(){
}
public DefinitionException(Integer errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public Integer getErrorCode() {
return errorCode;
}
public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
?其中包含了錯誤的狀態(tài)碼,錯誤的提示信息席楚。然后我們可以自定義一個全局異常處理類咬崔,來處理各種異常,包括自己定義的異常和內(nèi)部異常。這樣可以簡化不少代碼烦秩,不用自己對每個異常都使用try垮斯,catch的方式來實現(xiàn)。
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 處理自定義異常
*
*/
@ExceptionHandler(value = DefinitionException.class)
@ResponseBody
public Result bizExceptionHandler(DefinitionException e) {
return Result.defineError(e);
}
/**
* 處理其他異常
*
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result exceptionHandler( Exception e) {
return Result.otherError(ErrorEnum.INTERNAL_SERVER_ERROR);
}
}
?說明:每個方法上面加上一個 @ResponseBody的注解只祠,用于將對象解析成json,方便前后端的交互兜蠕,也可以使用 @ResponseBody放在異常類上面。
3. controller代碼測試與結(jié)果
?controller代碼:
@RestController
@RequestMapping("/result")
public class ResultController {
@GetMapping("/getStudent")
public Result getStudent(){
Student student = new Student();
student.setAge(21);
student.setId(111);
student.setName("學(xué)習(xí)筆記");
Result result = new Result();
result.setCode(200);
result.setSuccess(true);
result.setData(student);
result.setMsg("學(xué)生列表信息");
return result;
}
@RequestMapping("/getDeException")
public Result DeException(){
throw new DefinitionException(400,"我出錯了");
}
@RequestMapping("/getException")
public Result Exception(){
Result result = new Result();
int a=1/0;
return result;
}
}
?其中的Student類就是前面一直在用的類了抛寝。包含三個屬性熊杨。其中省略了get,set方法盗舰。
public class Student {
/**
* 唯一標(biāo)識id
*/
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 年齡
*/
private Integer age;
}
?然后啟動項目晶府,來挨個測試。首先測試正常沒有異常發(fā)生的數(shù)據(jù)钻趋。
瀏覽器輸入:localhost:8095/result/getStudent
?可以看到數(shù)據(jù)是正常返回json串川陆。沒有異常。
然后我們測試第二個自定義異常處理接口蛮位。瀏覽器輸入localhost:8095/result/getDeException较沪。
?可以看到這個自定義的異常是捕獲到了鳞绕,并且返回了一個json串。
最后我們測試一下其他的異常尸曼。瀏覽器輸入:localhost:8095/result/getException
?到這里我們就處理完了異常并且正確的返回了前端猾昆。
這里說一下,測試接口又很多方法骡苞,可以使用postman,或者idea自帶的接口測試工具都很好用楷扬。
?但是解幽,你可能會發(fā)現(xiàn)一個問題,這種方法是不能處理404異常的烘苹,捕獲不到躲株。該怎么辦呢?
4. 404異常特殊處理镣衡。
?默認情況下霜定,SpringBoot是不會拋出404異常的,所以@ControllerAdvice也不能捕獲到404異常廊鸥。我們可以通過以下配置來讓這個注解能捕獲到404異常望浩。
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
其中第一句是表示:當(dāng)發(fā)現(xiàn)404異常時直接拋出異常。第二句關(guān)閉默認的靜態(tài)資源路徑映射惰说。這樣404錯誤也能被捕獲到磨德,但是這個配置會讓你的靜態(tài)資源訪問出現(xiàn)問題,也就是不適合前后端不分離的情況吆视。
5. 總結(jié)
?本文講解了如何處理捕獲全局異常以及怎么自定義異常典挑,順便說明了統(tǒng)一結(jié)果的返回格式,并特殊處理的404啦吧,not found的異常您觉,將其作為統(tǒng)一結(jié)果返回。如果你覺得本文有用授滓,點個贊吧琳水!