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

转自:http://www.importnew.com/18561.html

为什么要使用Bean Validation?

当我们实现某个接口时,都需要对入参数进行校验。例如下面的代码


1

2

3

4

5

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


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

<!-- 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,也可以验证方法参数


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

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) {

        }

    }

}

执行代码后,输出如下:


1

2

车主不能为空

最大不能超过75

使用代码验证方法参数

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


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

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来验证参数,测试代码如下,


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

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接口


1

2

3

4

5

public interface XXXService {

GetObjectResponse getObject(GetObjectRequest getObjectRequest);

}

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


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

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的所有方法。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

<?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>

参考资料

原文地址:https://www.cnblogs.com/toSeeMyDream/p/9414450.html

时间: 2024-10-18 16:49:52

在系统中使用Bean Validation验证参数的相关文章

SpringMVC中实现Bean Validation(JSR 303 JSR 349 JSR 380)

JSR 303是针对bean数据校验提出的一个规范.使用注解方式实现数据校验. 每个注解的用法这里就不多介绍,请移步JSR 303 - Bean Validation 介绍及最佳实践 笔者上面提到的JSR303是专家组成员向JCP提交的第一版Bean Validation, 主流Bean Validation使用Hibernate的实现,本文使用hibernate-validator 各个版本的规范对应关系如下: JSR 380 (Bean Validation 2.0) JSR 349 (Be

EBS系统中各种特殊变量,特殊参数引用格式的汇总

1. 在建立说明性弹性域的参考列时,如果不想参考本表的字段,而是想参考系统的某个变量时,可以这样写 $PROFILES$.USER_ID 2. 在做多层级联弹性域时,如果下一层弹性域想引用上一层弹性域的取值,可以在下一层弹性域所引用的值集的where语句设置中这样写: $FLEX$.PROVINCE,其中PROVINCE为上一层弹性域的引用字段的列名. 3.report builder中取得报表request id RETURN :P_CONC_REQUEST_ID; fnd_global.co

linux系统中useradd和usermod命令参数讲解

useradd 命令,添加用户: 参数描述  -c comment 给新用户添加备注 -d home_dir 为主目录指定一个名字(如果不想用登录名作为主目录名的话) -e expire_date 用YYYYY-MM-DD格式指定一个账户过期的日期 -f inactive_days 指定这个帐户密码过期后多少天这个账户被禁用:0表示密码一过期就立即禁用,-1表示禁用这个功能 -g initial_group 指定用户登录组的GID或组名 -G group ... 指定用户除登录组之外所属的一个或

JSR 303 - Bean Validation 介绍及最佳实践

JSR 303 – Bean Validation 是一个数据验证的规范,2009 年 11 月确定最终方案.2009 年 12 月 Java EE 6 发布,Bean Validation 作为一个重要特性被包含其中.本文将对 Bean Validation 的主要功能进行介绍,并通过一些示例来演示如何在 Java 开发过程正确的使用 Bean Validation. 1 评论: 安 大鹏, 软件工程师, IBM 杨 乐, 软件工程师, IBM 翁 志弘, 软件工程师, IBM 2011 年

一个新人如何学习在大型系统中添加新功能和Debug

文章背景: 今年七月份正式入职,公司主营ERP软件,楼主所在的组主要负责二次开发,使用的语言是Java. 什么叫二次开发呢?ERP软件的客户都是企业.而这些企业之间的情况都有所不同,一套标准版本的企业资源管理系统必然难以百分之一百地满足每一家公司的所有要求.所以,在客户提出需求之后,程序员对系统进行增减修改,这就是二次开发. 另外,我们组还负责修复客户报上来的各种漏洞. 学会如何添加新模块新功能 为什么说从头到尾只看代码是不可行的? 基本上,财务系统跨越的年限都会有十几二十年,代码数千万级别,更

.Net Core Web Api使用模型验证验证参数合法性

原文:.Net Core Web Api使用模型验证验证参数合法性 在接口开发过程中免不了要去验证参数的合法性,模型验证就是帮助我们去验证参数的合法性,我们可以在需要验证的model属性上加上Data Annotations特性后就会自动帮我们在action前去验证输入数据的合法性. 1.定义一个Person类 public class PersonDto { public string Name { get; set; } public string Phone { get; set; } p

Java参数验证Bean Validation 框架

1.为什么要做参数校验? 参数校验和业务逻辑代码分离,参数校验代码复用,统一参数校验方式.校验不太通过时统一异常描述. 2.bean validation规范 JSR303 规范(Bean Validation 规范)提供了对 Java EE 和 Java SE 中的 Java Bean 进行验证的方式.该规范主要使用注解的方式来实现对 Java Bean 的验证功能,并且这种方式会覆盖使用 XML 形式的验证描述符,从而使验证逻辑从业务代码中分离出来.JSR303注解如下: Hibernate

SpringMVC 使用验证框架 Bean Validation(上)

SpringMVC 使用验证框架 Bean Validation(上) 对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证. SpringMVC 自身对数据在服务端的校验(Hibernate Validator)有一个比较好的支持,它能将我们提交到服务端的数据按照我们事先的约定进行数据有效性验证,对于不合格的数据信息 SpringMVC 会把它保存在错误对象中(Errors接口的子类),这些错误信息我们也可以通过 Spri

基于Java Bean Validation对Request参数进行校验的设计思路

摘自Hibernate Validator文档: 数据校验是任何一个应用程序都会用到的功能,无论是显示层还是持久层. 通常,相同的校验逻辑会分散在各个层中, 这样,不仅浪费了时间还会导致重复代码的发生. 为了避免重复, 开发人员经常会把这些校验逻辑直接写在领域模型里面, 但是这样又把领域模型代码和校验代码混杂在了一起, 而这些校验逻辑更应该是描述领域模型的元数据. JSR 303 - Bean Validation (version 1.1)- 为实体验证定义了元数据模型和API. 默认的元数据