【问题标题】:Configuring spring validation and hibernate validation配置spring验证和hibernate验证
【发布时间】:2019-11-08 23:01:37
【问题描述】:

问题已经在这里解决了,但对我不起作用(我猜不是相同的 spring boot 版本)this

尝试编写自定义约束验证器,以在持久化之前检查帐户电子邮件是否存在。

@Email
@NotNull
@NotBlank
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueCompteEmailValidator.class)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
public @interface UniqueCompteEmail {

    String message() default "{com.mssmfactory.bacsimulator.uniquecompteemail.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

// --------------------------------------------- -----------------------------

public class UniqueCompteEmailValidator implements ConstraintValidator<UniqueCompteEmail, String> {

    @Autowired
    private CompteRepository compteRepository;

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value != null && this.compteRepository.findByEmail(value) == null;
    }
}

// --------------------------------------------- -----------------------------

@Configuration
public class OtherConfigurations {

    //----

    @Bean
    public Validator validator(@Autowired AutowireCapableBeanFactory autowireCapableBeanFactory) {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class).configure()
                .constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        return validator;
    }
}

// --------------------------------------------- -----------------------------

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.mssmfactory</groupId>
    <artifactId>bacsimulator</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>bacsimulator</name>
    <description>BAC Simulator</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jersey</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

我的问题是私有 CompteRepository compteRepository 总是包含 null,从我的堆栈跟踪中,我可以看到它是由 hibernate-validation 实例化的,而不是由 spring 实例化并由 hibernate 使用。

有什么想法吗?

【问题讨论】:

    标签: hibernate spring-boot validation dependency-injection spring-data-jpa


    【解决方案1】:

    通过这个@Component 类改变了hibernate的bean验证器工厂,现在它运行得很好

    @Component
    public class ValidatorAddingCustomizer implements HibernatePropertiesCustomizer {
    
        private final ObjectProvider<javax.validation.Validator> provider;
    
        public ValidatorAddingCustomizer(ObjectProvider<javax.validation.Validator> provider) {
            this.provider = provider;
        }
    
        public void customize(Map<String, Object> hibernateProperties) {
            Validator validator = provider.getIfUnique();
    
            if (validator != null) {
                hibernateProperties.put("javax.persistence.validation.factory", validator);
            }
        }
    }
    

    【讨论】:

    • 非Spring boot有类似的解决方案吗?我正在使用 Spring Framework 5、Hibernate 5 和 Hibernate Validator 6。我尝试了很多在 Stackoverflow 中找到的解决方案,但没有任何效果。
    • 老实说我不知道​​我总是使用 spring-boot :/
    • 太棒了。几个星期以来,我一直在不停地反对这个!
    • @Mssm 兄弟,我遵循了你的方法。但是当我试图保存我的实体时,我的验证器的 isValid 方法被重复调用,导致 stackoverflow 错误。我在这里做错了什么? friendpaste.com/6ppeO6IeXz2lr4D55QDilU
    • @Mssm 这是 stackoverflow 的问题:stackoverflow.com/questions/62896519/…
    【解决方案2】:

    您面临的问题是,当您自动装配 CompteRepository.class 时,@Autowired 注释对您不起作用。您可以在验证类中自动装配组件,但请确保使用 spring 创建验证器 bean,否则bean 注入无法使用验证工厂手动创建验证器 bean(Hibernate Validator 作为参考实现不会将依赖项注入到 ConstraintValidator 实例中

    因此,您不能使用验证器工厂来创建验证器实例,而是自动装配它,一切都会正常工作。

    @AutoWired
    Validator validator;
    ...
    
    validator.validate(book);
    

    【讨论】:

    • 我正在使用注释来验证获得的 java pojo 字段抛出一个远程访问(基本上是一个发布请求)到一个暴露的 rest 存储库,我不是那个必须调用 validator.validate(entity ),它由验证器调用...
    • 与其自己配置验证器bean,不如让spring来处理。
    • 如果我不再配置我的验证器,我只需配置 hibernate 验证器工厂,这样 hibernate 就不会实例化验证器,而是使用 spring intanciated 并且在 spring 上下文中的验证器
    猜你喜欢
    • 2018-06-20
    • 2016-12-17
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    • 2015-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多