Java統(tǒng)一異常處理(配置文件集中化定義)

作者:xcbeyond
瘋狂源自夢(mèng)想,技術(shù)成就輝煌!微信公眾號(hào):《程序猿技術(shù)大咖》號(hào)主,專注后端開(kāi)發(fā)多年,擁有豐富的研發(fā)經(jīng)驗(yàn),樂(lè)于技術(shù)輸出、分享,現(xiàn)階段從事微服務(wù)架構(gòu)項(xiàng)目的研發(fā)工作,涉及架構(gòu)設(shè)計(jì)、技術(shù)選型、業(yè)務(wù)研發(fā)等工作。對(duì)于Java、微服務(wù)、數(shù)據(jù)庫(kù)、Docker有深入了解,并有大量的調(diào)優(yōu)經(jīng)驗(yàn)。


0、前言
      無(wú)論任何項(xiàng)目,都避免不了在運(yùn)行期間出現(xiàn)的一些異常,并伴隨著因業(yè)務(wù)邏輯的需要而給出相應(yīng)的提示,使得系統(tǒng)變得更加友好,這類提示處理,我們統(tǒng)稱為異常處理(exceptiona handling)。

     在項(xiàng)目中異常處理所拋出的異常碼、異常提示 ,都需要進(jìn)行一定的封裝,以確保異常的統(tǒng)一,提高程序的可維護(hù)性。而不是隨心所欲的來(lái)進(jìn)行異常提醒,如:一些硬編碼異常信息(throw new Exception("系統(tǒng)處理異常")),隨著想項(xiàng)目的變大、開(kāi)發(fā)人員的不同,這些異常碼可能會(huì)五花八門,沒(méi)有統(tǒng)一標(biāo)準(zhǔn),給用戶提示、給開(kāi)發(fā)很容易帶來(lái)些許的困惑。 

    本文不是講解如何正確使用try、catch、finally等進(jìn)行異常捕獲,而是就異常碼、異常信息進(jìn)行封裝,通過(guò)配置文件進(jìn)行集中化定義,來(lái)統(tǒng)一異常處理,讓異常處理變得更標(biāo)準(zhǔn)化、統(tǒng)一化,方便維護(hù)、管理。

 

1、異常處理
    異常處理,又稱為錯(cuò)誤處理,提供了處理程序運(yùn)行時(shí)出現(xiàn)的任何意外或異常情況的方法。異常處理使用 try、catch 和 finally 關(guān)鍵字來(lái)嘗試可能未成功的操作,處理失敗,以及在事后清理資源。

異常發(fā)生的原因有很多,通常包含以下幾大類:

用戶輸入了非法數(shù)據(jù)。
要打開(kāi)的文件不存在。
網(wǎng)絡(luò)通信時(shí)連接中斷,或者JVM內(nèi)存溢出。
這些異常有的是因?yàn)橛脩翦e(cuò)誤引起,有的是程序錯(cuò)誤引起的。

要理解Java異常處理是如何工作的,你需要掌握以下三種類型的異常:

檢查性異常:最具代表的檢查性異常是用戶錯(cuò)誤或問(wèn)題引起的異常,這是程序員無(wú)法預(yù)見(jiàn)的。例如要打開(kāi)一個(gè)不存在文件時(shí),一個(gè)異常就發(fā)生了,這些異常在編譯時(shí)不能被簡(jiǎn)單地忽略。
運(yùn)行時(shí)異常: 運(yùn)行時(shí)異常是可能被程序員避免的異常。與檢查性異常相反,運(yùn)行時(shí)異常可以在編譯時(shí)被忽略。
錯(cuò)誤: 錯(cuò)誤不是異常,而是脫離程序員控制的問(wèn)題。錯(cuò)誤在代碼中通常被忽略。例如,當(dāng)棧溢出時(shí),一個(gè)錯(cuò)誤就發(fā)生了,它們?cè)诰幾g也檢查不到的。


所有的異常類是從 java.lang.Exception 類繼承的子類。

Exception 類是 Throwable 類的子類。除了Exception類外,Throwable還有一個(gè)子類Error 。

