【问题标题】:Spring Boot, Hibernate validator language based on LocaleContextHolderSpring Boot,基于 LocaleContextHolder 的 Hibernate 验证器语言
【发布时间】:2021-04-05 10:02:36
【问题描述】:

我有一个使用 JPA、Hibernate 等的 Spring Boot 2.4.2 REST 应用程序。 到目前为止,我使用 MessageSource 处理应用程序错误(位于 i18n/messages 中),使用默认 ValidationMessages 进行 bean 验证。

这是我的配置的一部分:

 public static Set<Locale> LOCALES = Set.of(new Locale("en"), new Locale("it"));


@Bean
    public LocaleResolver localeResolver() {
        SmartLocaleResolver localeResolver = new SmartLocaleResolver();
        return localeResolver;
    }

    public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            if (StringUtils.isBlank(request.getHeader("Accept-Language"))) {
                return Locale.getDefault();
            }
            List<Locale.LanguageRange> list = Locale.LanguageRange.parse(request.getHeader("Accept-Language"));
            Locale locale = Locale.lookup(list, LOCALES);
            return locale;
        }
    }

    @Primary
    @Bean("messageSource")
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setAlwaysUseMessageFormat(true);
        messageSource.setBasenames("classpath:/i18n/messages");
        // set to true only for debugging
        messageSource.setUseCodeAsDefaultMessage(false);
        messageSource.setFallbackToSystemLocale(false);
        return messageSource;
    }

到目前为止,我的应用程序支持 2 种语言:iten。 现在的问题是应用程序的消息在代理的语言(浏览器)中正​​确本地化,但验证错误不是。

我发现 Hibernate 使用默认语言环境 (Locale.getDefault()) 并自定义行为我应该自定义语言环境分辨率。

所以我尝试创建一个自定义 hibernateValidator(我在我的 entityFactory 中设置):

  @Bean
public MessageSource validationMessageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setAlwaysUseMessageFormat(true);
    messageSource.setBasenames("classpath:/ValidationMessages");
    // set to true only for debugging
    messageSource.setUseCodeAsDefaultMessage(false);
    messageSource.setFallbackToSystemLocale(false);
    return messageSource;
}

 @Bean("hibernateValidator")
    public LocalValidatorFactoryBean hibernateValidator() {
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        factoryBean.setValidationMessageSource(validationMessageSource());           
        return factoryBean;
    }

和解析器:

public class HibernateLocaleResolver implements LocaleResolver {

    @Override
    public Locale resolve(LocaleResolverContext context) {
        return LocaleContextHolder.getLocale();
    }
}

这样做,语言环境解析工作正常,但参数替换不能。我的意思是这样的消息:

server.validators.ArraySize.message = The number of values must be between [{min}] and [{max}].

我有一个例外:

"exception": "java.lang.IllegalArgumentException", "message": "can't parse argument number: min"

所以我更改了上面的配置,添加了 MessageInterpolator:

factoryBean.setMessageInterpolator(new ResourceBundleMessageInterpolator(LOCALES, Locale.ENGLISH, new HibernateLocaleResolver(), false));

此时参数已正确解析,但语言环境解析再次不起作用。

您能否指出正确的方向,尝试解释 Spring Boot - Hibernate Validator 组合的最佳实践?

【问题讨论】:

    标签: spring spring-boot hibernate nhibernate-validator


    【解决方案1】:

    我解决了这个问题。我希望这可以帮助别人。这是我的配置文件:

    @Primary
    @Bean("messageSource")
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setAlwaysUseMessageFormat(true);
        messageSource.setBasenames("classpath:/i18n/messages");
        // set to true only for debugging
        messageSource.setUseCodeAsDefaultMessage(false);
        messageSource.setFallbackToSystemLocale(false);
        return messageSource;
    }
    
    @Bean
    public MessageSource validationMessageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setAlwaysUseMessageFormat(true);
        messageSource.setBasenames("classpath:/ValidationMessages");
        // set to true only for debugging
        messageSource.setUseCodeAsDefaultMessage(false);
        messageSource.setFallbackToSystemLocale(false);
        return messageSource;
    }
    
    @Bean
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        factoryBean.setValidationMessageSource(validationMessageSource());
        MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
        factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
        return factoryBean;
    }
    

    和 LocaleConfiguration:

    @Configuration
    public class LocaleConfiguration implements WebMvcConfigurer {
    
        @Bean
        public LocaleResolver localeResolver() {
            SmartLocaleResolver localeResolver = new SmartLocaleResolver();
            return localeResolver;
        }
    
        public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
            @Override
            public Locale resolveLocale(HttpServletRequest request) {
                if (StringUtils.isBlank(request.getHeader("Accept-Language"))) {
                    return Locale.getDefault();
                }
                List<Locale.LanguageRange> list = Locale.LanguageRange.parse(request.getHeader("Accept-Language"));
                Locale locale = Locale.lookup(list, Constants.LOCALES);
                return locale;
            }
        }
    }
    

    我看到的重要部分是以下几行:

    MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
    factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
    

    通过这种方式,插值器可以正常工作以及消息的本地化。

    【讨论】:

      猜你喜欢
      • 2017-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-15
      • 1970-01-01
      • 2017-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多