@[toc]
前言
- 在我們開發中,總會碰到一些異常 ---------- 運行時異常(不受檢異常):RuntimeException類極其子類表示JVM在運行期間可能出現的錯誤。編譯器不會檢查此類異常,並且不要求處理異常,比如用空值對象的引用(NullPointerException)、數組下標越界(ArrayIndexOutBoundException)。此類異常屬於不可查異常,一般是由程序邏輯錯誤引起的,在程序中可以選擇捕獲處理,也可以不處理。
- 對於這些異常,如果返回給前端,會給用戶代碼很不好的體驗,因為用戶不知道 NullPointerException 等異常的意思,只會吐槽我們的項目,嚴重會導致用戶流失,下面我們優雅的解決程序運行中的一場
-
設計
## 1. 自定義枚舉類
-
使用枚舉統一管理我們的錯誤信息
-
enum ResultEnum {
UNKNOWN_ERROR(-100, "未知錯誤"),
NEED_LOGIN(-1, "未登錄"),
REPEAT_REGISTER(-2, "該用戶已註冊"),
USER_NOT_EXIST(-3, "不存在該用戶"),
PASSWORD_ERROR(-4, "密碼錯誤"),
EMPTY_USERNAME(-5, "用戶名為空"),
EMPTY_PASSWORD(-6, "密碼為空"),
SUCCESS(0, "success"),
SYSTEM_ERROR(500,"手速太快了,慢點");private Integer code;
private String msg;
private ResultEnum(Integer code, String msg) {
this.code = code; this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
2. 自定義異常
package com.yxl.exception;
import com.yxl.enums.ResultEnum;
/**
* @Author:byteblogs
* @Date:2018/09/27 12:52
*/
public class BusinessException extends RuntimeException {
private int code;
private String errMsg;
public BusinessException(ResultEnum resultEnum){
this.code = resultEnum.getCode();
this.errMsg = resultEnum.getMsg();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
}
3. 異常全局處理
- 創建handler文件夾
-
新增ExcepetionHandler類
- 加入 @ControllerAdvice 註解
- 對於@ControllerAdvice,我們比較熟知的用法是結合@ExceptionHandler用於全局異常的處理,但其作用不僅限於此。ControllerAdvice拆分開來就是Controller
Advice,關於Advice,前面我們講解SpringAop時講到,其是用於封裝一個切面所有屬性的,包括切入點和需要織入的切面邏輯。這裡ContrllerAdvice也可以這麼理解,其抽象級別應該是用於對Controller進行“切面”環繞的,而具體的業務織入方式則是通過結合其他的註解來實現的。@ControllerAdvice是在類上聲明的註解,其用法主要有三點:
結合方法型註解@ExceptionHandler,用於捕獲Controller中拋出的指定類型的異常,從而達到不同類型的異常區別處理的目的;
處理全局異常
- ResultBody 是返回的項目統一格式
package com.yxl.handler;
import com.yxl.enums.ResultEnum;
import com.yxl.exception.BusinessException;
import com.yxl.po.ResponseMessage;
import com.yxl.po.ResultBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;
@ControllerAdvice
public class ExceptionHandler {
private final static Logger logger= LoggerFactory.getLogger(ExceptionHandler.class);
/**
* 處理其他異常
* @param e
* @return
*/
@org.springframework.web.bind.annotation.ExceptionHandler(value = Exception.class)
@ResponseBody
public ResponseMessage handel(Exception e){
if(e instanceof BusinessException){
BusinessException myException =(BusinessException)e;
return ResultBody.error( myException.getCode(),myException.getMessage());
}else {
logger.error("[系統異常] {}",e);
return ResultBody.error(ResultEnum.SYSTEM_ERROR);
}
}
/**
* 處理BusinessException異常
* @param e
* @return
*/
@org.springframework.web.bind.annotation.ExceptionHandler(value = BusinessException.class)
@ResponseBody
public ResponseMessage busin(BusinessException e) {
return ResultBody.error(e.getCode(), e.getErrMsg());
}
/**
* 處理空指針的異常
*
* @param req
* @param e
* @return
*/
@org.springframework.web.bind.annotation.ExceptionHandler(value = NullPointerException.class)
@ResponseBody
public ResponseMessage exceptionHandler(HttpServletRequest req, NullPointerException e) {
logger.error("發生空指針異常!原因是:", e);
return ResultBody.error(ResultEnum.SYSTEM_ERROR);
}
/**
* 處理參數校驗異常
*
* @param req
* @param e
* @return
*/
@org.springframework.web.bind.annotation.ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseBody
public ResponseMessage exceptionHandler(HttpServletRequest req, MethodArgumentNotValidException e) {
logger.error("參數校驗異常:", e);
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
return ResultBody.error(ResultEnum.SYSTEM_ERROR);
}
/**
* 處理參數校驗異常 --Json 轉換異常
* @param req
* @param e
* @return
*/
@org.springframework.web.bind.annotation.ExceptionHandler(value = HttpMessageNotReadableException.class)
@ResponseBody
public ResponseMessage exceptionHandler(HttpServletRequest req, HttpMessageNotReadableException e) {
logger.error("參數校驗異常-json轉換異常:", e);
return ResultBody.error(ResultEnum.SYSTEM_ERROR);
}
}
4. 使用
@GetMapping("/test2")
public ResponseMessage test2(@ApiParam(value = "id")@RequestParam(required = false) Long id) {
//如果等於空拋出異常
if(Objects.isNull(id)){
throw new BusinessException(ResultEnum.EMPTY_USERNAME);
}
return ResultBody.success();
}
- 結果 拋出了我們自定義的枚舉異常