Java 程序通常不捕獲錯(cuò)誤。錯(cuò)誤一般發(fā)生在嚴(yán)重故障時(shí),它們?cè)贘ava程序處理的范疇之外。

Error 用來(lái)指示運(yùn)行時(shí)環(huán)境發(fā)生的錯(cuò)誤。例如,JVM 內(nèi)存溢出。一般地,程序不會(huì)從錯(cuò)誤中恢復(fù)。

異常類有兩個(gè)主要的子類:IOException 類和 RuntimeException 類。

本文就針對(duì)處理的是Exception類異常。

   

2、統(tǒng)一異常處理
     本實(shí)戰(zhàn)中將異常碼、異常信息進(jìn)行封裝,通過(guò)properties配置文件進(jìn)行集中化定義,并支持國(guó)際化異常碼的定義,來(lái)統(tǒng)一異常處理。

2.1 消息結(jié)果的封裝
全系統(tǒng)統(tǒng)一返回的數(shù)據(jù)格式為:

{
    "statusCode":"00000000",
    "msg":"成功",
    "data": {
        "username":"xcbeyond",
        "sex":"男",
        "age":18
    }
}
標(biāo)準(zhǔn)的json字符串,statusCode:狀態(tài)碼,msg:提示信息,data:結(jié)果數(shù)據(jù)(以實(shí)際數(shù)據(jù)而定的json)。

定義一個(gè)實(shí)體類Result,用來(lái)封裝消息返回?cái)?shù)據(jù),如下:

package com.xcbeyond.execption.data;
 
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.xcbeyond.execption.util.ObjectUtils;
 
import java.io.Serializable;
 
/**
 * 返回結(jié)果
 * @Auther: xcbeyond
 * @Date: 2019/5/24 17:55
 */
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class Result implements Serializable {
    //狀態(tài)碼
    private String statusCode;
    //提示信息
    private String msg;
    //結(jié)果數(shù)據(jù)
    private Object data;
 
    public Result() {
 
    }
 
    public Result(String statusCode, String msg) {
        this.statusCode = statusCode;
        this.msg = msg;
    }
 
    public String getStatusCode() {
        return statusCode;
    }
 
    public void setStatusCode(String statusCode) {
        this.statusCode = statusCode;
    }
 
    public String getMsg() {
        return msg;
    }
 
    public void setMsg(String msg) {
        this.msg = msg;
    }
 
    public Object getData() {
        return data;
    }
 
    public void setData(Object data) {
        this.data = data;
    }
 
    /**
     * 重寫toString方法,讓Result對(duì)象以json字符串形式存在
     * @return
     *  Json字符串
     */
    @Override
    public String toString() {
        JSONObject json = new JSONObject();
        json.put("statusCode", this.statusCode);
        json.put("msg", this.msg);
        if (null != this.data) {
            json.put("data", ObjectUtils.modelToMap(this.data));
        }
        return json.toJSONString();
    }
}
2.2 異常碼、異常信息配置文件定義化 *
   將異常碼、異常信息統(tǒng)一集中定義到properties配置文件中,避免硬編碼在代碼中,方便維護(hù),便于后期變動(dòng)統(tǒng)一修改。異常碼文件位于項(xiàng)目resources目錄下\resources\error\,如下:

異常碼文件名統(tǒng)一格式:模塊名_error_zh_CN.properties/模塊名_error_en_US.properties(zh_CN、en_US區(qū)分國(guó)際化定義)






異常碼統(tǒng)一格式定義,具體以實(shí)際項(xiàng)目情況而定,可參考如下標(biāo)準(zhǔn)定義:

