Spring 依赖于其他字段的自定义验证器
Spring custom validator with dependencies on other fields
我们正在为控制器端点中使用的请求对象使用 spring 自定义验证器。我们以与下面 link 中相同的方式实现它:
https://www.baeldung.com/spring-mvc-custom-validator
我们面临的问题是,如果特定字段也依赖于其他输入字段,它就无法工作。例如,我们将以下代码作为控制器端点的请求对象:
public class FundTransferRequest {
private String accountTo;
private String accountFrom;
private String amount;
@CustomValidator
private String reason;
private Metadata metadata;
}
public class Metadata {
private String channel; //e.g. mobile, web, etc.
}
基本上@CustomValidator 是我们的自定义验证器class,我们想要的逻辑是,如果元数据提供的渠道是“WEB”。请求的“原因”字段将不是必需的。否则,它将是必需的。
有办法吗?我已经进行了额外的研究,但看不到任何可以处理此类情况的方法。
显然,如果您需要访问自定义验证器中的多个字段,则必须使用 class-level 注释。
您提到的同一篇文章有一个例子:https://www.baeldung.com/spring-mvc-custom-validator#custom-class-level-validation
在您的情况下,它可能看起来像这样:
@Constraint(validatedBy = CustomValidator.class)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomValidation {
String message() default "Reason required";
String checkedField() default "metadata.channel";
String checkedValue() default "WEB";
String requiredField() default "reason";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
package com.example.demo;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/*
If the supplied channel from Metadata is "WEB". The field "reason" of the request won't be required.
Else, it will be required.
*/
@Component
public class CustomValidator implements ConstraintValidator<CustomValidation, Object> {
private String checkedField;
private String checkedValue;
private String requiredField;
@Override
public void initialize(CustomValidation constraintAnnotation) {
this.checkedField = constraintAnnotation.checkedField();
this.checkedValue = constraintAnnotation.checkedValue();
this.requiredField = constraintAnnotation.requiredField();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
Object checkedFieldValue = new BeanWrapperImpl(value)
.getPropertyValue(checkedField);
Object requiredFieldValue = new BeanWrapperImpl(value)
.getPropertyValue(requiredField);
return checkedFieldValue != null && checkedFieldValue.equals(checkedValue) || requiredFieldValue != null;
}
}
用法为:
@CustomValidation
public class FundTransferRequest {
...
或指定参数:
@CustomValidation(checkedField = "metadata.channel",
checkedValue = "WEB",
requiredField = "reason",
message = "Reason required")
public class FundTransferRequest {
...
我们正在为控制器端点中使用的请求对象使用 spring 自定义验证器。我们以与下面 link 中相同的方式实现它:
https://www.baeldung.com/spring-mvc-custom-validator
我们面临的问题是,如果特定字段也依赖于其他输入字段,它就无法工作。例如,我们将以下代码作为控制器端点的请求对象:
public class FundTransferRequest {
private String accountTo;
private String accountFrom;
private String amount;
@CustomValidator
private String reason;
private Metadata metadata;
}
public class Metadata {
private String channel; //e.g. mobile, web, etc.
}
基本上@CustomValidator 是我们的自定义验证器class,我们想要的逻辑是,如果元数据提供的渠道是“WEB”。请求的“原因”字段将不是必需的。否则,它将是必需的。
有办法吗?我已经进行了额外的研究,但看不到任何可以处理此类情况的方法。
显然,如果您需要访问自定义验证器中的多个字段,则必须使用 class-level 注释。
您提到的同一篇文章有一个例子:https://www.baeldung.com/spring-mvc-custom-validator#custom-class-level-validation
在您的情况下,它可能看起来像这样:
@Constraint(validatedBy = CustomValidator.class)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomValidation {
String message() default "Reason required";
String checkedField() default "metadata.channel";
String checkedValue() default "WEB";
String requiredField() default "reason";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
package com.example.demo;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/*
If the supplied channel from Metadata is "WEB". The field "reason" of the request won't be required.
Else, it will be required.
*/
@Component
public class CustomValidator implements ConstraintValidator<CustomValidation, Object> {
private String checkedField;
private String checkedValue;
private String requiredField;
@Override
public void initialize(CustomValidation constraintAnnotation) {
this.checkedField = constraintAnnotation.checkedField();
this.checkedValue = constraintAnnotation.checkedValue();
this.requiredField = constraintAnnotation.requiredField();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
Object checkedFieldValue = new BeanWrapperImpl(value)
.getPropertyValue(checkedField);
Object requiredFieldValue = new BeanWrapperImpl(value)
.getPropertyValue(requiredField);
return checkedFieldValue != null && checkedFieldValue.equals(checkedValue) || requiredFieldValue != null;
}
}
用法为:
@CustomValidation
public class FundTransferRequest {
...
或指定参数:
@CustomValidation(checkedField = "metadata.channel",
checkedValue = "WEB",
requiredField = "reason",
message = "Reason required")
public class FundTransferRequest {
...