valid入参校验

这篇博客介绍了如何在不依赖Hibernate Validator和javax.validation的情况下,动态地进行参数验证。作者提供了一个简单的工具类实现,用于手动校验入参。

平时使用Hibernate Validator + javax.validation.XXX 进行入参校验,由框架进行自动管理;

但很多情况下我们还是需要动态的手动去校验入参;于是简单写了个工具类;直接调用

AnaValidUtils.validObjectParams(Object object); 即可进行参数校验

 

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.executable.ExecutableValidator;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 功能描述:valid工具类(目前支持属性校验和被@AssertTrue、@AssertFalse修饰的方法校验)
 * 当入参存在问题,会抛出异常IllegalArgumentException;未知问题会抛出异常RuntimeException;
 * Created by wangpeng on 2019/8/9.
 */
@Slf4j
public class AnaValidUtils {

    private volatile static AnaValidUtils uniqueInstance;

    private AnaValidUtils() {
    }

    private static AnaValidUtils getInstance() {
        if (uniqueInstance == null) {
            synchronized (AnaValidUtils.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new AnaValidUtils();
                }
            }
        }
        return uniqueInstance;
    }

    /**
     * 校验对象参数(当入参存在问题,会抛出异常IllegalArgumentException;未知问题会抛出异常RuntimeException;)
     *
     * @param request
     */
    public static void validObjectParams(Object request) {
        AnaValidUtils.getInstance().validateAttributesAndMethods(request);
    }

    // 校验属性和方法
    private void validateAttributesAndMethods(Object request) {
        List<Object> toValidObjects = null;
        try {
            toValidObjects = getAllValidObjects(request, 0);
        } catch (IllegalAccessException ex) {
            log.error("反射权限问题", ex);
            throw new RuntimeException("校验入参失败");
        } catch (Exception ex) {
            log.error("未知问题", ex);
            throw new RuntimeException("校验入参失败");
        }

        for (Object object : toValidObjects) {
            validateAttributes(object);
            List<String> validMethodNames = getValidMethodNamesInObject(object);
            for (String validMethodName : validMethodNames) {
                try {
                    validateMethodInObject(object, validMethodName);
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
                    log.error("校验入参方法失败", ex);
                    throw new RuntimeException("校验入参方法失败");
                } catch (Exception ex) {
                    log.error("未知问题", ex);
                    throw new RuntimeException("校验入参方法失败");
                }
            }
        }
    }

    // 获取对象中的有效方法
    private List<String> getValidMethodNamesInObject(Object object) {
        List<String> rtnList = new ArrayList<>();
        for (Method method : object.getClass().getMethods()) {
            // @AssertTrue 修饰的方法
            javax.validation.constraints.AssertTrue annotationAssertTrue = method.getAnnotation(javax.validation.constraints.AssertTrue.class);
            if (Objects.nonNull(annotationAssertTrue)) {
                String methodName = method.getName();
                if (rtnList.contains(methodName)) {
                    throw new IllegalArgumentException("方法不可重名");
                }
                rtnList.add(methodName);
            }
            // @AssertFalse 修饰的方法
            javax.validation.constraints.AssertFalse annotationAssertFalse = method.getAnnotation(javax.validation.constraints.AssertFalse.class);
            if (Objects.nonNull(annotationAssertFalse)) {
                String methodName = method.getName();
                if (rtnList.contains(methodName)) {
                    throw new IllegalArgumentException("方法不可重名");
                }
                rtnList.add(methodName);
            }
        }
        return rtnList;
    }

    // 获取所有需要校验的对象(@Valid修饰的属性 + 初始对象)
    private List<Object> getAllValidObjects(Object request, Integer level) throws IllegalAccessException {
        if (Objects.isNull(request)) {
            return new ArrayList<>();
        }
        level = level + 1;
        if (level > 10) {
            throw new IllegalArgumentException("对象嵌套过深");
        }
        // 返回值
        List<Object> rtnList = new ArrayList<>();
        rtnList.add(request);
        for (Field field : request.getClass().getDeclaredFields()) {
            //设置对象的访问权限,保证对private的属性的访问
            field.setAccessible(true);
            javax.validation.Valid annotation = field.getAnnotation(javax.validation.Valid.class);
            if (Objects.nonNull(annotation)) {
                Object object = field.get(request);
                rtnList.addAll(getAllValidObjects(object, level));
            }
        }
        return rtnList;
    }

    // 校验属性
    private void validateAttributes(Object request) {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        //验证某个对象,,其实也可以只验证其中的某一个属性的
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(request);
        Iterator<ConstraintViolation<Object>> iter = constraintViolations.iterator();
        StringBuilder stringBuilder = new StringBuilder();
        while (iter != null && iter.hasNext()) {
            stringBuilder.append(iter.next().getMessage()).append(";");
        }
        if (StringUtils.isNotBlank(stringBuilder.toString())) {
            throw new IllegalArgumentException(stringBuilder.toString());
        }

    }

    // 校验对象中的方法
    private void validateMethodInObject(Object request, String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        //1.获取校验器
        Validator validator = factory.getValidator();
        //2.获取校验方法参数的校验器
        ExecutableValidator validatorParam = validator.forExecutables();

        //3.获取要校验的方法
        Method method = request.getClass().getMethod(methodName);
        Object returnValue = method.invoke(request);//调用方法获取返回值
        //4.校验返回值
        Set<ConstraintViolation<Object>> constraintViolationSet = validatorParam.validateReturnValue(request, method, returnValue);
        StringBuilder stringBuilder = new StringBuilder();
        for (ConstraintViolation item : constraintViolationSet) {
            stringBuilder.append(item.getMessage()).append(";");
        }
        if (StringUtils.isNotBlank(stringBuilder.toString())) {
            throw new IllegalArgumentException(stringBuilder.toString());
        }
    }

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值