ValidationMessages.properties 文件之间的冲突

Alf*_*Alf 5 java resourcebundle bean-validation

我习惯将所有验证约束收集在一个公共库中。在 jar 的根目录中,我放置了一个ValidationMessages_it.properties文件。\n一切正常,如果我将此库放入 jsf 2 war 项目中,所有验证消息都会正确显示。\n但是,如果我也将另一个库放入ValidationMessages_it.propertieswar 工件中,则会出现问题。在这种情况下{library.message_key},会显示一个字符串。

\n

我认为 Bean Validation 在战争中找到了正确的属性文件,并且没有考虑到库中的属性文件。\n我该如何解决?

\n

例子

\n

我有一个库 commons.jar,其中包含自定义约束。为了设置这些约束的消息,我ValidationMessages_it.properties在这个库的根目录中添加了

\n
commons.jar\n    |\n    + library\n    |   |\n    |   + CustomConstraint.class\n    |\n    + ValidationMessages_it.properties\n
Run Code Online (Sandbox Code Playgroud)\n

ValidationMessages_it.properties

\n
library.custom=Questo \xc3\xa8 l\'errore di cui parlavo\n
Run Code Online (Sandbox Code Playgroud)\n

自定义约束.java

\n
@Pattern( regexp = "[a-z]", message = "{library.custom}" )\n@Constraint( validatedBy = {} )\n@Documented\n@Target( { ElementType.METHOD, ElementType.FIELD } )\n@Retention( RetentionPolicy.RUNTIME )\npublic @interface CustomConstraint {\n    String message() default "C\'\xc3\xa8 un errore";\n\n    Class<?>[] groups() default {};\n\n    Class<? extends Payload>[] payload() default {};\n}\n
Run Code Online (Sandbox Code Playgroud)\n

PS: 请注意,消息键位于 @Pattern 注释上,而不是 message() 上,这可能看起来是一个错误,但否则它永远不会起作用!

\n

之后我想commons.jar在我的网络应用程序项目(jsf/mojarra 2.1)中使用它。一切正常。显示的错误消息为“Questo \xc3\xa8 l\'errore di cui parlavo”。

\n

但现在假设我在 web 应用程序中定义了新的验证约束,因此我想通过添加ValidationMessages_it.propertiesinWEB-INF/classes文件夹来为这些约束提供翻译。在这种情况下,显示的错误消息是“{library.custom}”

\n

所以我认为 BV(或 jsf?)在战争中找到了捆绑包,并且没有考虑到 commons.jar 中的捆绑包。library.custom它在文件夹中ValidationMessages_it.properties找不到密钥,WEB-INF/classes因此{library.custom}按字面意思返回。

\n

实施例2

\n

基于共享库中的 Bean Validation 约束,我的包结构似乎是正确的。我上传了一个简单的网络应用程序来显示问题:

\n\n

我在 Glassfish 3.1.2、JBoss AS 7.1.1、Geronimo 3.0.0 中测试了 web 应用程序

\n

Glassfish 和 JBoss 具有相同的行为。在 Geronimo 中,它的效果要好一些。

\n

M. *_*tin 5

默认情况下,如果有多个 JAR/WAR/等。文件包含一个同名的资源包文件,只有其中一个将用于验证器消息。这就是这里的问题:commons.jar应用程序 WAR 都包含一个名为 name 的资源ValidationMessages_it.properties

Hibernate Validator 5.2 于 2015 年 7 月发布,增加了对聚合来自不同 JAR 文件的所有同名资源包的支持。该功能默认是禁用的,可以在org.hibernate.validator.resourceloading.PlatformResourceBundleLocator中配置。

例子:

PlatformResourceBundleLocator resourceBundleLocator =
        new PlatformResourceBundleLocator(
                ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES, 
                null, true);

Validator validator = Validation.byProvider(HibernateValidator)
    .configure()
    .messageInterpolator(
            new ResourceBundleMessageInterpolator(resourceBundleLocator))
    .buildValidatorFactory()
    .getValidator();
Run Code Online (Sandbox Code Playgroud)

使用 Java 配置的 Spring 项目的等效代码:

@Bean
public LocalValidatorFactoryBean validator() {
    PlatformResourceBundleLocator resourceBundleLocator =
            new PlatformResourceBundleLocator(
                    ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES, 
                    null, true);

    LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
    factoryBean.setMessageInterpolator(
            new ResourceBundleMessageInterpolator(resourceBundleLocator));
    return factoryBean;
}
Run Code Online (Sandbox Code Playgroud)

对于使用 Web MVC 的 Spring Boot 3.x 项目,以下配置了 Spring 使用的默认验证器,以及 Web MVC 用于验证控制器参数等的验证器:

import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class ValidationConfig {
    /**
     * Matches the bean name from {@code ValidationAutoConfiguration.defaultValidator}.
     */
    @Bean
    public LocalValidatorFactoryBean defaultValidator() {
        PlatformResourceBundleLocator resourceBundleLocator =
                new PlatformResourceBundleLocator(
                        ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES, 
                        null, true);

        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        factoryBean.setMessageInterpolator(
                new ResourceBundleMessageInterpolator(resourceBundleLocator));
        return factoryBean;
    }

    @Bean
    public WebMvcConfigurer validatorConfigurer(Validator defaultValidator) {
        return new WebMvcConfigurer() {
            @Override
            public Validator getValidator() {
                return defaultValidator;
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)


Har*_*rdy 3

我认为您的情况的解决方案是提到的AggregateResourceBundleLocator。但是,属性文件不能具有相同的名称。在内部调用ResourceBundle#getBundle并返回单个ResourceBundle。不存在组合/合并同名属性文件的概念。

编辑1

关于这样做的标准方法 - 不幸的是没有。Bean Validation 1.1 ( BVAL-252 )有一个悬而未决的问题,以解决提供约束库的能力,但尚未做出任何决定,并且消息插值也需要解决。也许您知道它应该如何工作。如果是这样,请向专家组提出您的建议。检查 beanvalidation.org