#錯(cuò)誤碼定義8位
#  ┌─1─┬─2─┬─3─┬─4─┬─5─┬─6─┬─7─┬─8─┐
#  │預(yù)留 │C/B端│   模塊名   │         錯(cuò)誤碼           │
#  └─1─┴─2─┴─3─┴─4─┴─5─┴─6─┴─7─┴─8─┘
#第1位:
#   預(yù)留
#第2位:
#   C/B端(客戶端或服務(wù)端) 0-服務(wù)端, 1-客戶端
#第3、4位:
#   2位模塊名
#第5、6、7、8位:
#   4位錯(cuò)誤碼(后4位),各位含義如下:
#   第5為:類別,可按業(yè)務(wù)分類、接口分類等劃分,0-9
#   第6-8位:3位具體錯(cuò)誤碼
#       第6位:按以下含義定義分類:
#           0:預(yù)留
#           1:非空檢查類提示,數(shù)據(jù)為空、不為空檢查
#           2:有效性檢查提示,數(shù)據(jù)有效性檢查(如格式、存在、不存在、不在有效值范圍等)
#           3:業(yè)務(wù)邏輯類提示,合法性/一致性/完整性檢查提示
#           4:預(yù)留/待擴(kuò)展定義
#           5:預(yù)留/待擴(kuò)展定義
#           6:預(yù)留/待擴(kuò)展定義
#           7:預(yù)留/待擴(kuò)展定義
#           8:預(yù)留/待擴(kuò)展定義
#           9:預(yù)留/待擴(kuò)展定義
#       第7、8位:二位順序標(biāo)號(hào),00-99
封裝異常碼工具類ErrorUtils,用于從異常碼文件中獲取錯(cuò)誤提示信息等,如下:

package com.xcbeyond.execption.util;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
 
/**
 * 錯(cuò)誤工具類,用于從錯(cuò)誤碼配置文件中獲取錯(cuò)誤提示信息等
 * 支持國(guó)際化。
 * @Auther: xcbeyond
 * @Date: 2019/5/24 17:16
 */
public class ErrorUtils {
    private static final Logger log = LoggerFactory.getLogger(ErrorUtils.class);
 
    private static ResourceBundleMessageSource resourceBundle = new ResourceBundleMessageSource();
    private static final String ZH_LANGUAGE = "CHINESE";
    private static final String EN_LANGUAGE = "AMERICAN/ENGLISH";
    private static final String FILE_KEYWORKS = "error";
    private static final String JAR_RESOURCES = "classpath*:error/*error*.properties";
    private static final String RESOURCES = "classpath*:*error*.properties";
 
 
    /**
     * 靜態(tài)代碼塊。
     * 用于加載錯(cuò)誤碼配置文件
     */
    static {
        try {
            PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
            List nameListCn = new ArrayList();
 
            Resource[] jarResources = patternResolver.getResources(JAR_RESOURCES);
            if (log.isDebugEnabled())
                log.debug("加載CLASSPATH下[error]文件夾錯(cuò)誤碼配置文件[" + jarResources.length + "]");
            for (Resource resource : jarResources) {
                String fileName = resource.getFilename();
                fileName = fileName.substring(0, fileName.indexOf(FILE_KEYWORKS) + 5);
                if (log.isDebugEnabled())
                    log.debug("加載[error]下錯(cuò)誤碼配置文件[" + resource.getFilename() + "][" + fileName + "]");
                nameListCn.add("error/" + fileName);
            }
 
            Resource[] resources = patternResolver.getResources(RESOURCES);
            if (log.isDebugEnabled())
                log.debug("加載CLASSPATH根目錄錯(cuò)誤碼配置文件[" + resources.length + "]");
            for (Resource resource : resources) {
                String fileName = resource.getFilename();
                fileName = fileName.substring(0, fileName.indexOf(FILE_KEYWORKS) + 5);
                if (log.isDebugEnabled())
                    log.debug("加載錯(cuò)誤碼配置文件[" + resource.getFilename() + "][" + fileName + "]");
                nameListCn.add(fileName);
            }
            resourceBundle.setBasenames((String[]) nameListCn.toArray(new String[0]));
 
            resourceBundle.setCacheSeconds(5);
        } catch (Throwable localThrowable) {
        }
    }
 
    /**
     * 獲取錯(cuò)誤碼描述信息
     * @param errCode 錯(cuò)誤碼
     * @return
     */
    public static String getErrorDesc(String errCode) {
        return getErrorDesc(errCode, "CHINESE");
    }
 
