【问题标题】:ResourceBundle not found for MessageSource when placed inside a folder放置在文件夹中时找不到 MessageSource 的 ResourceBundle
【发布时间】:2012-06-22 05:58:53
【问题描述】:

我正在尝试将资源包与 Spring 的消息源一起使用。这是我的做法:

@Component
public class MessageResolver implements MessageSourceAware {

    @Autowired
    private MessageSource messageSource;

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    public String getMessage(){
        return messageSource.getMessage("user.welcome", new Object[]{"Rama"} , Locale.US);
    }

}

这是我的文件夹结构:

messages_en_US.properties 只包含一行:

user.welcome=Welcome {0}

这里是使用的xml配置:

<bean name="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basename">
        <value>resourcebundles/messages</value>
    </property>
</bean>

这是我得到的错误:

WARNING: ResourceBundle [resourcebundles/messages] not found for MessageSource: Can't find bundle for base name resourcebundles/messages, locale en_US
Exception in thread "main" org.springframework.context.NoSuchMessageException: No message found under code 'user.welcome' for locale 'en_US'.

但是,如果我将资源包直接移动到资源文件夹下,它就可以正常工作。在这种情况下,这是我正在使用的 xml 配置:

<bean name="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
    <value>messages</value>
</property>

如果我必须使用 ResourceBundleMessageSource,我应该将我的资源包直接放在资源下吗?如果我只能将它保存在指定的文件夹中,还有其他方法可以让这个工作吗?

谢谢!

【问题讨论】:

  • 你能在这里展示你为resourceBundle完成的xml配置吗?
  • @Japs,已编辑问题并添加了使用的 xml。请仔细查看。
  • @AhamedMustafaM,如帖子中所述,我正在为资源包文件使用正确的命名。问题不是因为文件名,而是因为我将它保存在子文件夹中。

标签: spring spring-mvc resources resourcebundle


【解决方案1】:

男孩,也许你可以改变xml配置如下:

使用

org.springframework.context.support.ReloadableResourceBundleMessageSource

而不是

org.springframework.context.support.ResourceBundleMessageSource

所有配置如下:

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:resourcebundles/messages" />
    <property name="useCodeAsDefaultMessage" value="true" />
</bean>

【讨论】:

  • +1。我有类似于 OP 的问题,这对我有帮助。就我而言,使用classpath:.. 不带星号 很重要(就像这里一样)。星号用于破坏加载程序,消息未解析。当消息属性不在最终应用程序中时(因此需要classpath*:),我没有对此进行测试,因为这不是我的情况。
【解决方案2】:

将 xml 文件中 messageSource bean 的配置更改为以下内容。

<bean name="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> 
    <property name="basename"> 
        <value>classpath*:resourcebundles/messages</value> 
    </property> 
</bean>

由于所有属性文件都在 java 的类路径中,因此您需要使用前缀 classpath*: 定义路径,否则它将查看您应用程序的 web 目录。

希望这对您有所帮助。干杯。

【讨论】:

  • 即使现在它也给出了同样的例外。实际上它是直接抛出错误,甚至没有抛出找不到指定资源包的警告。
  • 这是抛出的异常:线程“main”中的异常 org.springframework.context.NoSuchMessageException:在语言环境“en_US”的代码“user.welcome”下找不到消息。
【解决方案3】:

现在快 2015 年了,我使用的是 Spring 4.1.2.RELEASE,而且 messageSource bean 的配置方式肯定存在问题,因此它需要获取目标资源包。

1) 如果 messageSource bean 的类型是 ReloadableResourceBundleMessageSource 它将不起作用:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

@Configuration
@ComponentScan(basePackages = { "com.intertech.service" })
//@ImportResource({"classpath:spring/applicationContext-i18n.xml"})
public class AppConfig {

  @Bean(name = "messageSource")
  public ReloadableResourceBundleMessageSource getMessageSource() {
      ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
      messageSource.setBasename("config/messages");
      messageSource.setDefaultEncoding("UTF-8");
      messageSource.setUseCodeAsDefaultMessage(true);
      return messageSource;
  }

//  @Bean(name = "messageSource")
//  public ResourceBundleMessageSource getMessageSource() {
//      ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
//      messageSource.setBasename("config/messages");
//      messageSource.setDefaultEncoding("UTF-8");
//      messageSource.setUseCodeAsDefaultMessage(true);
//      return messageSource;
//  }
}

2) 如果 messageSource bean 是 ResourceBundleMessageSource 类型,它将起作用:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;

@Configuration
@ComponentScan(basePackages = { "com.intertech.service" })
//@ImportResource({"classpath:spring/applicationContext-i18n.xml"})
public class AppConfig {

//  @Bean(name = "messageSource")
//  public ReloadableResourceBundleMessageSource getMessageSource() {
//      ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
//      messageSource.setBasename("config/messages");
//      messageSource.setDefaultEncoding("UTF-8");
//      messageSource.setUseCodeAsDefaultMessage(true);
//      return messageSource;
//  }

