服務端參數校驗(二):SpringMVC項目的參數校驗

項目參見:

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());
            }
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章