BindingResult 验证请求数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BindingResult 验证请求数据相关的知识,希望对你有一定的参考价值。

参考技术A BindingResult用在实体类校验信息返回结果绑定。

实体类常用的校验注解有:

## 空检查

@NotEmpty: 用在集合类上面;不能为null,而且长度必须大于0

@NotBlank: 用在String上面;只能作用在String上,不能为null,而且调用trim()后,长度必须大于0

@NotNull: 用在基本类型上;不能为null,但可以为empty。

## 长度检查

@Size(min=,max=): 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内

不要错用了异常类型,比如在int上不可用@size

@Length(min=, max=)  : 只适用于String 类型

##  Booelan检查

@AssertTrue :   验证 Boolean 对象是否为 true

@AssertFalse :  验证 Boolean 对象是否为 false

##  日期检查

@Past:  验证 Date 和 Calendar 对象是否在当前时间之前

@Future:  验证 Date 和 Calendar 对象是否在当前时间之后

##  数值检查

建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为"" 时无法转换为int,但可以转换为Stirng为"",Integer为null

@Min:  验证 Number 和 String 对象是否大等于指定的值

@Max:  验证 Number 和 String 对象是否小等于指定的值

@DecimalMax:   被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度

@DecimalMin: 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度

@Pattern(regexp = "[abc]")  验证 String 对象是否符合正则表达式的规则

@Email 被注释的元素必须是电子邮件地址

@Range  被注释的元素必须在合适的范围内

@CreditCardNumber 对信用卡号进行一个大致的验证

@Digits(integer=,fraction=): 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。

以上注解在使用时,都可以设置自定义message提示信息。

将 JSR-303 验证错误转换为 Spring 的 BindingResult

【中文标题】将 JSR-303 验证错误转换为 Spring 的 BindingResult【英文标题】:Convert JSR-303 validation errors to Spring's BindingResult 【发布时间】:2013-01-31 08:06:45 【问题描述】:

我在 Spring 控制器中有以下代码:

@Autowired
private javax.validation.Validator validator;

@RequestMapping(value = "/submit", method = RequestMethod.POST)
public String submitForm(CustomForm form) 
    Set<ConstraintViolation<CustomForm>> errors = validator.validate(form);
    ...

是否可以将errors 映射到Spring 的BindingResult 对象而无需手动检查所有错误并将它们添加到BindingResult?像这样的:

// NOTE: this is imaginary code
BindingResult bindingResult = BindingResult.fromConstraintViolations(errors);

我知道可以用@Valid 注释CustomForm 参数并让Spring 注入BindingResult 作为另一个方法的参数,但在我的情况下这不是一个选项。

// I know this is possible, but doesn't work for me
public String submitForm(@Valid CustomForm form, BindingResult bindingResult) 
    ...

【问题讨论】:

【参考方案1】:

一个更简单的方法是使用 Spring 的抽象 org.springframework.validation.Validator 代替,您可以通过在上下文中使用这个 bean 来获取验证器:

<bean id="jsr303Validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

@Autowired @Qualifier("jsr303Validator") Validator validator;

有了这个抽象,你可以这样使用验证器,传入你的 bindingResult:

validator.validate(obj, bindingResult);

【讨论】:

谢谢!这肯定更简洁。 我没有看到方法 validate 接受 BindingResult 如果您没有看到接受绑定结果的 validate 方法,则表示您的 Validator 验证器是 javax.validation.Validator。将其更改为 org.springframework.validation.Validator 就可以了。无需更改 bean 定义。【参考方案2】:

Spring 使用 SpringValidatorAdapter 将 javax.validation.ConstraintViolation 对象转换为 ObjectError 或 FieldError 对象,如绑定结果中所示。 然后 BindStatus 使用消息源(如 Web 应用程序上下文本身)来转换错误。 简而言之,您可以这样做:

SpringValidatorAdapter springValidator = new SpringValidatorAdapter(validator);
BindingResult bindingResult= new BeanPropertyBindingResult(myBeanToValidate, "myBeanName");
springValidator.validate(myBeanToValidate, bindingResult);

这在编写单元测试时更容易,因为您甚至不需要创建 Spring 上下文。

【讨论】:

【参考方案3】:

扩展 Kristiaan 的答案,出于测试目的,没有必要创建一个 spring 上下文来使用 Spring 的 bindingResult 进行验证。下面是一个例子:

public class ValidatorTest 

    javax.validation.Validator javaxValidator = Validation.buildDefaultValidatorFactory().getValidator();
    org.springframework.validation.Validator springValidator = new SpringValidatorAdapter(javaxValidator);

    @Test
    public void anExampleTest() 

    JSR303AnnotatedClassToTest   ctt  = new JSR303AnnotatedClassToTest( ..init vars..)

    ... test setup...

    WebDataBinder dataBinder = new WebDataBinder(ctt);
    dataBinder.setValidator(springValidator);
    dataBinder.validate();
    BindingResult bindingResult = dataBinder.getBindingResult(); 

    ... test analysis ...

    

