首页 > 解决方案 > 有时基于来自数据库的配置验证制造商属性的 bean 约束

问题描述

我们能否实现@NotNull 约束只有在数据库中启用才能执行?

public class Vehicle {
  @NotNull //supposed to execute only if configuration in database is enable to execute this @Notnull annotation
  private String manufacturer;  
  private String id;
}

标签: springhibernatebean-validationhibernate-validatorspring-validator

解决方案


我不能使用自定义约束,因为我必须为每个约束实现。所以请与社区核实我是否可以利用一些我不知道的功能

为什么不实现一个自定义约束来验证所有这些可选的验证规则呢?只需使用类级约束而不是字段级约束。它看起来像这样:


@FieldsRequiredForSpecialCountries // inside, use @Target(TYPE) instead of @Target(FIELD)
public class Vehicle {...}

class FieldsRequiredForSpecialCountriesValidator implements ConstraintValidator<FieldsRequiredForSpecialCountries, Vehicle> {
    // constructor etc.

    @Autowired
    private CountryRepository repository;

    public void validate(Vehicle input, ConstraintValidationContext context) {
        if (input != null && repository.isSpecialCountry(input.getCountry()) {
            if (Objects.isEmpty(input.getManufacturer()) {
                context.disableDefaultConstraintViolation()
                    .buildConstraintViolationWithTemplate("must not be empty")
                    .addPropertyNode("manufacturer")
                    .addConstraintViolation();
                return false;
            }
            ... // the rest of the rules, you could also collect all the rules first instead of immediately returning when a violation is found
        }
        return true;
    }
}

我能想到的唯一选择是使用约束组

public interface SpecialCountriesOnly {}

public class Vehicle {

    @NotNull(groups = SpecialCountriesOnly.class)
    private String manufacturer;
}

但是,要使用它,您必须:

  1. 以编程方式调用验证器,根据国家/地区使用正确的组:
@Autowired
private Validator validator;
...

if (countryRepository.isSpecialCountry(vehicle.getCountry()) {
    var constraintViolations = validator.validate(vehicle, javax.validation.groups.Default.class, SpecialCountriesOnly.class);
    ... // do sth with the violations, e.g. wrap in `ConstraintViolationException`)
} else {
    var constraintViolations = validator.validate(vehicle); // only the default group is validated here
    ...
}
  1. 保留声明性方法,而是为“特殊”国家和常规国家/地区公开单独的服务/控制器方法:
public void saveRegularCountryVehicle(@Validated @IsRegularCountry Vehicle vehicle) {
    ...
}

public void saveSpecialCountryVehicle(@Validated({{Default.class, SpecialCountriesOnly.class}) @IsSpecialCountry Vehicle vehicle) {
    
}

推荐阅读