在Spring Boot项目中,我需要验证业务规则,而我正在尝试使用Bean验证来做到这一点。
我写了一个单独的类来放置我的业务规则,并使用“返回值约束”技术来实现。 但是,Validator.validate()方法调用了我的约束方法两次。
为什么?以及如何解决这个问题?
下面的简单代码更容易理解该问题:
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
@Autowired
private Validator validator;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
DemoObject obj = new DemoObject();
validator.validate(obj);
}
}
class DemoObject {
@AssertTrue(message="My business rule was failed")
public boolean isMyBusinessRule() {
System.out.println("isMyBusinessRule called");
// ... my business rule validation code ...
return true;
}
}
方法isMyBusinessRule()被调用了两次。输出控制台显示:
isMyBusinessRule called
isMyBusinessRule called
如何解决这个问题?
答案 0 :(得分:0)
我刚刚在Spring Boot 2.2上进行了测试,发现同样的事情。
现在,您甚至不应该考虑通过Hibernate Validator
实现调用该方法一次,两次甚至更多次的事实。
仅出于记录目的,在处理验证之前第一次调用它以检查是否需要验证。
如果需要验证,则处理约束,然后第二次读取:从而再次调用带有注释的方法。
这里用我的3条评论方法来说明流程:
private boolean validateMetaConstraint(ValidationContext<?> validationContext, ValueContext<?, Object> valueContext, Object parent, MetaConstraint<?> metaConstraint) {
// .... FIRST INVOCATION
if ( isValidationRequired( validationContext, valueContext, metaConstraint ) ) {
if ( parent != null ) {
// .... SECOND INVOCATION with valueContext.getValue()
valueContext.setCurrentValidatedValue( valueContext.getValue( parent, metaConstraint.getLocation() ) );
}
success = metaConstraint.validateConstraint( validationContext, valueContext );
validationContext.markConstraintProcessed( valueContext.getCurrentBean(), valueContext.getPropertyPath(), metaConstraint );
}
// ....
}
该行为来自ValueContext
class,该行为存储验证信息,并且出于优化或处理的原因,该行为可能会多次调用:
此类的一个实例用于收集所有相关的 验证单个类,属性或方法的信息 调用。
仍然忘记了它,这是实现的细节,明天在下一版本中,可以一次调用带注释的方法,并且永远不要破坏您的逻辑。因此,请不要依赖它。
重要的是,API遵守其合同并且做到了:即使实现两次调用了该方法,也将返回单个验证错误。
public class DemoObj {
private final boolean value;
DemoObj(boolean value){
this.value = value;
}
@AssertTrue(message = "My business rule was failed")
public boolean isMyBusinessRule() {
System.out.println("isMyBusinessRule called");
return value;
}
}
使用它:
Set<ConstraintViolation<DemoObj>> constraintViolations = validator.validate(new DemoObj (true));
System.out.println("validations errors : " + constraintViolations.size());
constraintViolations = validator.validate(new DemoObj (false));
System.out.println("validation errors : " + constraintViolations.size());
输出:
isMyBusinessRule called
isMyBusinessRule called
validations errors : 0
isMyBusinessRule called
isMyBusinessRule called
validation errors : 1