这种方法不需要提前创建绑定结果,dataBinder 会为您构建正确的结果。

【讨论】:

【参考方案4】:
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public String submitForm(CustomForm form) 
    Set<ConstraintViolation<CustomForm>> errors = validator.validate(form);

    BindingResult bindingResult = toBindingResult(errors, form, "form");
    ...


private BindingResult toBindingResult(ConstraintViolationException e, Object object, String objectName) 
    BindingResult bindingResult = new BeanPropertyBindingResult(object, objectName);
    new AddConstraintViolationsToErrors().addConstraintViolations(e.getConstraintViolations(), bindingResult);
    return bindingResult;


private static class AddConstraintViolationsToErrors extends SpringValidatorAdapter 
    public AddConstraintViolationsToErrors() 
        super(Validation.buildDefaultValidatorFactory().getValidator()); // Validator is not actually used
    

    @SuppressWarnings("rawtypes", "unchecked")
    public void addConstraintViolations(Set<? super ConstraintViolation<?>> violations, Errors errors) 
        // Using raw type since processConstraintViolations specifically expects ConstraintViolation<Object>
        super.processConstraintViolations((Set) violations, errors);
    

与此问题的其他答案不同,此解决方案处理已经存在需要转换为 BindingResultSet&lt;ConstraintViolation&lt;?&gt;&gt; 的情况。

说明

Spring 提供了SpringValidatorAdapter 类来执行bean 验证,将结果存储在Errors 实例中(注意BindingResult 扩展了Errors)。此类的正常手动使用是通过validate 方法使用它来执行验证:

Validator beanValidator = Validation.buildDefaultValidatorFactory().getValidator();
SpringValidatorAdapter validatorAdapter = new SpringValidatorAdapter(beanValidator);

BindException bindException = new BindException(form, "form");
validatorAdapter.validate(form, bindException);

但是,在已经存在需要转换为 BindingResultSet&lt;ConstraintViolation&lt;?&gt;&gt; 的情况下,这无济于事。

实现这个目标仍然是可能的,尽管它确实需要多跳几圈。 SpringValidatorAdapter 包含一个processConstraintViolations 方法,它将ConstraintViolation 对象转换为适当的Spring ObjectError 子类型,并将它们存储在Errors 对象上。然而,这个方法是受保护的,限制了它对子类的访问。

可以通过创建SpringValidatorAdapter 的自定义子类来解决此限制,该子类委托或公开受保护的方法。这不是典型的用法,但它确实有效。

public class AddConstraintViolationsToErrors extends SpringValidatorAdapter 
    public AddConstraintViolationsToErrors() 
        super(Validation.buildDefaultValidatorFactory().getValidator()); // Validator is not actually used
    

    @SuppressWarnings("rawtypes", "unchecked")
    public void addConstraintViolations(Set<? super ConstraintViolation<?>> violations, Errors errors) 
        // Using raw type since processConstraintViolations specifically expects ConstraintViolation<Object>
        super.processConstraintViolations((Set) violations, errors);
    

此自定义类可用于填充新创建的BindingResult,实现从Set&lt;ConstraintViolation&lt;?&gt;&gt; 创建BindingResult 的目标。

private BindingResult toBindException(ConstraintViolationException e, Object object, String objectName) 
    BindingResult bindingResult = new BeanPropertyBindingResult(object, objectName);
    new AddConstraintViolationsToErrors().addConstraintViolations(e.getConstraintViolations(), bindingResult);
    return bindingResult;

【讨论】:

【参考方案5】:

我遇到过类似的问题,我就是这样解决的。

根据你的例子,这就是我实现它的方式

首先,我使用了一个智能验证器,在方法中我让 spring 注入了 BindingResult

@Autowired
private org.springframework.validation.SmartValidator validator;

@RequestMapping(value = "/submit", method = RequestMethod.POST)
public String submitForm(CustomForm form, BindingResult bindingResult) 
    Set<ConstraintViolation<CustomForm>> errors = validator.validate(form);
    ...

然后使用该绑定结果,我将其传递给 SmartValidator,以便将任何错误绑定到 BindingResult。

validator.validate(form, bindingResult);
if(bindingResult.hasErrors()) 
     throw new BindException(bindingResult);

【讨论】:

以上是关于BindingResult 验证请求数据的主要内容,如果未能解决你的问题,请参考以下文章

Spring - 将 BindingResult 添加到新创建的模型属性

Spring验证的错误返回------BindingResult

使用aop和BindingResult进行参数验证

java Spring验证:如何向BindingResult添加错误

无法将数据保存到 mysql db,在 gradle 项目中,bean 名称“goal”的 BindingResult 和普通目标对象都不能用作请求属性

将 JSR-303 验证错误转换为 Spring 的 BindingResult