1. 程式人生 > >全局異常方式處理自定義異常 @RestControllerAdvice + @ExceptionHandler

全局異常方式處理自定義異常 @RestControllerAdvice + @ExceptionHandler

不可 end vat 信息 actor 頁面 ech opera 方式

前言

本文講解使用 @ControllerAdvice + @ExceptionHandler 進行全局的 Controller 層異常處理,可以處理大部分開發中用到的自自定義業務異常處理了,再也不用在 Controller 層進行 try-catch 了
文章結尾附帶項目代碼示例下載地址

一、處理思路

  1. 思路:在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-27
 * @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-27
 * @description  自定義用戶異常
 */
public class UserException extends BaseBusinessException { // 繼承繼承 業務異常類
    public UserException(ResponseCodeEnum responseCodeEnum) {
        super(responseCodeEnum);
    }
}

6、service 層拋出

/**
 * @author 路飛
 * @date 2018-8-27
 * @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-27
     * @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); 
        }
    }

}

後續會提供代碼實例及下載地址。。。

全局異常方式處理自定義異常 @RestControllerAdvice + @ExceptionHandler