  @Bean(name = "messageSource")
  public ResourceBundleMessageSource getMessageSource() {
      ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
      messageSource.setBasename("config/messages");
      messageSource.setDefaultEncoding("UTF-8");
      messageSource.setUseCodeAsDefaultMessage(true);
      return messageSource;
  }
}

3) 如果您使用结合了配置类的 XML 配置文件 - 它会起作用(注意基本包是如何以类限定方式配置的,即“config.messages”而不是“config/messages”) : (applicationContext-i18n.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource"
        p:basename="config.messages"
        p:useCodeAsDefaultMessage="true"/>

    <!-- This will not work -->
    <!--
    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
        p:basename="config/messages"
        p:useCodeAsDefaultMessage="true"/>
     -->
</beans>

和:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ComponentScan(basePackages = { "com.intertech.service" })
@ImportResource({"classpath:spring/applicationContext-i18n.xml"})
public class AppConfig {

//  @Bean(name = "messageSource")
//  public ReloadableResourceBundleMessageSource getMessageSource() {
//      ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
//      messageSource.setBasename("config/messages");
//      messageSource.setDefaultEncoding("UTF-8");
//      messageSource.setUseCodeAsDefaultMessage(true);
//      return messageSource;
//  }

//  @Bean(name = "messageSource")
//  public ResourceBundleMessageSource getMessageSource() {
//      ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
//      messageSource.setBasename("config/messages");
//      messageSource.setDefaultEncoding("UTF-8");
//      messageSource.setUseCodeAsDefaultMessage(true);
//      return messageSource;
//  }
}

4) 最重要的是...如果您使用的是 WebApplicationInitializer(没有 web.xml),您必须在根目录中注册定义“messageSource”bean 的配置类上下文,不在调度程序 servlet 的上下文中:

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class WebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) throws ServletException {
    // Create the 'root' Spring application context
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(AppConfig.class);
    // Manage the lifecycle of the root application context
    container.addListener(new ContextLoaderListener(rootContext));
    // Create the dispatcher servlet's Spring application context
    AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
    dispatcherServlet.register(MvcConfig.class);
    // Register and map the dispatcher servlet
    ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(
            dispatcherServlet));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("*.htm");
    }
}

【讨论】:

  • 这些解决方案都不再适用于春季 4.2.3 版本。您能否更新有关如何使用最新的 srping 版本对其进行配置的答案?谢谢
  • 为我工作
【解决方案4】:

就我而言,使用 Spring 4.3.2.RELEASEjava config 以及 ReloadableResourceBundleMessageSource,我必须将我的模板引擎定义为一个 bean,否则我的消息没有得到解决。

这是一个工作配置示例。

AppConfig.java

import java.util.concurrent.TimeUnit;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;

@Configuration
@EnableWebMvc
@ComponentScan("myapp")
public class AppConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware {

private ApplicationContext applicationContext;

private static final boolean CACHE_THYMELEAF_TEMPLATES = false;
private final String UTF8_ENCODING = "UTF-8";

@Override
public void setApplicationContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
}

@Bean
public ViewResolver viewResolver() {
    ThymeleafViewResolver resolver = new ThymeleafViewResolver();
    resolver.setTemplateEngine(templateEngine());
    resolver.setCharacterEncoding(UTF8_ENCODING);
    resolver.setCache(CACHE_THYMELEAF_TEMPLATES);
    return resolver;
}

@Bean
public TemplateEngine templateEngine() {
    //this method must be defined as a bean otherwise i18n messages are not found
    //if method defined as private TemplateEngine templateEngine() messages are not found
    SpringTemplateEngine engine = new SpringTemplateEngine();
    engine.setEnableSpringELCompiler(true);
    engine.addTemplateResolver(templateResolver());
    return engine;
}

private ITemplateResolver templateResolver() {
    SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
    resolver.setApplicationContext(applicationContext);
    resolver.setPrefix("/WEB-INF/thymeleaf/");
    resolver.setTemplateMode(TemplateMode.HTML);
    resolver.setSuffix(".html");
    resolver.setCacheable(CACHE_THYMELEAF_TEMPLATES);
    resolver.setCharacterEncoding(UTF8_ENCODING);
    return resolver;
}   

@Bean
public MessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames("WEB-INF/i18n/messages");
    messageSource.setUseCodeAsDefaultMessage(true);
    messageSource.setDefaultEncoding(UTF8_ENCODING);
    messageSource.setFallbackToSystemLocale(false);
    messageSource.setCacheSeconds((int)TimeUnit.HOURS.toSeconds(1));
    return messageSource;
}

}

【讨论】:

  • 它对我有用,谢谢 :) 只需将 @Bean 注释放在 templateEngine 方法上。
【解决方案5】:
 <!-- Application Message Bundle -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="resourcebundles/messages" />
</bean>

您必须如上所示配置您的消息路径。 另外,检查类名。

【讨论】:

  • 这正是我正在使用的配置。但它不起作用。在问题中,你可以看到我正在使用的xml。
  • 你把类改成 ReloadableResourceBundleMessageSource 了吗?
  • 将您的属性文件名更改为messages_en.properties。
  • 现在它在将文件名更改为messages_en.properties后可以工作但是如果我将我的文件命名为messages_en_US并将语言环境作为Locale.US传递,我不明白为什么它不起作用?
