项目参见:
https://gitee.com/xxssyyyyssxx/validation
compile "top.jfunc.validation:validation-core:1.0.1"
compile "top.jfunc.validation:validation-spring:1.0.1"
上文提供了参数校验工具,但是如果我们把参数校验跟正常业务逻辑放一起,势必会严重影响代码的可读性。站在Spring巨人的肩头上,利用AOP+注解实现参数校验和正常业务逻辑的解耦。
首先定义校验器Validator,使用者需要实现此接口实现自己的校验逻辑,并把其放入Spring容器,也由于此可以注入Spring容器中的组件供其使用。校验器Validator能够拿到被校验方法的输入参数。
public interface Validator {
/**
* 对传入的参数进行校验
* @param params 传入的参数
* @throws IllegalArgumentException 参数校验不过抛出异常
*/
void validate(Object[] params) throws IllegalArgumentException;
}
比如:
/**
* 注册校验
* @author xiongshiyan at 2019/9/28 , contact me with email yanshixiong@126.com or phone 15208384257
*/
@Component
public class StoreRegisterValidator implements Validator {
@Autowired
private MemberService memberService;
@Override
public void validate(Object[] params) throws IllegalArgumentException {
JSONObject jsonObject = JSON.parseObject(params[0].toString());
ValidateValue.with(jsonObject.getString("name")).notNull("名字不允许为空")
.and(jsonObject.getString("idCard")).notNull("身份证不允许为空")
.and(jsonObject.getString("cardFront")).notNull("身份证正面照片不允许为空")
.and(jsonObject.getString("cardBack")).notNull("身份证反面照片不允许为空");
Member byPhone = memberService.findByPhone(jsonObject.getString("phone"));
if(null != byPhone){
throw new IllegalArgumentException("此号码已经存在,不允许重复注册");
}
}
}
再定义注解Validated,方法标注了此注解表示要进行参数校验。此注解指定使用哪些Validator进行校验。
/**
* 添加了此注解就表示要进行参数校验
* @author xiongshiyan at 2018/11/2 , contact me with email yanshixiong@126.com or phone 15208384257
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
Class<? extends Validator>[] value();
}
在需要参数校验的方法上标注该注解:
@RequestMapping(value = "/register",method ={ RequestMethod.POST})
@Validated(StoreRegisterValidator.class)
public ResponseMsg register(@RequestBody String body){
。。。。
}
再定义切面,在切入点之前调用注解指定的校验器的校验方法,传入参数,当校验失败的时候就抛出IllegalArgumentException异常:
/**
* @author xiongshiyan
* 示例:参数校验切面
* 使用者可以通过定义自己的切面,在调用方法之前调用{@see ValidateUtil#validateJoinPointParams}
*/
@Aspect
@Component
public class ParamValidateAspect implements Ordered , ApplicationContextAware{
private ApplicationContext applicationContext;
@Pointcut("execution(public * top.jfunc.validation.controller..*.*(..))")
public void webParamValid(){}
@Around(value = "webParamValid()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
ValidateUtil.validateJoinPointParams(applicationContext , pjp);
return pjp.proceed();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public int getOrder() {
return 0;
}
}
public class ValidateUtil {
/**
* 在切面方法前调用此方法,根据注解{@link Validated}指定的{@link Validator}校验方法的参数
* @param applicationContext ApplicationContext
* @param pjp JoinPoint 在此切入点之前调用
*/
public static void validateJoinPointParams(ApplicationContext applicationContext , JoinPoint pjp) {
//目标方法
Method method = AnnotationUtil.getMethod(pjp);
Validated validated = AnnotationUtil.getValidated(method);
//存在@Validated注解
if(null != validated){
Class<? extends Validator>[] validatorClasses = validated.value();
for (Class<? extends Validator> validatorClass : validatorClasses) {
Validator validator = applicationContext.getBean(validatorClass);
validator.validate(pjp.getArgs());
}
}
}
}