当参数校验通过后,可以执行后续的业务逻辑;
但如果校验未通过,应该如何处理?这就涉及到参数校验的异常捕获问题。
系统没有按照预期的执行,遇到了一些意料之中或者意料之外的问题,这就是系统运行异常。我们需要将问题捕获,记录下来当时的情况(入参、异常信息),然后抛出一个预先设计的友好的错误代码和描述,这就是异常处理。
针对异常处理,有最适合的方式就是切面编程。
我们首先定义一个切面类
@Slf4j
@Aspect
@Configuration
public class ControllerAspect {
//定义切面范围
private final String controller = "execution(public * com.xx.controller.*.*(..))";
@Pointcut(controller)
public void controller() {}
@Around(controller)
public ServiceResult doAround(ProceedingJoinPoint joinPoint) {
LogUtil.setLogId();
long startTime = System.currentTimeMillis();
Object[] args = joinPoint.getArgs();
ServiceResult result = null;
BindingResult bindingResult = null;
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getName();
className = className.substring(className.lastIndexOf(".") + 1);
log.info("<<" + className + "." + methodName + ">> --->request :{} ",args);
try {
for(int i=0;i<args.length;i++) {
if(args[i] instanceof BindingResult) {
bindingResult = (BindingResult)args[i];
}
}
if(bindingResult !=null) {
if(bindingResult.hasErrors()) {
List<ObjectError> errors = bindingResult.getAllErrors();
if (errors.size() > 0) {
ObjectError error = errors.get(0);
String message = error.getDefaultMessage();
if (StringUtils.isNotBlank(message)) {
throw new ServiceException(ErrorCode.PARAM_ERROR,message);
} else {
throw new ValidationException();
}
}
}
}
result = (ServiceResult)joinPoint.proceed();
} catch (Throwable e) {
return ExceptionHandler.exceptionHandler(e);
}
log.info("<<" + className + "." + methodName + ">> ==> exec time millis : {} ",
System.currentTimeMillis() - startTime);
log.info("<<" + className + "." + methodName + ">> --->response : {} ", JSON.toJSONString(result));
LogUtil.clearLogId();
return result;
}
}
对于上述代码中的异常处理类,具体如下:
public class ExceptionHandler {
public static ServiceResult exceptionHandler(Throwable th) {
if(th instanceof ConstraintViolationException) {
//参数异常
String message = null;
Set<ConstraintViolation<?>> set = ((ConstraintViolationException)th).getConstraintViolations();
for(ConstraintViolation cv:set) {
message = cv.getMessage();
break;
}
LOG.error("参数异常:{}",message);
return ServiceResult.fail(ErrorCode.PARAM_ERROR.getCode(), message);
}else if(th instanceof ServiceException) {
// 业务异常
ServiceException se = (ServiceException) th;
LOG.error("业务异常:{}",se.getMessage());
return ServiceResult.fail(se.getErrorCode(), se.getMessage());
}else {
// 其他异常
LOG.error("其他系统异常:{}",th);
return ServiceResult.fail(ErrorCode.SYSTEM_ERROR.getCode(), ErrorCode.SYSTEM_ERROR.getMessage());
}
}
}
如上所示,通过切面来捕获异常,使用ExceptionHandler 来处理异常,即可对参数校验问题,业务问题以及系统运行时异常进行统一处理。