    /**
     * 獲取錯(cuò)誤碼描述信息
     * @param errCode   錯(cuò)誤碼
     * @param userLang  國(guó)際化語(yǔ)言
     * @return
     */
    public static String getErrorDesc(String errCode, String userLang) {
        String errDesc = "";
        try {
            if ((null == userLang) || (ZH_LANGUAGE.equals(userLang))) {
                errDesc = resourceBundle.getMessage(errCode, null, Locale.SIMPLIFIED_CHINESE);
            } else if (EN_LANGUAGE.equals(userLang)) {
                errDesc = resourceBundle.getMessage(errCode, null, Locale.US);
            }
        } catch (NoSuchMessageException localNoSuchMessageException) {
 
        }
        return errDesc;
    }
 
    /**
     * 獲取錯(cuò)誤碼描述信息
     * @param errCode   錯(cuò)誤碼
     * @param args  錯(cuò)誤描述信息中參數(shù)
     * @return
     */
    public static String getParseErrorDesc(String errCode, String[] args) {
        return getParseErrorDesc(errCode, ZH_LANGUAGE, args);
    }
 
    /**
     * 獲取錯(cuò)誤碼描述信息
     * @param errCode   錯(cuò)誤碼
     * @param userLang  國(guó)際化語(yǔ)言
     * @param args  錯(cuò)誤描述信息中參數(shù)
     * @return
     */
    public static String getParseErrorDesc(String errCode, String userLang, String[] args) {
        String errDesc = "";
        try {
            if ((null == userLang) || (ZH_LANGUAGE.equals(userLang)))
                errDesc = resourceBundle.getMessage(errCode, args, Locale.SIMPLIFIED_CHINESE);
            else if (EN_LANGUAGE.equals(userLang))
                errDesc = resourceBundle.getMessage(errCode, args, Locale.US);
        } catch (NoSuchMessageException localNoSuchMessageException) {
        }
        return errDesc;
    }
}
2.3 異常類封裝
本文封裝兩類異常:

系統(tǒng)級(jí)異常:指系統(tǒng)級(jí)別的,如:網(wǎng)絡(luò)通信時(shí)連接中斷、系統(tǒng)連接、超時(shí)等異常
業(yè)務(wù)處理異常:指用戶輸入了非法數(shù)據(jù)等業(yè)務(wù)邏輯存在的異常
(其他類別異常,可自行封裝,如SQL類異常)

(1)異?;怋aseException,所有異常類都繼承此類,如下:

package com.xcbeyond.execption;
 
import java.io.Serializable;
 
/**
 * 異?;?br style="box-sizing: border-box; outline: 0px; overflow-wrap: break-word;"> * @Auther: xcbeyond
 * @Date: 2019/5/28 16:27
 */
public class BaseException extends RuntimeException implements Serializable {
    public BaseException() {
    }
 
    public BaseException(String message) {
        super(message);
    }
 
    public BaseException(Throwable cause) {
        super(cause);
    }
 
    public BaseException(String message, Throwable cause) {
        super(message, cause);
    }
}
(2)系統(tǒng)級(jí)異常SystemException,如下:

package com.xcbeyond.execption;
 
import com.xcbeyond.execption.data.Result;
 
/**
 * 系統(tǒng)級(jí)異常。
 *  指系統(tǒng)級(jí)別的,如:網(wǎng)絡(luò)通信時(shí)連接中斷、系統(tǒng)連接、超時(shí)等異常
 * @Auther: xcbeyond
 * @Date: 2019/5/28 16:26
 */
public class SystemException extends BaseException{
    private Result result = new Result();
 
    public SystemException(Result result) {
        super(result.getStatusCode()+ ":" + result.getMsg());
        this.result = result;
    }
 
    public SystemException(String code, String msg) {
        super(code + ":" + msg);
        this.result.setStatusCode(code);
        this.result.setMsg(msg);
    }
 
    public SystemException(Result result, Throwable cause) {
        super(result.getStatusCode() + ":" + result.getMsg(), cause);
        this.result = result;
    }
 
    public SystemException(String code, String msg, Throwable cause) {
        super(code + ":" + msg, cause);
        this.result.setStatusCode(code);
        this.result.setMsg(msg);
    }
 
    public Result getResult() {
        return result;
    }
 
    public void setResult(Result result) {
        this.result = result;
    }
}
(3)業(yè)務(wù)處理異常類BusinessException,如下:

package com.xcbeyond.execption;
 
