Spring framework框架为我们提供了很多有用的工具,比如Validation类用于处于HTTP请求的参数校验。
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
我们可以在Controller层获取Error来判断是否校验失败,但是这样每一个Controller层的方法都有重复的代码,我们可以实现统一的切面Aspect去为所有的方法都添加 校验逻辑。
@Aspect是Spring面向切面编程最重要的注解~可以实现在方法执行的时候添加额外的行为,
包括方法执行前Before、方法执行后After、方法抛出异常Exception、方法环绕Around等等时机。
import com.nova.felixchat.infrastructure.commons.BusinessException;
import com.nova.felixchat.infrastructure.commons.enums.BizErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import java.util.List;
/**
* @author linzihao
*/
@Slf4j
@Aspect
@Component
public class ParamValidateAspect {
@Pointcut("execution(* com.nova.felixchat..*(..))")
public void aspect() {
}
/*
* 配置前置通知,使用在方法aspect()上注册的切入点
* 同时接受JoinPoint切入点对象,可以没有该参数
*/
@Before("aspect()")
public void before(JoinPoint joinPoint) {
Object[] params = joinPoint.getArgs();
for (Object param : params) {
if (param instanceof Errors) {
Errors errors = (Errors) param;
if (errors.hasErrors()) {
List<ObjectError> errorList = errors.getAllErrors();
StringBuilder sb = new StringBuilder();
FieldError fieldError = (FieldError) errorList.get(0);
sb.append(fieldError.getDefaultMessage());
log.warn("======参数校验异常======" + sb.toString().trim());
throw new BusinessException(BizErrorCode.REQUEST_PARAM_ILLEGAL);
}
}
}
}
}
当然,我们完全可以使用@ControllerAdvice或者@RestControllerAdvice来实现统一参数校验。
import com.ligeit.supply.rules.infrastructure.commons.BizErrorCode;
import com.ligeit.supply.rules.infrastructure.commons.BusinessException;
import com.ligeit.supply.rules.infrastructure.commons.ResultData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import java.io.IOException;
import java.util.Comparator;
import java.util.stream.Collectors;
/**
* 统一异常处理类
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 参数验证统一处理
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
String msg = bindingResult.getFieldErrors().stream().sorted(Comparator.comparing(FieldError::getField))
.map(e1 -> e1.getDefaultMessage()).collect(Collectors.joining(","));
log.error("参数验证失败: {},", e.getMessage());
return ResultData.builder().code(BizErrorCode.REQUEST_PARAM_INVALID.getCode()).msg(msg).build();
}
//......其他异常处理逻辑
}