Spring MVC和@Validate:仅在特定条件下或用户更改属性时执行验证
控制器方法需要一个Spring MVC和@Validate:仅在特定条件下或用户更改属性时执行验证,spring,validation,spring-mvc,Spring,Validation,Spring Mvc,控制器方法需要一个@NotNull@Valid@modeldattribute Person。 个人具有@有效地址属性 在PersonController.create(@NotNull@Valid@modeldattribute Person Person,BindingResult BindingResult…)上,我需要验证Person.address,前提是用户设置了地址的任何字段或基于Person实例的字段值(例如Person.hasAddress=true) 问题在于,默认情况下,s
@NotNull@Valid@modeldattribute Person
。
个人
具有@有效地址
属性
在PersonController.create(@NotNull@Valid@modeldattribute Person Person,BindingResult BindingResult…)上,我需要验证Person.address,前提是用户设置了地址的任何字段或基于Person实例的字段值(例如Person.hasAddress=true)
问题在于,默认情况下,spring创建了一个新的Address实例,该实例在createForm提交时提交,在验证时失败
我亲自创建了一个crossproperty验证,它要求地址在hasAddress=true时不为null,但无法解决地址字段中验证的问题
我尝试使用@InitBinder(“地址”)
/@InitBinder(“person.address”)
来设置binder.setAutologownestedPath(false)代码>但我打不到这个电话。全局使用@InitBinder会导致其他属性出现其他问题
我在考虑组,但只有当您在开发时知道是否需要验证时,才可以使用组。在我的情况下,根据地址或hasAddress字段的任何更改,它将在提交时被知道
有什么想法吗?中也有类似的问题()
我的解决方案的主要思想是动态绑定数据,即逐步有条件地绑定和验证输入数据:
我创建了一个新的注释类@BindingGroup
。它类似于验证约束注释的groups参数。在我的解决方案中,您可以使用它来指定一组没有验证约束的字段
我创建了一个名为GroupAwareDataBinder的定制活页夹。调用此绑定器时,将传递一个组,并且绑定器仅绑定属于此组的字段。要为字段设置组,可以使用新的@BindingGroup
注释。由于也可能存在正常组足够的情况,绑定器还会查找验证约束的“组”参数。为方便起见,活页夹提供了一种方法bindAndValidate()
指定名为BasicCheck
的绑定组和第二个绑定组AddressCheck
,并将它们分配给Person和Address类的相应字段
现在,您可以在控制器方法中逐步执行数据绑定。下面是一些伪代码:
//create a new binder for a new Person instance
result = binder.getBindingResult();
binder.bindAndValidate(data, BasicCheck.class);
if (person.hasAddress)
binder.bindAndValidate(data, AddressCheck.class);
if (!result.hasErrors())
// do something
正如您所看到的,缺点是您必须自己执行绑定,而不是使用漂亮的注释
以下是我的源代码:
绑定组:
import java.lang.annotation.*;
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BindingGroup
{
Class<?>[] value() default {};
}
Person类字段的一些示例:
@NotNull(groups = BasicCheck.class)
public String getName() { return name; }
@BindingGroup(BasicCheck.class)
public String phoneNumber() { return phoneNumber; }
@Valid
public Address getAddress() { return address; }
地址类别:
@BindingGroup(BasicCheck.class)
public Integer getZipCode() { return zipCode; }
写这个答案需要很多工作,所以我希望它能帮助你。这个答案是针对@InitBinder
部分的。Javadoc说注释的值是这个init binder方法应该应用的[model attribute]的名称
我认为您应该明确地为model属性设置一个名称,并为@InitBinder
@InitBinder("person_with_address")
public void ...
...
public String create(@NotNull @Valid @ModelAttribute("person_with_address") Person person, BindingResult bindingResult...)
这样,您应该能够为该控制器方法使用专用绑定
从地址字段中删除了@Valid
手动验证:在控制器的create
方法中:validateAddressIfNeeded(person,bindingResult)
感谢@fishbone的回复,不幸的是,我无法接受,因为我发现它很复杂,并且由于工作的规模,可能会成为遗留问题或引入新的bug。请看下面我最后遵循的方法。不太理想,但它比较短,维护的代码也比较少。这看起来确实比实际情况更复杂。它只是一个尊重组的绑定器,而不是绑定整个数据。如果您想定义一个组,但没有验证约束,那么可以添加一个注释“BindingGroup”。我们经常以多步骤的形式使用它。谢谢@Serge,最后我采用了其他方法
@BindingGroup(BasicCheck.class)
public Integer getZipCode() { return zipCode; }
@InitBinder("person_with_address")
public void ...
...
public String create(@NotNull @Valid @ModelAttribute("person_with_address") Person person, BindingResult bindingResult...)
private void validateAddressIfNeeded(Person person, BindingResult bindingResult) {
if (person.hasAddress()) {
bindingResult.pushNestedPath("address");
validator.validate(person.getAddress(), bindingResult);
bindingResult.popNestedPath();
}
}