Skip to main content

错误处理

在这篇文章中,将介绍如何在本项目中进行业务错误处理

1. 基本原则

对于业务错误,项目的基本原则如下:

  • 建议使用RuntimeException
  • 对业务错误要具体化

2. 指引

2.1 定义业务错误码

在业务中,你可以在任何一层中,编写一个错误ErrorCode类


public enum UserErrorCode implements ErrorCode {

USER_ID_EMPTY,

USER_NAME_EMPTY,

PASSWORD_EMPTY,

USER_NOT_FOUND
}

如上所示,在对应层中,定义一个ErrorCode码类,实现ErrorCode,定义业务上的一些错误行为

2.2 定义错误异常

为你的每个错误码定义一个错误异常类

public class UserIdEmptyException extends BusinessException {
public UserIdEmptyException() {
super(UserErrorCode.USER_ID_EMPTY);
}
}

如上述代码所示,这个错误异常,应访介继承自BusinessException,这是一个通用的异常类,myddd-spring-boot会在rest层中使用拦截器,拦截此异常并处理。

这意味着你只需要关心定义及在合适的地方抛出异常,不需要关心如何捕获及在REST中处理它

带参数的异常

除了支持上述只有错误码的异常外,你可以定义带参数的错误类

public class UserNotFoundException extends BusinessException {
public UserNotFoundException(String userId) {
super(UserErrorCode.USER_NOT_FOUND,userId);
}
}

如上所示,我们定义了一个UserNotFoundException的异常,并附带了一个参数userId。这个参数在后续错误输出中是可以使用的。

参数值可以有0到n个,它是个可变长参数

2.3 定义错误描述

错误码只是一个码,你需要为它定义一个详细的错误描述,这样在API返回时,能给调用者更通俗易懂的信息.

在rest层的MAT-INF目录下的error_msg.properties文件中,为错误码定义错误描述

MEDIA_NOT_FOUND=media not found
FILE_NOT_FOUND=file %s not found
BAD_EMAIL=the email your input is bad: %s

在错误描述中,可以通过 %s这样的参数方式来使用你在异常中的参数值

2.4 在业务中抛出异常


public class User extends BaseDistributedEntity {

public void enable(){
enableOrDisable(false);
}

public void disable(){
enableOrDisable(true);
}

private void enableOrDisable(boolean disabled){
if(Strings.isNullOrEmpty(userId)){
throw new UserIdEmptyException();
}
User exists = queryUserByUserId(userId);
if(Objects.isNull(exists)){
throw new UserNotFoundException(userId);
}

exists.disabled = disabled;
getUserRepository().save(exists);
}
}

你只需要在合适的地方抛出业务异常就可以了。不需要在任何地方捕获或处理它

3. REST对异常的处理

在REST API调用的过程中,任何遇到业务错误,会最终输出status code为400的响应,响应格式为:

{
"error_code": "USER_ID_EMPTY",
"error_msg": "用户ID为空"
}

其中,error_code是你定义的Error Code,而error_msg则是你对错误的更详细的描述

4. 其它

请注意检查你的错误定义,在DDD的实现中,大部分业务上的错误,都应该是定义在领域层的。如果你的错误定义大多不在领域层,你需要认真检查下它是否是合适的。