import com.xcbeyond.execption.data.Result;
 
 
/**
 * 業(yè)務(wù)處理異常
 *  指用戶輸入了非法數(shù)據(jù)等業(yè)務(wù)邏輯存在的異常
 * @Auther: xcbeyond
 * @Date: 2018/12/24 11:20
 */
public class BusinessException extends BaseException {
    private Result result = new Result();
 
    public BusinessException(Result result) {
        super(result.getStatusCode()+ ":" + result.getMsg());
        this.result = result;
    }
 
    public BusinessException(String code, String msg) {
        super(code + ":" + msg);
        this.result.setStatusCode(code);
        this.result.setMsg(msg);
    }
 
    public BusinessException(Result result, Throwable cause) {
        super(result.getStatusCode() + ":" + result.getMsg(), cause);
        this.result = result;
    }
 
    public BusinessException(String code, String msg, Throwable cause) {
        super(code + ":" + msg, cause);
        this.result.setStatusCode(code);
        this.result.setMsg(msg);
    }
 
    public Result getResult() {
        return result;
    }
 
    public void setResult(Result result) {
        this.result = result;
    }
}
(4)異常工具類ExecptionUtils

為方便在業(yè)務(wù)代碼中進(jìn)行統(tǒng)一異常調(diào)用,特封裝異常工具類ExecptionUtils,如下:

package com.xcbeyond.execption.util;
 
import com.xcbeyond.execption.BusinessException;
import com.xcbeyond.execption.SystemException;
import com.xcbeyond.execption.data.Result;
 
/**
 * 異常工具類
 * @Auther: xcbeyond
 * @Date: 2019/5/27 09:37
 */
public class ExecptionUtils {
    /**
     * 業(yè)務(wù)處理異常
     * @param errCode   異常碼
     * @return
     */
    public static BusinessException businessException(String errCode) {
        return new BusinessException(createResult(errCode));
    }
 
    /**
     * 業(yè)務(wù)處理異常
     * @param errCode   自定義異常碼
     * @param msg   自定義異常提示
     * @return
     */
    public static BusinessException businessException(String errCode, String msg) {
        return new BusinessException(createResult(errCode, msg));
    }
 
    /**
     * 業(yè)務(wù)處理異常
     * @param errCode   異常碼
     * @param args  錯(cuò)誤描述信息中的參數(shù)
     * @return
     */
    public static BusinessException businessException(String errCode, String... args) {
        return new BusinessException(createResult(errCode, args));
    }
 
    /**
     * 系統(tǒng)級(jí)異常
     * @param errCode   異常碼
     * @return
     */
    public static SystemException systemException(String errCode) {
        return new SystemException(createResult(errCode));
    }
 
    /**
     * 業(yè)務(wù)處理異常
     * @param errCode   自定義異常碼
     * @param msg   自定義異常提示
     * @return
     */
    public static SystemException systemException(String errCode, String msg) {
        return new SystemException(createResult(errCode, msg));
    }
 
    /**
     * 系統(tǒng)級(jí)異常
     * @param errCode   異常碼
     * @param args  錯(cuò)誤描述信息中的參數(shù)
     * @return
     */
    public static SystemException systemException(String errCode, String... args) {
        return new SystemException(createResult(errCode, args));
    }
 
 
    private static Result createResult(String errCode) {
        return new Result(errCode, getErrorMsg(errCode));
    }
 
    private static Result createResult(String errCode, String msg) {
        return new Result(errCode, msg);
    }
 
    private static Result createResult(String errCode, String[] args) {
        return new Result(errCode, getErrorMsg(errCode, args));
    }
 
    /**
     * 獲取錯(cuò)誤信息
     * @param errCode   錯(cuò)誤碼
     * @return
     */
    private static String getErrorMsg(String errCode) {
        return ErrorUtils.getErrorDesc(errCode);
    }
 
    /**
     * 獲取錯(cuò)誤信息
     * @param errCode   錯(cuò)誤碼
     * @param args  錯(cuò)誤描述信息中的參數(shù)
     * @return
     */
    private static String getErrorMsg(String errCode, String[] args) {
        return ErrorUtils.getParseErrorDesc(errCode, args);
    }
 
}
2.4 全局異常捕獲
      一般異常捕獲都是通過(guò)try/catch、throw new等方式進(jìn)行捕獲,而頻繁的這樣操作,有時(shí)讓人覺(jué)得麻煩,代碼變得不是那么的干凈,尤其業(yè)務(wù)復(fù)雜的場(chǎng)合。就像下面這種:

