全局異常處理:
controller
層拋出的自定義異常時,可以實現@ControllerAdvice
注解捕獲,配合@ExceptionHandler來增強所有的@requestMapping方法。
@ExceptionHandler
:統一處理某一類異常,從而能夠減少代碼重復率和復雜度該注解作用對象為方法,並且在運行時有效,
value()
可以指定異常類。異常參數:包括一般的異常或特定的異常(即自定義異常),如果注解沒有指定異常類,會默認進行映射。
@ControllerAdvice
:異常集中處理,更好的使業務邏輯與異常處理剝離開
例如:@ExceptionHandler(Exception.class) 用來捕獲@requestMapping的方法中所有拋出的exception。
代碼:
@ControllerAdvice
public class GlobalDefultExceptionHandler {
//聲明要捕獲的異常
@ExceptionHandler(Exception.class)
@ResponseBody
public String defultExcepitonHandler(HttpServletRequest request,Exception e) {
return “error”;
}
}
這樣,全局異常處理類完畢。可以添加自己的邏輯。
然后還有一個問題,有的時候,我們需要業務邏輯時拋出自定義異常,這個時候需要自定義業務異常類。
定義class:BusinessException ,使他繼承於RuntimeException.
說明:因為某些業務需要進行業務回滾。但spring的事務只針對RuntimeException的進行回滾操作。所以需要回滾就要繼承RuntimeException。
public class BusinessException extends RuntimeException{
}
然后,現在來稍微完善一下這個類。
當我們拋出一個業務異常,一般需要錯誤碼和錯誤信息。有助於我們來定位問題。
所以如下:
1.首先定義一個枚舉類型,把錯誤碼及錯誤信息,組裝起來統一管理。
定義一個業務異常的枚舉。
public enum ResultEnum {
CODE_200("200", ""),
CODE_400("400", "錯誤的請求參數"),
CODE_401("401", "沒有登錄"),
//CODE_402("402", "用戶名或密碼錯誤"),
CODE_403("403", "沒有權限"),
//CODE_404("404", "用戶不存在"),
CODE_405("405", "用戶被凍結"),
//CODE_406("406", "信息重復"),
CODE_500("500", "內部服務器錯誤");
private Integer code;
private String msg;
ResultEnum(Integer code,String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
2.然后定義一個業務異常。
public class BusinessException extends RuntimeException{
private static final long serialVersionUID = 1L;
private Integer code; //錯誤碼
public BusinessException() {}
public BusinessException(ResultEnum resultEnum) {
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
3.定義一個全局異常處理類:
@ControllerAdvice
public class GlobalDefultExceptionHandler {
// 根據特定的異常返回指定的 HTTP 狀態碼400
@ResponseStatus(value=HttpStatus.BAD_REQUEST) // 400
@ExceptionHandler(ConstraintViolationException.class)
public ModelAndView handleValidationException(ConstraintViolationException e) {
logger.error(e.getMessage(),e);
Set<ConstraintViolation<?>> errors = e.getConstraintViolations();
return ResultUtil.error(ResultEnum.CODE_400,errors.toString());
}
// 捕捉shiro的異常
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(ShiroException.class)
public ModelAndView handleShiroException(HttpServletResponse resp,HttpServletRequest req,ShiroException e) {
logger.error(e.getMessage(),e);
Object errorMassage = req.getAttribute("error"); //取出shiro異常massage
if(errorMassage !=null) { //返回jwt過濾器異常.(這里只是替換錯誤Massage而已)
return getRedirect(ResultUtil.error(ResultEnum.CODE_401,errors.toString()));
}
return ResultUtil.error(ResultEnum.CODE_401,errors.toString());
}
// 捕捉UnauthorizedException
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(UnauthorizedException.class)
public ModelAndView handleUnauthorizedException(HttpServletResponse resp,HttpServletRequest req,UnauthorizedException e) {
logger.error(e.getMessage(),e);
return ResultUtil.error(ResultEnum.CODE_403,errors.toString());
}
//聲明要捕獲的異常(自定義異常和Exception)
@ExceptionHandler(Exception.class)
@ResponseBody
public <T> Result<?> defultExcepitonHandler(HttpServletRequest request,Exception e) {
e.printStackTrace();
if(e instanceof BusinessException) {
Log.error(this.getClass(),"業務異常:"+e.getMessage());
BusinessException businessException = (BusinessException)e;
return ResultUtil.error(businessException.getCode(), businessException.getMessage());
}
//未知錯誤
return ResultUtil.error(-1, "系統異常:\\n"+e);
}
}
判斷這個是否是業務異常。和系統異常就可以分開處理了。