大神教你用Java中SpringBoot中的全局異常處理

大神教你用Java中SpringBoot中的全局異常處理

在實際項目中,如果出現了異常,我們不希望直接把異常拋給用戶,應該對異常進行處理,然後返回一個友好的信息給用戶。這節主要總結一下項目中如何使用SpringBoot如何攔截全局的異常。

1. 定義返回的json結構

請求接口需要返回json數據,一般後臺會統一定義一個返回給前端的數據結構,包括code、msg信息等,這可以參考【1】SpringBoot返回Json數據及封裝中封裝的統一json結構,如下:

public class JsonResult {

/**

* 異常碼

*/

protected String code;

/**

* 異常信息

*/

protected String msg;

protected JsonResult() {}

public JsonResult(String code, String msg) {

this.code = code;

this.msg = msg;

}

// get set

}

2. 處理系統異常

新建一個GlobalExceptionHandler全局異常處理類,然後加上@ControllerAdvice註解即可攔截項目中拋出的異常,該註解中也可以跟上basePackages屬性,用來指定攔截哪個包中的異常,一般我們可以不指定,所有異常都攔截。

@ControllerAdvice

public class GlobalExceptionHandler {

}

下面舉幾個例子來說明一下如何使用。

2.1 處理不合法的請求格式異常

有些時候,請求格式不合法,會拋出TypeMismatchException,我們可以攔截該異常,做一個友好處理:

@ControllerAdvice

public class GlobalExceptionHandler {

private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

/**

* 不合法的請求格式異常

* @param ex

* @return

*/

@ExceptionHandler(TypeMismatchException.class)

@ResponseStatus(value = HttpStatus.BAD_REQUEST)

@ResponseBody

public JsonResult handleTypeMismatchException(TypeMismatchException ex) {

logger.error("不合法的請求格式", ex);

return new JsonResult("400", "不合法的請求格式");

}

}

2.2 HTTP參數不可讀異常

有些時候,請求參數不合法,會拋出HttpMessageNotReadableException,我們可以攔截該異常,做一個友好處理:

@ControllerAdvice

public class GlobalExceptionHandler {

private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

/**

* HTTP參數不可讀

* @param ex

* @return

*/

@ExceptionHandler(HttpMessageNotReadableException.class)

@ResponseStatus(value = HttpStatus.BAD_REQUEST)

@ResponseBody

public JsonResult handleHttpMessageNotReadableException(

HttpMessageNotReadableException ex) {

logger.error("請求參數不可讀", ex);

return new JsonResult("400", "請求參數不可讀");

}

}

2.3 一勞永逸?

當然了,異常很多,比如還有RuntimeException,數據庫還有一些查詢或者操作異常等等。由於Exception異常是父類,所有異常都會繼承該異常,所以我們可以直接攔截Exception異常:

@ControllerAdvice

public class GlobalExceptionHandler {

private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

/**

* 系統異常 預期以外異常

* @param ex

* @return

*/

@ExceptionHandler(Exception.class)

@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)

@ResponseBody

public JsonResult handleUnexpectedServer(Exception ex) {

logger.error("系統異常:", ex);

return new JsonResult("500", "系統發生異常,請聯繫管理員");

}

}

但是項目中,我們一般都會比較詳細的去攔截一些常見異常,攔截Exception雖然可以一勞永逸,但是不利於我們去排查或者定位問題。實際項目中,可以把攔截Exception異常寫在GlobalExceptionHandler最下面,如果都沒有找到,最後再攔截一下Exception異常,保證輸出信息友好。

3. 攔截自定義異常

在實際項目中,除了攔截一些系統異常外,在某些業務上,我們需要自定義一些異常,比如在微服務中,服務之間的相互調用很平凡,很常見。要處理一個服務的調用,那麼可能會調用失敗,此時我們需要自定義一個異常,當調用失敗時拋出來,給GlobalExceptionHandler去捕獲。

3.1 定義異常信息

由於在業務中,有很多異常,針對不同的業務,可能給出的提示信息不同,所以為了方便項目管理,我們一般會定義一個異常信息枚舉類。

/**

* 業務異常提示信息枚舉類

* @author shengwu ni

*/

public enum BusinessMsgEnum {

/** 參數異常 */

PARMETER_EXCEPTION("102", "參數異常!"),

/** 等待超時 */

SERVICE_TIME_OUT("103", "服務調用超時!"),

/** 參數過大 */

PARMETER_BIG_EXCEPTION("102", "輸入的圖片數量不能超過50張!"),

/** 500 : 一勞永逸的提示也可以在這定義 */

UNEXPECTED_EXCEPTION("500", "系統發生異常,請聯繫管理員!");

// 還可以定義更多的業務異常

/**

* 消息碼

*/

private String code;

/**

* 消息內容

*/

private String msg;

private BusinessMsgEnum(String code, String msg) {

this.code = code;

this.msg = msg;

}

// set get方法

}

3.2 攔截自定義異常

然後我們定義一個業務異常,當出現業務異常時,我們就拋這個自定義的業務異常即可。

/**

* 自定義業務異常

* @author shengwu ni

*/

public class BusinessErrorException extends RuntimeException {

private static final long serialVersionUID = -7480022450501760611L;

/**

* 異常碼

*/

private String code;

/**

* 異常提示信息

*/

private String message;

public BusinessErrorException(BusinessMsgEnum businessMsgEnum) {

this.code = businessMsgEnum.code();

this.message = businessMsgEnum.msg();

}

// get set方法

}

構造方法中,傳入我們上面自定義的異常枚舉類,所以在項目中,如果有信息異常信息,我們直接在枚舉類中添加即可,然後再攔截該異常時獲取即可。

@ControllerAdvice

public class GlobalExceptionHandler {

private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

/**

* 攔截業務異常,返回業務異常信息

* @param ex

* @return

*/

@ExceptionHandler(BusinessErrorException.class)

@ResponseStatus(value = HttpStatus.OK)

@ResponseBody

public JsonResult handleBusinessError(BusinessErrorException ex) {

String code = ex.getCode();

String message = ex.getMessage();

return new JsonResult(code, message);

}

}

在業務代碼中,我們可以直接在拋出業務異常,測試一下:

@RestController

@RequestMapping("/test")

public class TestController {

@RequestMapping("/exception")

public String testException() {

try {

int i = 1 / 0;

} catch (Exception e) {

throw new BusinessErrorException(BusinessMsgEnum.UNEXPECTED_EXCEPTION);

}

return null;

}

}

運行一下項目,測試一下,返回json如下;

{"code":"500","msg":"系統發生異常,請聯繫管理員!"}

SpringBoot的全局異常攔截處理就總結這麼多,在項目中運用也很廣泛,基本上每個項目中都需要全局異常處理。

可獲得兩大新人禮包

36份一線互聯網Java面試電子書

84個Java稀缺面試題視頻


分享到:


相關文章: