項目參見:
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 [email protected] 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 [email protected] 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());
}
}
}
}