微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用Spring 4和消息插值配置在ConstraintValidator中注入存储库

我创建了一个小示例项目,以显示我在Spring Boot验证配置及其与Hibernate集成时遇到的两个问题.
我已经尝试过我发现的有关该主题的其他回复,但遗憾的是它们对我不起作用或者要求禁用Hibernate验证.

我想使用实现ConstraintValidator的自定义Validator< ValidUser,User>并在其中注入我的UserRepository.
同时我想保持Hibernate的认行为,在更新/持久化期间检查验证错误.

在这里写的是应用程序的完整主要部分.

自定义配置
在这个类中,我使用自定义MessageSource设置自定义验证器,因此Spring将从文件resources / messages.properties中读取消息

@Configuration
public class CustomConfiguration {

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasenames("classpath:/messages");
        messageSource.setUseCodeAsDefaultMessage(false);
        messageSource.setCacheSeconds((int) TimeUnit.HOURS.toSeconds(1));
        messageSource.setFallbackToSystemLocale(false);
        return messageSource;
    }

    @Bean
    public LocalValidatorfactorybean validator() {
        LocalValidatorfactorybean factorybean = new LocalValidatorfactorybean();
        factorybean.setValidationMessageSource(messageSource());
        return factorybean;
    }

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
        methodValidationPostProcessor.setValidator(validator());
        return methodValidationPostProcessor;
    }

}

豆子
如果不是自定义验证器@ValidUser,这里没什么特别的

@ValidUser
@Entity
public class User extends AbstractPersistableinformatION **/

    @Pattern(regexp = "^\\+{1}[1-9]\\d{1,14}$")
    private String landlinePhone;

    @Pattern(regexp = "^\\+{1}[1-9]\\d{1,14}$")
    private String mobilePhone;

    @NotBlank
    @Column(nullable = false,unique = true)
    private String username;

    @Email
    private String email;

    @JsonIgnore
    private String password;

    @Min(value = 0)
    private BigDecimal cashFund = BigDecimal.ZERO;

    public User() {

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLandlinePhone() {
        return landlinePhone;
    }

    public void setLandlinePhone(String landlinePhone) {
        this.landlinePhone = landlinePhone;
    }

    public String getMobilePhone() {
        return mobilePhone;
    }

    public void setMobilePhone(String mobilePhone) {
        this.mobilePhone = mobilePhone;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getpassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public BigDecimal getCashFund() {
        return cashFund;
    }

    public void setCashFund(BigDecimal cashFund) {
        this.cashFund = cashFund;
    }

}

自定义验证器
这是我尝试注入存储库的地方.如果不禁用Hibernate验证,则存储库始终为null.

    public class UserValidator implements ConstraintValidatordisableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate("{ValidUser.unique.username}").addConstraintViolation();

                return false;
            }
        } catch (Exception e) {
            log.error("",e);
            return false;
        }
        return true;
    }

}

messages.properties

#CUSTOM VALIDATORS
ValidUser.message = I dati inseriti non sono validi. Verificare nuovamente e ripetere l'operazione.
ValidUser.unique.username = L'username [${validatedValue.getUsername()}] è già stato utilizzato. Sceglierne un altro e ripetere l'operazione.

#DEFAULT VALIDATORS
org.hibernate.validator.constraints.NotBlank.message = Il campo non può essere vuoto

# === USER ===
Pattern.user.landlinePhone = Il numero di telefono non è valido. Dovrebbe essere nel formato E.123 internazionale (https://en.wikipedia.org/wiki/E.123)

在我的测试中,您可以尝试使用源代码,我有两个问题:

>如果我不禁用Hibernate验证,则UserValidator中注入的存储库为null(spring.jpa.properties.javax.persistence.validation.mode = none)
>即使我禁用了Hibernate验证器,我的测试用例也会失败,因为有些东西会阻止Spring对验证消息使用认字符串插值,这些消息应该类似于[Constraint].[class name lowercase].[propertyName].我不想使用像@NotBlank(message =“{mycustom.message}”这样的值元素的约束注释,因为我没有看到考虑到它有自己的插值对流的点,我可以利用那……这意味着更少编码.

I attach the code;您可以运行Junit测试并查看错误(启用Hibernate验证,检查application.properties).

我究竟做错了什么?我该怎么做才能解决这两个问题?

======更新======

为了澄清,阅读Spring验证文档https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#validation-beanvalidation-spring-constraints,他们说:

By default,the LocalValidatorfactorybean configures a SpringConstraintValidatorFactory that uses Spring to create ConstraintValidator instances. This allows your custom ConstraintValidators to benefit from dependency injection like any other Spring bean.

As you can see,a ConstraintValidator implementation may have its dependencies @Autowired like any other Spring bean.

在我的配置类中,我在编写时创建了LocalValidatorfactorybean.

一个有趣的问题是thisthis,但我没有运气.

======更新2 ======

经过大量的研究,似乎用Hibernate验证器没有提供注入.

我找到了几种可以做到这一点的方法

第一路

创建此配置类:

 @Configuration
public class HibernateValidationConfiguration extends HibernateJpaAutoConfiguration {

    public HibernateValidationConfiguration(DataSource dataSource,JpaProperties jpaProperties,ObjectProvidervendorProperties(MapvendorProperties) {
        super.customizevendorProperties(vendorProperties);
        vendorProperties.put("javax.persistence.validation.factory",validator);
    }
}

第二种方式

创建一个实用程序bean

    @Service
public class BeanUtil implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        context = applicationContext;

    }

    public static 

然后在验证器初始化中:

@Override
 public void initialize(ValidUser constraintAnnotation) {
 userRepository = BeanUtil.getBean(UserRepository.class);
 em = BeanUtil.getBean(EntityManager.class);
 }

很重要

在这两种情况下,为了使其工作,您必须以这种方式“重置”实体管理器:

@Override
public boolean isValid(User value,ConstraintValidatorContext context) {
    try {
        em.setFlushMode(FlushModeType.COMMIT);
        //your code
    } finally {
        em.setFlushMode(FlushModeType.AUTO);
    }
}

无论如何,我不知道这是否真的是一种安全的方式. Probably it’s not a good practice access to the persistence layer at all.

最佳答案
如果您确实需要在Validator中使用注入,请尝试在其上添加@Configurable注释:

@Configurable(autowire = Autowire.BY_TYPE,dependencyCheck = true)
public class UserValidator implements ConstraintValidatorNow
    @Override
    public void initialize(ValidUser constraintAnnotation) {
    }

    @Override
    public boolean isValid(User value,ConstraintValidatorContext context) {
        try {
            User foundUser = userRepository.findByUsername( value.getUsername() );

            if ( foundUser != null && foundUser.getId() != value.getId() ) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate( "{ValidUser.unique.username}" ).addConstraintViolation();

                return false;
            }
        } catch (Exception e) {
            log.error( "",e );
            return false;
        }
        return true;
    }

}

从文档到该注释:

Marks a class as being eligible for Spring-driven configuration

所以这应该解决你的null问题.为了使它工作,你需要配置AspectJ …(检查如何在Spring中使用@Configurable)

原文地址:https://www.jb51.cc/spring/432140.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