How can a Spring Boot web app validate a form field that is required conditional on another field?

huangapple go评论164阅读模式
英文:

How can a Spring Boot web app validate a form field that is required conditional on another field?

问题

我有一个Spring Boot Web应用程序,在这个应用程序中,我的表单后端Bean的字段被注解为Bean Validation注解(参见Baeldung的教程spring.io的文档)。例如,Customer bean上的字段可以像这样被注解:

@NotBlank
@Pattern(regexp="[ \\.A-Za-z-]*")
private String firstName;

@DateTimeFormat(pattern="M/d/yyyy")
@NotNull
@Past
private Date DOB;

我想知道的是:我如何实现一个复杂的验证,它涉及多个字段? 我是说,使用这个框架。例如,假设我有一个字段Country和一个字段ZipCode,我希望只有当Country等于"US"时,ZipCode才需要@NotBlank,否则是可选的。

在我的控制器中,验证非常优雅地通过使用@Valid注解触发,错误会附加到BindingResult对象上。像这样:

@PostMapping("customer/{id}")
public String updateCustomer(@PathVariable("id") Integer id,
                             @Valid @ModelAttribute("form") CustomerForm form,
                             BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "customerview";
    }
    customerService.updateCustomer(form);
    return "redirect:/customer/" + id;
}

我希望找到的是一种编写这个条件验证器的方式,使它也可以通过@Valid注解触发,并将其错误消息附加到BindingResult中的ZipCode字段。理想情况下,我不应该需要改变控制器代码。

英文:

I have a Spring Boot web app in which fields of my form-backing bean are annotated with Bean Validation annotations (see Baeldung's tutorial or the docs at spring.io). For example, fields on Customer beans might be annotated like this:

@NotBlank
@Pattern(regexp="[ \\.A-Za-z-]*")
private String firstName;

@DateTimeFormat(pattern="M/d/yyyy")
@NotNull
@Past
private Date DOB;

What I want to know is: (How) Can I implement a complex validation that looks at multiple fields? I mean, using this framework. For example, let's say I have a field Country and a field ZipCode and I want the ZipCode to be @NotBlank if and only if the Country equals "US", optional otherwise.

In my Controller, the validation is very elegantly triggered with the use of the @Valid annotation, and errors are attached to a BindingResult object. Like so:

@PostMapping("customer/{id}")
public String updateCustomer( @PathVariable("id") Integer id,
                              @Valid @ModelAttribute("form") CustomerForm form, 
                              BindingResult bindingResult ) {
    if (bindingResult.hasErrors()) {
        return "customerview";
    }
    customerService.updateCustomer(form);
    return "redirect:/customer/"+id;
}

What I'm hoping to find is a way to write this conditional validator in a way that it, too, will be triggered by the @Valid annotation and will attach it's error message to the ZipCode field in the BindingResult. Ideally I shouldn't have to change the Controller code at all.

答案1

得分: 1

你可以获取创建自定义验证器类的帮助,以下链接可以帮助您:
https://www.baeldung.com/spring-mvc-custom-validator#custom-validation

英文:

you can getting help of creating custom validator class, the following link helps you:
https://www.baeldung.com/spring-mvc-custom-validator#custom-validation

答案2

得分: 1

对于这种情况,您需要使用交叉字段验证。请尝试:

创建注解:

package foo.bar;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {CustomerValidator.class})
public @interface CustomerValid {
 
    String message() default "{foo.bar.CustomerValid.message}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
 
}

创建自定义验证器:

public class CustomerValidator implements ConstraintValidator<CustomerValid, Customer> {
 
    @Override
    public void initialize(CustomerValid constraint) {
    }
 
    @Override
    public boolean isValid(Customer customer, ConstraintValidatorContext context) {
        return !("US".equals(customer.getCountry()) && "".equals(customer.getZipCode()));
    }
}

为您的类添加注解:

@CustomerValid
public class Customer {
    // 类主体
}

此类验证将与现有字段验证一起进行处理。

英文:

For this kind of stuff you need to use cross field validation. Please try :

Create annotation :

package foo.bar;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {CustomerValidator.class})
public @interface CustomerValid {
 
    String message() default &quot;{foo.bar.CustomerValid.message}&quot;;
    Class&lt;?&gt;[] groups() default {};
    Class&lt;? extends Payload&gt;[] payload() default {};
 
}

Create custom validator :

public class CustomerValidator implements ConstraintValidator&lt;CustomerValid, Customer&gt; {
 
    @Override
    public void initialize(CustomerValid constraint) {
    }
 
    @Override
    public boolean isValid(Customer customer, ConstraintValidatorContext context) {
        return !(&quot;US&quot;.equals(customer.getCountry() &amp;&amp; &quot;&quot;.equals(customer.getZipCode())));
    }
}

Annotate your class :

@CustomerValid
public class Customer {
// body
}

This class validation will be processed in addition to existent field validators.

huangapple
  • 本文由 发表于 2020年4月10日 03:42:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/61129021.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定