【解决方案6】:

是,如果我必须使用 ResourceBundleMessageSource,我应该把 我的资源包直接在资源下?如果我必须保留它 仅在指定文件夹中,有没有其他方法可以让这个工作?

您可以在自己的包中定义您的消息,它不需要位于资源文件夹中。

使用 Spring 5.2.2.RELEASE 版本的组件,这是我设法使其工作的方式:

文件的限定名称是:

/tutproject/src/com/tutproject/app/messages/messages.properties

bean 在我的 Spring Bean 配置文件 (XML) 中是这样定义的:

<bean id="messageSource"
    class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename"
    value="/com/tutproject/app/messages/messages">
</property>
</bean>

Java 构建路径包括 tutproject/src ,这是 XML 定义中省略的位置部分。

来自 ResourceBundleMessageSource 类的一些额外有用信息:

  • 基本名称遵循 {@link java.util.ResourceBundle} 约定:本质上,* 一个完全限定的类路径位置。如果 它不包含包限定符 *(例如 {@code org.mypackage}),它将从类路径根目录中解析。 * 笔记 JDK 的标准 ResourceBundle 将点视为包 分隔符:* 这意味着“test.theme”实际上是等效的 到“测试/主题”

【讨论】:

    【解决方案7】:

    我使用了以下配置,它工作正常

    <beans:bean id="messageSource class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
            <beans:property name="basename" value="classpath:resourcebundles/ScreenLabelResources" />
        </beans:bean>
    

    【讨论】:

      【解决方案8】:

      对我有用的东西非常简单。

      原来是

      <property name="basename">
                  <value>locale\messages</value>
              </property>
      

      我改成

      <property name="basename">
                  <value>locale/messages</value>
              </property>
      

      只是一个 \ 到 / 更改为我修复了它。我使用的是 MAC。

      我没有尝试过*classpath,这可能对我不起作用。

      【讨论】:

        【解决方案9】:

        我使用了以下配置,它在我的项目中运行良好。 我的 messages.properties 位于以下路径: ..\WebContent\WEB-INF\资源

        <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
            <property name="basename" value="classpath:WEB-INF/resources/messages" />
            <property name="useCodeAsDefaultMessage" value="true" />
        </bean>
        

        【讨论】:

          【解决方案10】:

          我使用了以下配置,它在我的项目中运行良好。

          <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
              <property name="basename" value="classpath:configurations/messages" />
              <property name="useCodeAsDefaultMessage" value="true" />
          </bean>
          

          位置:src\main\resources\configurations\messages_en.properties

          【讨论】:

            【解决方案11】:

            YAML 版本

              spring:
                 messages:
                   basename: i18n/validation, i18n/message # for multiple properties just use comma separated values
                   encoding: UTF-8
            

            您可以参考documentation查看完整说明。

            另外我应该提到,默认的 MessageSource bean 是一个 ResourceBundleMessageSource,它已经从类路径中读取,因此不需要使用像 classpath:i18n/validation 这样的非命名。

            目录结构

            【讨论】:

              【解决方案12】:

              在 Spring Boot 2.2.5 中,情况略有变化。不再需要类路径。

                  @Bean
              public MessageSource messageSource() {
                  ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
                  messageSource.setBasename("messages");
                  messageSource.setDefaultEncoding("UTF-8");
                  return messageSource;
              }
              

              【讨论】:

                【解决方案13】:

                我强烈建议将属性文件保留在项目之外,这样我们就不需要为每个属性更改编译代码。

                我们在实时项目中使用的以下配置。在 application.properties 文件中设置 property.location 的值

                @Configuration
                public class LocalizationConfiguration {
                
                    private static final Logger logger = LoggerFactory.getLogger(LocalizationConfiguration.class);
                
                    @Value("${property.location}")
                    private String propertyLocation;
                
                    @Bean
                    public LocaleResolver localeResolver() {
                        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
                        localeResolver.setDefaultLocale(Locale.ENGLISH); // change this
                        return localeResolver;
                    }
                
                    @Bean
                    public ReloadableResourceBundleMessageSource messageSource() {
                        ReloadableResourceBundleMessageSource  resource = new ReloadableResourceBundleMessageSource();
                        String messageFolderPath = propertyLocation + "/" + "i18n";
                        resource.setBasename("file:"+messageFolderPath+"/messages");
                        resource.setDefaultEncoding("UTF-8");
                        resource.setCacheSeconds(10);
                        return resource;
                    }
                
                    @Bean
                    public LocalValidatorFactoryBean validatorFactoryBean() {
                        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
                        bean.setValidationMessageSource(messageSource());
                        return bean;
                    }
                
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-02-25
                  • 2012-07-24
                  • 2015-07-15
                  • 2010-09-15
                  • 1970-01-01
                  • 2020-02-29
                  • 2015-02-09
                  • 1970-01-01
                  相关资源
                  最近更新 更多