1 概述
2 规范
2.1 统一为带错误码的结果
- 一是HTTP请求状态码为失败的,这个时候是没有业务结果的。这种需要根据HTTP的状态码来判断。
- 二是HTTP请求状态是成功的,里面包含了业务结果的。
import com.qqian.stepfmk.srvpro.base.error.ErrorCode;
import com.qqian.stepfmk.srvpro.base.error.SystemErrorCode;
import lombok.Value;
@Value
public class CodeResult<T> {
ErrorCode code;
T data;
public CodeResult() {
this(SystemErrorCode.SUCCESS, null);
}
public CodeResult(ErrorCode code) {
this(code, null);
}
public CodeResult(ErrorCode code, T data) {
this.code = code;
this.data = data;
}
}
其中,code为错误码,里面包含具体的错误码和错误描述,应该用常量进行定义,便于统一管理所有错误码。data则是具体的业务数据。
如果业务也是成功的,则使用系统级的成功状态码:
public class SystemErrorCode {
public static final long SCOPE_SYSTEM = 0L;
public static final int CODE_SUCCESS = 0;
public static final ErrorCode SUCCESS = ErrorCode.withSystem(SCOPE_SYSTEM, CODE_SUCCESS,
"OK", "成功");
}
2.2 校验错误
前面文章讲了使用hibernate-validator包来进行请求参数校验,校验的结果会抛出异常,需要对这里异常也转为统一结果形式。
1) 有校验错误的时候,抛出BindException
// 源码位置:org.springframework.web.method.annotation.ModelAttributeMethodProcessor
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 省略部分代码
if (bindingResult == null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
if (!mavContainer.isBindingDisabled(name)) {
bindRequestParameters(binder, webRequest);
}
validateIfApplicable(binder, parameter);
// 如果有校验错误,抛出BindException,参数为BindingResult对象,里面包含了具体的错误信息
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
if (!parameter.getParameterType().isInstance(attribute)) {
attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}
bindingResult = binder.getBindingResult();
}
Map<String, Object> bindingResultModel = bindingResult.getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return attribute;
}
2) 统一处理这类异常,转为带错误码的结果
@ControllerAdvice
public class ParamValidateExceptionHandler {
@ExceptionHandler(BindException.class)
public CodeResult<Object> handleBindException(BindException e) {
BindingResult result = e.getBindingResult();
ErrorCode code = ErrorCode.withSystem(SystemErrorCode.SCOPE_SYSTEM,
SystemErrorCode.CODE_INVALID_PARAMETER, "", "");
return new CodeResult<Object>(code);
}
}
由于hibernate-validator包并没有留扩展点供扩展校验结果信息,从头扩展工作量又比较大,所以用@ExceptionHandler处理这一类异常更方便一些,缺点是错误码不够具体化。如果实在要具体化,可以考虑扩展hibernate-validator提供的消息模版,在定义模版的时候规定一个带错误码的格式,到了统一处理异常的时候,再解释模版得到具体的信息。
2.3 业务错误
如果在业务处理的过程中,需要抛出异常中断处理流程,此时应该定义具体的错误码,并抛出有错误码的异常。
@Value
public class ErrorCodeException extends RuntimeException {
ErrorCode code;
public ErrorCodeException(ErrorCode code) {
super(code.getMessage());
this.code = code;
}
public static ErrorCodeException with(ErrorCode code) {
return new ErrorCodeException(code);
}
}
统一把带错误码异常转成带错误码的结果:
@ControllerAdvice
public class ErrorCodeExceptionHandler {
@ExceptionHandler(ErrorCodeException.class)
public CodeResult<Object> handleBindException(ErrorCodeException e) {
return new CodeResult<Object>(e.getCode());
}
}
2.4 未知错误
还有一类是预料不到的错误,比如数据库连接异常等。这类需要给个默认的异常处理,避免服务器的堆栈信息暴露到了服务器端。
public class SystemErrorCode {
public static final long SCOPE_SYSTEM = 0L;
public static final int CODE_SUCCESS = 0;
public static final int CODE_UNKNOWN = 1;
public static final int CODE_INVALID_PARAMETER = 101;
public static final ErrorCode SUCCESS = ErrorCode.withSystem(SCOPE_SYSTEM, CODE_SUCCESS,
"OK", "成功");
public static final ErrorCode UNKNOWN = ErrorCode.withSystem(SCOPE_SYSTEM, CODE_UNKNOWN,
"未知错误", "请联系系统管理处理");
public static final ErrorCode INVALID_PARAMETER = ErrorCode.withSystem(SCOPE_SYSTEM, CODE_INVALID_PARAMETER,
"非法参数错误", "请检查参数");
}
@ControllerAdvice
public class DefaultExceptionHandler {
@ExceptionHandler(Exception.class)
public CodeResult<Object> handleException(Exception ex) {
return new CodeResult<Object>(SystemErrorCode.UNKNOWN);
}
}
3 架构一小步
统一返回带错误码的结果。成功的结果,错误码为0,其它情况定义具体的错误码。
1万+

被折叠的 条评论
为什么被折叠?



