<address id="xhxt1"><listing id="xhxt1"></listing></address><sub id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></sub>

    <thead id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></thead>

    在系统中使用Bean Validation验证参数

    为什么要使用Bean Validation?

    ?当我们实现某个接口时,都需要对入参数进行校验。例如下面的代码
    public String queryValueByKey(String parmTemplateCode, String conditionName, String conditionKey, String resultName) {
            checkNotNull(parmTemplateCode, "parmTemplateCode not null");
            checkNotNull(conditionName, "conditionName not null");
            checkNotNull(conditionKey, "conditionKey not null");
            checkNotNull(resultName, "resultName not null");
    


    该方法输入的四个参数都是必填项。用代码进行参数验证带来几个问题

    • 需要写大量的代码来进行参数验证。
    • 需要通过注释来直到每个入参的约束是什么。
    • 每个程序员做参数验证的方式不一样,参数验证不通过抛出的异常也不一样。

    什么是Bean Validation?

    Bean Validation是一个通过配置注解来验证参数的框架,它包含两部分Bean Validation API和Hibernate Validator。

    • Bean Validation API是Java定义的一个验证参数的规范。
    • Hibernate Validator是Bean Validation API的一个实现。

    快速开始

    引入POM

    <!-- Bean Validation start -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.1.1.Final</version>
    </dependency>
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>el-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>javax.el</artifactId>
        <version>2.2.4</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.logging</groupId>
        <artifactId>jboss-logging</artifactId>
        <version>3.1.3.GA</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml</groupId>
        <artifactId>classmate</artifactId>
        <version>1.0.0</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.13</version>
    </dependency>
    <!-- Bean Validation end -->
    

    实例代码如下,可以验证Bean,也可以验证方法参数

    
    import java.lang.reflect.Method;
    import java.util.Set;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.Validation;
    import javax.validation.Validator;
    import javax.validation.constraints.Max;
    import javax.validation.constraints.NotNull;
    import javax.validation.executable.ExecutableValidator;
    
    public class BeanValidatorTest {
    
        public static void main(String[] args) {
            Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
            //验证Bean参数,并返回验证结果信息
            Car car = new Car();
            Set<ConstraintViolation<Car>> validators = validator.validate(car);
            for (ConstraintViolation<Car> constraintViolation : validators) {
                System.out.println(constraintViolation.getMessage());
            }
    
            // 验证方法参数
            Method method = null;
            try {
                method = Car.class.getMethod("drive", int.class);
            } catch (SecurityException e) {
            } catch (NoSuchMethodException e) {
            }
            Object[] parameterValues = { 80 };
            ExecutableValidator executableValidator = validator.forExecutables();
            Set<ConstraintViolation<Car>> methodValidators = executableValidator.validateParameters(car,
                method, parameterValues);
            for (ConstraintViolation<Car> constraintViolation : methodValidators) {
                System.out.println(constraintViolation.getMessage());
            }
        }
    
        public static class Car {
    
            private String name;
    
            @NotNull(message = "车主不能为空")
            public String getRentalStation() {
                return name;
            }
    
            public void drive(@Max(75) int speedInMph) {
    
            }
    
        }
    }
    

    执行代码后,输出如下:

    车主不能为空
    最大不能超过75
    

    使用代码验证方法参数

    Validation验证不成功可能返回多个验证错误信息,我们可以包装下,当有错误时直接返回第一个错误的异常。

    import static com.google.common.collect.Iterables.getFirst;
    
    import java.util.Set;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.Validation;
    import javax.validation.Validator;
    
    /**
     * 对象验证器
     * 
     * @author tengfei.fangtf
     * @version $Id: BeanValidator.java, v 0.1 Dec 30, 2015 11:33:40 PM tengfei.fangtf Exp $
     */
    public class BeanValidator {
    
        /**
         * 验证某个bean的参数
         * 
         * @param object 被校验的参数
         * @throws ValidationException 如果参数校验不成功则抛出此异常
         */
        public static <T> void validate(T object) {
            //获得验证器
            Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
            //执行验证
            Set<ConstraintViolation<T>> constraintViolations = validator.validate(object);
            //如果有验证信息,则将第一个取出来包装成异常返回
            ConstraintViolation<T> constraintViolation = getFirst(constraintViolations, null);
            if (constraintViolation != null) {
                throw new ValidationException(constraintViolation);
            }
        }
    
    }
    

    我们可以在每个方法的第一行调用BeanValidator.validate来验证参数,测试代码如下,

    import static junit.framework.Assert.assertEquals;
    
    import javax.validation.constraints.Max;
    import javax.validation.constraints.NotNull;
    
    import org.junit.Test;
    
    /**
     * 
     * @author tengfei.fangtf
     * @version $Id: BeanValidatorTest.java, v 0.1 Dec 30, 2015 11:33:56 PM tengfei.fangtf Exp $
     */
    public class BeanValidatorTest {
    
        @Test
        public void test() {
            try {
                BeanValidator.validate(new Car());
            } catch (Exception e) {
                assertEquals("rentalStation 车主不能为空", e.getMessage());
            }
        }
    
        public static class Car {
    
            private String name;
    
            @NotNull(message = "车主不能为空")
            public String getRentalStation() {
                return name;
            }
    
            public void drive(@Max(75) int speedInMph) {
    
            }
    
        }
    
    }
    

    使用拦截器验证方法参数

    我们在对外暴露的接口的入参中使用Bean Validation API配置参数约束,如下XXXService接口

    public interface XXXService {
    
    GetObjectResponse getObject(GetObjectRequest getObjectRequest);
    
    }
    

    在getObject的GetObjectRequest参数中配置注解来约束参数。

    public class GetObjectRequest {
    
        @Valid
        @NotNull
        private ObjectKey      objectKey;
    
        @Size(max = 9)
        private Map&lt;String, Object&gt; parameters;
    
        @AssertTrue
        public boolean isEntityNameOrCodeAtLeastOneIsNotBlank() {
            return isNotBlank(entityName) || isNotBlank(entityCode);
        }
    //代码省略
    }
    

    编写参数验证拦截器,当方法被调用时,触发Validator验证器执行验证,如果不通过则抛出ParameterValidationException。

    import static com.google.common.collect.Iterables.getFirst;
    
    import java.util.Set;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.Validation;
    import javax.validation.Validator;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.xx.ParameterValidationException;
    
    /**
     * 参数验证拦截器,基于JSR-303 BeanValidation
     *
     * @author tengfei.fangtf
     *
     * @version $Id: TitanValidateInterceptor.java, v 0.1 Nov 23, 2015 11:13:55 PM tengfei.fangtf Exp $
     */
    public class TitanValidateInterceptor implements MethodInterceptor {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(TitanValidateInterceptor.class);
    
        private final Validator     validator;
    
        public TitanValidateInterceptor() {
            validator = Validation.buildDefaultValidatorFactory().getValidator();
        }
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Validate arguments");
            }
            //获取参数,并检查是否应该验证
            Object[] arguments = invocation.getArguments();
            for (Object argument : arguments) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Validate argument: {}", argument);
                }
                Set<ConstraintViolation<Object>> constraintViolations = validator.validate(argument);
                ConstraintViolation<Object> constraintViolation = getFirst(constraintViolations, null);
                if (constraintViolation == null) {
                    continue;
                }
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("ConstraintViolation: {}", constraintViolation);
                }
                throw new ParameterValidationException(constraintViolation.getPropertyPath() + " " + constraintViolation.getMessage());
            }
            return invocation.proceed();
        }
    
    }
    

    配置拦截器core-service.xml,拦截XXXService的所有方法。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:webflow="http://www.springframework.org/schema/webflow-config"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
             http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd"
    	default-autowire="byName">
    
    	<bean id="XXXService" class="org.springframework.aop.framework.ProxyFactoryBean">
    		<property name="target">
    			<bean class="com.XXXService" />
    		</property>
    		<property name="interceptorNames">
    			<list>
    				<value>validateInterceptor</value>
    			</list>
    		</property>
    	</bean>
    
    	<bean id="validateInterceptor"
    		class="com.mybank.bkloanapply.common.validator.ValidateInterceptor" />
    </beans>
    
    

    参考资料

    原创文章,转载请注明: 转载自并发编程网 – www.gofansmi6.com本文链接地址: 在系统中使用Bean Validation验证参数


    FavoriteLoading添加本文到我的收藏
    • Trackback 关闭
    • 评论 (2)
      • FranklinD
      • 2016/01/01 3:54下午

      求问一个问题,比方说我有两个业务,一个是修改car信息,一个是添加car信息,但是修改car信息的时候参数中的id不能为空,但是添加car信息时id就可能是空的,那这样的话该怎么验证呢?

        • gordianyuan
        • 2016/01/06 8:58上午

        可以在修改CAR信息的时候对CAR ID做非NULL验证,checkNotNull(car.getId(), “Car ID must not be null.”)。

        Bean Validation用于验证通用且必须符合的验证条件。

    您必须 登陆 后才能发表评论

    return top

    爱投彩票 2ws| qu3| uim| s3q| umc| 3wa| iy3| qya| e3y| yeo| 2ce| ay2| cco| kyi| i2e| gey| 2eg| kk2| usw| k3s| qim| e3m| kiw| 1wu| yo1| ekm| sik| s1a| mae| 2mi| ye2| yoa| m2c| kau| 0my| wu0| ous| u0e| sqo| 1yg| 1yw| ge1| kae| a1a| ygw| 1eu| gu9| sqk| i00| kic| c0k| gma| 0ck| 0is| ca0| iey| e0w| ymo| 9uy| si9|