try{
    ..........
}catch(Exception1 e){
    ..........
}catch(Exception2 e){
    ...........
}catch(Exception3 e){
    ...........
}
      這樣的代碼既不簡(jiǎn)潔好看 ,我們敲著也煩, 一般我們可能想到用攔截器去處理。而在spring中提供了更好的方案,注解@ControllerAdvice和@ExceptionHandler,進(jìn)行全局統(tǒng)一異常處理。

本文定義全局異常捕獲類GlobalExceptionHandler,如下:

package com.xcbeyond.execption.handler;
 
import com.xcbeyond.execption.BusinessException;
import com.xcbeyond.execption.SystemException;
import com.xcbeyond.execption.data.Result;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
 
/**
 * 全局異常捕獲處理
 * @Auther: xcbeyond
 * @Date: 2019/5/28 15:19
 */
@ControllerAdvice
public class GlobalExceptionHandler {
 
    /**
     * 業(yè)務(wù)邏輯異常。
     *  HTTP響應(yīng)狀態(tài)為200
     * @param businessException
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    public ResponseEntity businessExceptionHandler(BusinessException businessException) {
        Result result = businessException.getResult();
        return new ResponseEntity(result, HttpStatus.OK);
    }
 
    /**
     * 系統(tǒng)異常。
     *  HTTP響應(yīng)狀態(tài)為400
     * @param systemException
     * @return
     */
    @ExceptionHandler(value = SystemException.class)
    public ResponseEntity systemExceptionHandler(SystemException systemException) {
        Result result = systemException.getResult();
        return new ResponseEntity(result, HttpStatus.BAD_REQUEST);
    }
}
2.5 應(yīng)用
將上述定義封裝的異常,進(jìn)行實(shí)際應(yīng)用。

下述只是為了進(jìn)行異常應(yīng)用測(cè)試,并不符合實(shí)際業(yè)務(wù)場(chǎng)景。

以用戶登錄接口的service層UserServiceImpl類實(shí)現(xiàn)講解,代碼如下:

package com.xcbeyond.execption.service.impl;
 
import com.xcbeyond.execption.model.User;
import com.xcbeyond.execption.service.UserService;
import com.xcbeyond.execption.util.ExecptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
 
/**
 * @Auther: xcbeyond
 * @Date: 2019/5/28 17:04
 */
@Service
public class UserServiceImpl implements UserService {
 
    public ResponseEntity login(User user) {
        if (StringUtils.isEmpty(user.getUsername())) {
            throw ExecptionUtils.businessException("EE3001");
        }
        if (StringUtils.isEmpty(user.getPassword())) {
            throw ExecptionUtils.businessException("EE3002");
        }
 
        if (!"xcbeyond".equals(user.getUsername())) {
            throw ExecptionUtils.businessException("EE4001", user.getUsername());
        }
 
        /**
         * 測(cè)試系統(tǒng)級(jí)異常.
         * 通過(guò)用戶名和密碼相同時(shí),來(lái)模擬網(wǎng)絡(luò)連接異常
         */
        if (user.getPassword().equals(user.getUsername())) {
            throw ExecptionUtils.systemException("999999", "網(wǎng)絡(luò)鏈接異常");
        }
 
        return new ResponseEntity(HttpStatus.OK);
    }
}
此例有三類場(chǎng)合異常處理:

(1)不帶參的邏輯異常處理

throw ExecptionUtils.businessException("EE3002");
返回?cái)?shù)據(jù):

(2)帶參的邏輯異常處理

throw ExecptionUtils.businessException("EE4001", user.getUsername());


(3)系統(tǒng)級(jí)異常處理

throw ExecptionUtils.systemException("EE9999");


 

如果你有更好的異常統(tǒng)一處理建議,歡迎一起討論完善。

 源碼:https://github.com/xcbeyond/JavaExecptionFramework