前言
本文講解使用 @ControllerAdvice + @ExceptionHandler 進行全局的 Controller 層異常處理,可以處理大部分開發中用到的自自定義業務異常處理了,避免在Controller 層進行 try-catch
代碼示例地址(代碼里面類名稍微有些不同): https://gitee.com/coderLOL/springboot-demos
一、處理思路
- 思路:在sevice業務邏輯層 try{}catch(){} 捕獲拋出,經由contorller 層拋到 自定義全局處理類 中處理自定義異常及系統異常。
2、實現方式:使用 @RestControllerAdvice + @ExceptionHandler 注解方式實現全局異常處
二、實現過程
1、@ControllerAdvice 注解定義全局異常處理類 ,@ExceptionHandler 注解聲明異常處 理方法。
( 本類方法中用到的 ResponseResultUtil 工具類, ResponseCodeEnum 枚舉類,下面步驟中會介紹)
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* @author 路飛
* @date 2018-8-21
* @description 全局異常處理: 使用 @RestControllerAdvice + @ExceptionHandler 注解方式實現全
* 局異常處理
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
private final Logger logger = LogManager.getLogger(GlobalExceptionHandler.class);
/**
* @author 路飛
* @date 2018-8-22
* @param e 異常
* @description 處理所有不可知的異常
*/
@ExceptionHandler({Exception.class}) //申明捕獲那個異常類
public ResponseResultVO globalExceptionHandler(Exception e) {
this.logger.error(e.getMessage(), e);
return new ResponseResultUtil().error(ResponseCodeEnum.OPERATE_FAIL);
}
/**
* @author 路飛
* @date 2018-8-21
* @param e 異常
* @description 處理所有業務異常
*/
@ExceptionHandler({BaseBusinessException.class})
public ResponseResultVO BusinessExceptionHandler(BaseBusinessException e) {
this.logger.error(e);
return new ResponseResultUtil().error(e.getCode(), e.getMessage());
}
}
2、定義一個用於返回頁面結果信息的VO對象類:ResponseResultVO
/**
* @author 路飛
* @date 2018-8-21
* @description 請求響應對象
*/
public final class ResponseResultVO<T> {
/**
* @description 響應碼
*/
private int code;
/**
* @description 響應消息
*/
private String message;
/**
* @description 分頁對象 (如果用不到,這個可以不寫)
*/
private PageVO page;
/**
* @description 數據
*/
private Object data;
public final int getCode() {
return this.code;
}
public final void setCode(int code) {
this.code = code;
}
public final String getMessage() {
return this.message;
}
public final void setMessage( String message) {
this.message = message;
}
public final PageVO getPage() {
return this.page;
}
public final void setPage( PageVO page) {
this.page = page;
}
public final Object getData() {
return this.data;
}
public final void setData(Object data) {
this.data = data;
}
public ResponseResultVO(int code, String message, PageVO page, Object data) {
super();
this.code = code;
this.message = message;
this.page = page;
this.data = data;
}
}
3、 定義一個對步驟2中 返回信息結果處理的工具類:ResponseResultUtil
/**
* @author zhangwenlong
* @date 2018-8-20
* @description 請求響應工具類
*/
public final class ResponseResultUtil {
/**
* @param code 響應碼
* @param message 相應信息
* @param any 返回的數據
* @description 請求成功返回對象
*/
public final ResponseResultVO success(int code, String message, PageVO page, Object any) {
return new ResponseResultVO(code, message, page, any);
}
/**
* @param any 返回的數據
* @description 請求成功返回對象
*/
public final ResponseResultVO success(Object any) {
int code = ResponseCodeEnum.SUCCESS.getCode();
String message = ResponseCodeEnum.SUCCESS.getMessage();
return this.success(code, message, null, any);
}
/**
* @param any 返回的數據
* @description 請求成功返回對象
*/
public final ResponseResultVO success(Object any, PageVO page) {
int code = ResponseCodeEnum.SUCCESS.getCode();
String message = ResponseCodeEnum.SUCCESS.getMessage();
return this.success(code, message, page, any);
}
/**
* @description 請求成功返回對象
*/
public final ResponseResultVO success() {
return this.success(null);
}
/**
* @param responseCode 返回的響應碼所對應的枚舉類
* @description 請求失敗返回對象
*/
public final ResponseResultVO error(ResponseCodeEnum responseCode) {
return new ResponseResultVO(responseCode.getCode(), responseCode.getMessage(), null, null);
}
/**
* @param code 響應碼
* @param message 相應信息
* @description 請求失敗返回對象
*/
public final ResponseResultVO error(int code, String message) {
return new ResponseResultVO(code, message, null, null);
}
}
4、為方便統一管理異常代碼和信息之間的關系,建立枚舉類: ResponseCodeEnum
/**
* @author 路飛
* @date 2018-8-20
* @description 響應碼配置枚舉
*/
public enum ResponseCodeEnum {
// 系統通用
SUCCESS(200, "操作成功"),
UNLOGIN_ERROR(233, "沒有登錄"),
OPERATE_FAIL(666, "操作失敗"),
// 用戶
SAVE_USER_INFO_FAILED(2001, "保存用戶信息失敗"),
GET_USER_INFO_FAILED(2002, "保存用戶信息失敗"),
WECHAT_VALID_FAILED(2003, "微信驗證失敗"),
GET_USER_AUTH_INFO_FAILED(2004, "根據條件獲取用戶授權信息失敗"),
SAVE_USER_AUTH_INFO_FAILED(2005, "保存用戶授權失敗");
private Integer code;
private String message;
ResponseCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
public final Integer getCode() {
return this.code;
}
public final String getMessage() {
return this.message;
}
}
5、
(1)封裝一個基礎業務異常類(讓所有自定義業務異常類 繼承此 基礎類):BaseBusinessException
/**
* @author zhangwenlong
* @date 2018-8-21
* @description 價值分析系統所有的 業務異常父類
*/
public class BaseBusinessException extends RuntimeException {
private Integer code;
// 給子類用的方法
public BaseBusinessException(ResponseCodeEnum responseCodeEnum) {
this(responseCodeEnum.getMessage(), responseCodeEnum.getCode());
}
private BaseBusinessException(String message, Integer code) {
super(message);
this.code = code;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
(2)自定義的業務異常類 (例如):
自定義用戶異常
/**
* @author 路費
* @date 2018-8-21
* @description 自定義用戶異常
*/
public class UserException extends BaseBusinessException { // 繼承繼承 業務異常類
public UserException(ResponseCodeEnum responseCodeEnum) {
super(responseCodeEnum);
}
}
6、service 層拋出
/**
* @author 路飛
* @date 2018-8-21
* @description 用戶信息業務接口實現類
*/
@Service("userInfoService")
public class UserInfoSerimpl implements UserInfoService {
private Logger logger = LoggerFactory.getLogger(UserInfoSerimpl.class);
@Resource
private UserInfoMapper userInfoMapper; // maybatis通用Mapper插件
/**
* @author 路飛
* @date 2018-8-21
* @param userInfo 用戶信息
* @description 保存用戶信息
*/
@Override
public void saveUserInfo(UserInfo userInfo) {
try {
userInfoMapper.insertSelective(userInfo);
} catch (Exception e) {
logger.error("獲取用戶信息失敗", e);
//拋出自定義異常: ResponseCodeEnum.SAVE_USER_INFO_FAILED
throw new UserException(ResponseCodeEnum.SAVE_USER_INFO_FAILED);
}
}
}
后續會提供代碼實例及下載地址。。。