讓錯誤碼規范起來吧
一、前言
1、不規范的錯誤碼有什么問題?
1)理解困難
描述:如果錯誤碼的命名或描述不清晰,可能導致其他開發人員難以理解其含義。
舉例:例如,一個錯誤碼命名為“ERR1001”,沒有進一步的注釋或描述,可能導致其他開發人員不知道這個錯誤碼代表的具體問題。
2)不一致性
描述: 如果錯誤碼的命名、描述或分類不統一,可能導致代碼的可讀性和可維護性降低。
舉例:例如,有的錯誤碼使用三位數,有的使用兩位數;有的錯誤碼描述具體的問題,而有的描述則較為模糊。
3)排查困難
描述:如果錯誤碼沒有清晰的命名和描述,可能使得調試過程變得困難。
舉例:當出現問題時,開發人員需要查看大量的日志或代碼來定位問題所在。
4)冗余和重復
描述:如果錯誤碼過多或過于復雜,可能導致代碼中的錯誤處理邏輯變得冗余和重復。
舉例:同一個錯誤可能在不同地方有不同的錯誤碼,導致處理邏輯重復。
5)擴展性差
描述:如果錯誤碼已經定義但后來需要添加新的錯誤碼,可能需要修改多個地方的代碼,增加了維護成本。
2、規范的錯誤碼那么好,為什么不規范使用呢?
1)缺乏規范和標準:
在某些情況下,可能沒有明確的規范或標準來指導如何使用錯誤碼。這可能導致開發人員根據自己的理解和習慣來定義錯誤碼,從而導致不規范的情況。
2)缺乏意識和經驗:
某些開發人員可能沒有意識到錯誤碼規范化的重要性,或者缺乏足夠的經驗來正確地設計和使用錯誤碼。
3)歷史遺留問題:
在某些項目中,錯誤碼可能已經使用了很長時間,而且已經成為了代碼的一部分。在這種情況下,重新規范化錯誤碼可能會涉及到大量的代碼修改和測試,這可能會被視為成本較高。
4)個人習慣和偏好:
某些開發人員可能更傾向于按照自己的習慣和偏好來使用錯誤碼,而不是遵循團隊的規范。這可能會導致代碼中的錯誤碼使用不一致。
3、那怎么規范錯誤碼呢
1)制定規范和標準:
團隊可以制定明確的規范和標準,指導如何使用錯誤碼,并將其納入代碼審查和開發流程中。
2)培訓和指導:
為新開發人員提供培訓和指導,使其了解如何正確地設計和使用錯誤碼。
3)重構和改進:
對于歷史遺留問題,可以通過逐步重構和改進的方式來規范化錯誤碼的使用。
4)代碼審查和團隊協同:
通過代碼審查和團隊協同來確保錯誤碼的規范化和一致性。
二、規范錯誤碼
1、錯誤碼-分片區
根據號段區分錯誤類型,這里長度定義了5位,可以根據自己系統規模調整長度
| 錯誤碼 | 描述 |
|---|---|
| 00000 | 成功 |
| 10000 | 參數錯誤 |
| 20000 | 業務處理失敗(業務上給用戶吐出) |
| 30000 | RPC處理失敗 --->> 系統_失敗分類(請求0、返回1)_業務_方法_調用方CODE碼(代碼補齊),極端情況下吐出 99999 |
| 40000 | 運行處理失?。阂话銉炔刻幚硎褂?,極端情況下吐出 99999 |
| 99999 | 系統太火爆了,請稍后重試! -->極端情況下才吐出 |
@Getter
@AllArgsConstructor
enum ErrorCodeEnum implements CodeEnum {
ERROR_CODE_SUCCESS("00000", "成功"),
ERROR_CODE_PARAMS_ERROR("10000", "參數錯誤"),
ERROR_CODE_BUSINESS_ERROR("20000", "業務處理失敗"),
ERROR_CODE_PRC_ERROR("30000", "RPC處理失敗"),
ERROR_CODE_RUNTIME_ERROR("40000", "運行時失敗"),
ERROR_CODE_FAIL("99999", "系統太火爆了,請稍后重試!"),
;
private final String code;
private final String msg;
}
2、10000-參數異常
非常簡單,直接吐出即可
| 參數 | 說明 |
|---|---|
code |
錯誤碼 |
msg |
返回錯誤信息 |
@Getter
@AllArgsConstructor
enum ParamsErrorEnum implements CodeEnum {
ERROR_CODE_10000("10000", "參數錯誤"),
ERROR_CODE_10001("10001", "不支持的請求方式"),
ERROR_CODE_10002("10002", "參數格式異常"),
;
private final String code;
private final String msg;
}
3、20000-業務異常
| 參數 | 說明 |
|---|---|
code |
錯誤碼 |
msg |
底層-錯誤信息 |
showMsg |
吐出-錯誤信息 |
@Getter
@AllArgsConstructor
enum BusinessErrorEnum implements CodeEnum {
ERROR_CODE_20000("20000", "業務處理失敗", "系統太火爆了,請稍后重試!"),
ERROR_CODE_20001("20001", "訂單創建失敗", "您有一個訂單正在創建,請稍后查看"),
ERROR_CODE_20002("20002", "付款失敗,存在創建中的訂單", "您的訂單付款失敗,請稍后查看"),
ERROR_CODE_20003("20003", "付款失敗,存在未支付的訂單", "您的訂單付款失敗,請稍后查看"),
;
private final String code;
private final String msg;
private final String showMsg;
}
4、30000-RPC 異常
該異常一定要合理使用,這樣會讓微服務直接錯誤信息更明確
說明:
系統_失敗分類(請求0、返回1)_業務_調用方法_調用方CODE碼(代碼補齊)
| 字段 | 說明 |
|---|---|
| 系統 | 調用系統:如用戶系統 User |
| 失敗分類 | 請求失?。?;返回失?。? |
| 業務 | 業務(3開頭):用戶信息業務:30001 |
| 調用方法 | 業務調用方法(指定一個數字,確保是該業務唯一的方法) |
調用方Code碼 |
后續代碼中補齊,具體看異常拋出錯誤碼使用 |
| 參數 | 說明 |
|---|---|
code |
錯誤碼:系統_失敗分類(請求0、返回1)_業務_方法_調用方CODE碼(代碼補齊) |
msg |
底層-錯誤信息 |
@Getter
@AllArgsConstructor
enum RpcErrorEnum implements CodeEnum {
/**
* 系統_失敗分類(請求0、返回1)_業務_方法_調用方CODE碼(代碼補齊)
*/
ERROR_CODE_USER_0_30001_0001("USER_0_30001_0001", "RPC異常-USER-用戶信息-查詢單個用戶信息-接口調用失敗"),
ERROR_CODE_USER_1_30001_0001("USER_1_30001_0001", "RPC異常-USER-用戶信息-查詢單個用戶信息-接口返回失敗"),
ERROR_CODE_USER_1_30001_0002("USER_1_30001_0002", "RPC異常-USER-用戶信息-分頁查詢用戶信息-接口返回失敗"),
;
private final String code;
private final String msg;
}
5、40000-運行異常
@Getter
@AllArgsConstructor
enum PlatformErrorEnum implements CodeEnum {
ERROR_CODE_40000("40000", "運行時失敗"),
ERROR_CODE_40001("40001", "路由消息處理失敗"),
;
private final String code;
private final String msg;
}
三、錯誤碼使用
1、10000-參數異常
| 構造器 | 說明 |
|---|---|
ParameterException(CodeEnum.ParamsErrorEnum paramErrorEnum) |
建議使用:傳入一個固定的枚舉值 |
ParameterException(String message) |
不推薦:傳入一個錯誤信息 |
@Getter
public class ParameterException extends RuntimeException {
/**
* serialVersionUID
*/
private static final long serialVersionUID = -6114625076221233075L;
/**
* 返回錯誤碼
*/
private final String code;
/**
* BusinessException
*
* @param paramErrorEnum paramErrorEnum
*/
public ParameterException(CodeEnum.ParamsErrorEnum paramErrorEnum) {
super(paramErrorEnum.getMsg());
this.code = paramErrorEnum.getCode();
}
/**
* ParameterErrorException
*
* @param message message
*/
public ParameterException(String message) {
super(message);
this.code = CodeEnum.ErrorCodeEnum.ERROR_CODE_PARAMS_ERROR.getCode();
}
}
2、20000-業務異常
| 構造器 | 說明 |
|---|---|
BusinessException(CodeEnum.BusinessErrorEnum businessErrorEnum) |
建議使用:傳入一個固定的枚舉值 |
BusinessException(String message) |
不推薦:傳入一個錯誤信息 |
@Getter
public class BusinessException extends RuntimeException {
/**
* serialVersionUID
*/
private static final long serialVersionUID = 799633539625676004L;
/**
* 返回錯誤碼
*/
private final String code;
/**
* 展示信息
*/
private final String showMsg;
/**
* BusinessException
*
* @param businessErrorEnum businessErrorEnum
*/
public BusinessException(CodeEnum.BusinessErrorEnum businessErrorEnum) {
super(businessErrorEnum.getMsg());
this.code = businessErrorEnum.getCode();
this.showMsg = businessErrorEnum.getShowMsg();
}
/**
* BusinessException
*
* @param message message
*/
public BusinessException(String message) {
super(message);
this.code = CodeEnum.ErrorCodeEnum.ERROR_CODE_BUSINESS_ERROR.getCode();
this.showMsg = message;
}
}
3、30000-RPC異常
| 構造器 | 說明 |
|---|---|
RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum) |
場景:處理未知的RPC異常,如網絡超時等 |
RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String showMsg) |
場景:處理已知的異常 |
RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String msg, String showMsg) |
場景:處理已知的異常 |
@Getter
public class RpcException extends RuntimeException {
/**
* serialVersionUID
*/
private static final long serialVersionUID = 799633539625676004L;
/**
* 返回錯誤碼
*/
private final String code;
/**
* 展示信息
*/
private final String showMsg;
/**
* RpcException-處理未知的異常
*
*
* @param rpcErrorEnum rpcErrorEnum
*/
public RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum) {
super(rpcErrorEnum.getMsg());
this.code = rpcErrorEnum.getCode();
this.showMsg = CodeEnum.ErrorCodeEnum.ERROR_CODE_FAIL.getMsg();
}
/**
* RpcException 處理已知的異常
*
* @param rpcErrorEnum rpcErrorEnum
* @param code code
* @param showMsg showMsg
*/
public RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String showMsg) {
super(rpcErrorEnum.getMsg());
this.code = rpcErrorEnum.getCode() + "_" + code;
this.showMsg = showMsg;
}
/**
* RpcException 處理已知的異常
*
* @param rpcErrorEnum rpcErrorEnum
* @param code code
* @param showMsg showMsg
*/
public RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String msg, String showMsg) {
super(msg);
this.code = rpcErrorEnum.getCode() + "_" + code;
this.showMsg = showMsg;
}
}
4、40000-運行異常
@Getter
public class PlatformException extends RuntimeException {
private static final long serialVersionUID = 5535821215702463243L;
/**
* 返回錯誤碼
*/
private final String code;
/**
* 展示信息
*/
private final String showMsg;
/**
* PlatformException
*
* @param platformErrorEnum platformErrorEnum
*/
public PlatformException(CodeEnum.PlatformErrorEnum platformErrorEnum) {
super(platformErrorEnum.getMsg());
this.code = platformErrorEnum.getCode();
this.showMsg = CodeEnum.ErrorCodeEnum.ERROR_CODE_FAIL.getMsg();
}
}
四、異常吐出
1、10000-參數異常
/**
* 不支持的請求方始
*/
@ExceptionHandler(value ?> methodNotSupportExceptionHandler(HttpRequestMethodNotSupportedException e) {
log.error("不支持的請求方式", e);
return BaseRes.buildFailure(CodeEnum.ParamsErrorEnum.ERROR_CODE_10001.getCode(), e.getMessage());
}
/**
* 參數類型錯誤
*/
@ExceptionHandler(value ?> bindExceptionHandler(BindException e) {
log.error("====參數類型錯誤===", e);
return BaseRes.buildFailure(CodeEnum.ParamsErrorEnum.ERROR_CODE_10000);
}
/**
* 參數格式問題
*/
@ExceptionHandler(value ?> httpMessageConversionExceptionHandler(Exception e) {
log.error("====參數格式異常===", e);
return BaseRes.buildFailure(CodeEnum.ParamsErrorEnum.ERROR_CODE_10002);
}
/**
* 參數錯誤
*/
@ExceptionHandler(value ?> parameterErrorExceptionHandler(ParameterException e) {
log.error("====參數異常:code:{},msg:{}", e.getCode(), e.getMessage(), e);
return BaseRes.buildFailure(e.getCode(), e.getMessage());
}
2、20000-業務異常
/**
* 業務異常,給前臺返回異常數據
*/
@ExceptionHandler(value ?> businessExceptionHandler(BusinessException e) {
log.error("====業務異常:code:{},msg:{},showMsg:{}", e.getCode(), e.getMessage(), e.getShowMsg(), e);
return BaseRes.buildFailure(e.getCode(), e.getShowMsg());
}
3、30000-RPC異常
/**
* RPC,給前臺返回異常數據
*/
@ExceptionHandler(value ?> rpcExceptionHandler(RpcException e) {
log.error("====RPC異常:code:{},msg:{},showMsg:{}", e.getCode(), e.getMessage(), e.getShowMsg(), e);
return BaseRes.buildFailure(e.getCode(), e.getShowMsg());
}
4、40000-運行異常
/**
* 運行異常,給前臺返回異常數據
*/
@ExceptionHandler(value ?> rpcExceptionHandler(PlatformException e) {
log.error("====運行異常:code:{},msg:{},showMsg:{}", e.getCode(), e.getMessage(), e.getShowMsg(), e);
return BaseRes.buildFailure(e.getCode(), e.getShowMsg());
}
五、Demo
1、10000-參數異常
@ApiOperation("parameterExceptionEnum")
@LogIndex
@GetMapping("parameterExceptionEnum")
@ResponseBody
public BaseRes<List<UserDemoVO>> parameterExceptionEnum() {
throw new ParameterException(CodeEnum.ParamsErrorEnum.ERROR_CODE_10002);
}
{
"success"@ApiOperation("parameterExceptionMsg")
@LogIndex
@GetMapping("parameterExceptionMsg")
@ResponseBody
public BaseRes<List<UserDemoVO>> parameterExceptionMsg() {
throw new ParameterException("用戶Id不能為空");
}
{
"success"2、20000-業務異常
@ApiOperation("businessExceptionEnum")
@LogIndex
@GetMapping("businessExceptionEnum")
@ResponseBody
public BaseRes<List<UserDemoVO>> businessExceptionEnum() {
throw new BusinessException(CodeEnum.BusinessErrorEnum.ERROR_CODE_20001);
}
{
"success"@ApiOperation("businessExceptionMsg")
@LogIndex
@GetMapping("businessExceptionMsg")
@ResponseBody
public BaseRes<List<UserDemoVO>> businessExceptionMsg() {
throw new BusinessException("用戶創建失敗");
}
{
"success"3、30000-RPC異常
@ApiOperation("rpcExceptionDefaultEnum")
@LogIndex
@GetMapping("rpcExceptionDefaultEnum")
@ResponseBody
public BaseRes<List<UserDemoVO>> rpcExceptionDefaultEnum() {
throw new RpcException(CodeEnum.RpcErrorEnum.ERROR_CODE_USER_0_30001_0001);
}
{
"success"@ApiOperation("rpcExceptionEnumShowMsg")
@LogIndex
@GetMapping("rpcExceptionEnumShowMsg")
@ResponseBody
public BaseRes<List<UserDemoVO>> rpcExceptionEnumShowMsg() {
throw new RpcException(CodeEnum.RpcErrorEnum.ERROR_CODE_USER_1_30001_0001, "1000", "用戶不存在");
}
{
"success"@ApiOperation("rpcExceptionEnumMsg")
@LogIndex
@GetMapping("rpcExceptionEnumMsg")
@ResponseBody
public BaseRes<List<UserDemoVO>> rpcExceptionEnumMsg() {
throw new RpcException(CodeEnum.RpcErrorEnum.ERROR_CODE_USER_1_30001_0001,
"1000", "底層結構異常", "用戶不存在");
}
{
"success"4、40000-運行異常
@ApiOperation("platformException")
@LogIndex
@GetMapping("platformException")
@ResponseBody
public BaseRes<List<UserDemoVO>> platformException() {
throw new PlatformException(CodeEnum.PlatformErrorEnum.ERROR_CODE_40001);
}
{
"success"作者:京東保險 張宇晉
來源:京東云開發者社區 轉載請注明來源
浙公網安備 33010602011771號