7

我有一个用于本地化的属性文件:

foo=Bar
title=Widget Application

这与resource-bundlefaces-config 中的 a 相关联:

<resource-bundle>
    <base-name>com.example.messages.messages</base-name>
    <var>msgs</var>
</resource-bundle>

我可以使用 EL 在 facelets 视图中很好地访问它:

<title>#{msgs.title}</title>

但是,如果有 SQLExceptions 之类的东西,我需要能够从托管 bean 写入消息。这一切也都有效:

FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "There was an error saving this widget.", null);
FacesContext.getCurrentInstance().addMessage(null, message);

这是问题所在:我希望这些消息来自属性文件,以便它们也可以根据语言环境进行更改。有没有一种简单的方法可以使用注入访问属性文件?

4

5 回答 5

17

我问了一个非常相关的问题: How to injection a non-serializable class (like java.util.ResourceBundle) with Weld

在 Seam 论坛内部: http ://seamframework.org/Community/HowToCreateAnInjectableResourcebundleWithWeld

总结一下:我实现了一个具有 3 个生产者的可注入 ResourceBundle。首先你需要一个 FacesContextProducer。我从 Seam 3 Alpha 资源中获取了一个。

public class FacesContextProducer {
   @Produces @RequestScoped
   public FacesContext getFacesContext() {
      FacesContext ctx = FacesContext.getCurrentInstance();
      if (ctx == null)
         throw new ContextNotActiveException("FacesContext is not active");
      return ctx;
   }
}

然后你需要一个使用 FacesContextProducer 的 LocaleProducer。我还从 Seam 3 Alpha 中获取了它。

public class FacesLocaleResolver {
   @Inject
   FacesContext facesContext;

   public boolean isActive() {
      return (facesContext != null) && (facesContext.getCurrentPhaseId() != null);
   }

   @Produces @Faces
   public Locale getLocale() {
      if (facesContext.getViewRoot() != null) 
         return facesContext.getViewRoot().getLocale();
      else
         return facesContext.getApplication().getViewHandler().calculateLocale(facesContext);
   }
}

现在你已经拥有了创建 ResourceBundleProducer 的一切,它看起来像这样:

public class ResourceBundleProducer {
  @Inject       
  public Locale locale;

  @Inject       
  public FacesContext facesContext;

  @Produces
  public ResourceBundle getResourceBundle() {
   return ResourceBundle.getBundle("/messages", facesContext.getViewRoot().getLocale() );
  }
}

现在您可以将 ResourceBundle @Inject 注入到您的 bean 中。注意它必须被注入到一个临时属性中,否则你会得到一个异常,抱怨 ResourceBundle 不可序列化。

@Named
public class MyBean {
  @Inject
  private transient ResourceBundle bundle;

  public void testMethod() {
    bundle.getString("SPECIFIC_BUNDLE_KEY");
  }
}
于 2010-09-09T11:27:21.700 回答
2

它更易于使用,例如MyFaces CODI的消息模块!

于 2010-11-28T21:12:45.473 回答
2

您可以单独使用 JSF 完成此操作。

首先在您的支持 bean 上定义一个托管属性。在 JSF 配置中,您可以将托管属性的值设置为引用资源包的 EL 表达式。

我已经使用 Tomcat 6 完成了类似以下的操作。唯一需要注意的是,您无法从支持 bean 的构造函数访问此值,因为 JSF 尚未初始化它。@PostConstruct如果在 bean 生命周期的早期需要该值,则在初始化方法上使用。

<managed-bean>
  ...
  <managed-property>
    <property-name>messages</property-name>
    <property-class>java.util.ResourceBundle</property-class>
    <value>#{msgs}</value>
  </managed-property>
  ...
</managed-bean>

<application>
  ...
  <resource-bundle>
    <base-name>com.example.messages.messages</base-name>
    <var>msgs</var>
  </resource-bundle>
  ...
</application>

这样做的好处是使您的支持 bean 方法较少依赖于表示技术,因此应该更容易测试。它还将您的代码与包的名称等细节分离。

一些使用 Mojarra 2.0.4-b09 的测试在用户在会话中更改区域设置时确实显示出小的不一致。页内 EL 表达式使用新的语言环境,但没有为支持 bean 提供新的 ResourceBundle 引用。为了使其保持一致,您可以在 EL 表达式中使用 bean 属性值,例如使用#{backingBean.messages.greeting}. #{msgs.greeting}然后页面 EL 和支持 bean 将始终使用会话开始时处于活动状态的语言环境。如果用户必须在会话中切换语言环境并获取新消息,您可以尝试制作一个请求范围的 bean,并为其提供对会话 bean 和资源包的引用。

于 2011-11-10T23:19:23.977 回答
0

这是一个关于如何执行此操作的示例: http ://www.laliluna.de/articles/javaserver-faces-message-resource-bundle-tutorial.html

你想看看这个ResourceBundle.getBundle()部分。

问候,拉斯

于 2010-08-13T15:07:58.867 回答
0

这是一个老问题,但我正在添加另一种方法来做到这一点。我正在寻找其他东西并遇到了这个。这里的方法似乎都令人费解,因为我并不觉得那么困难。玩闪光,因为如果你问我它很漂亮。

给定一个文件:

/com/full/package/path/to/messages/errormessages.properties

文件内:

SOME_ERROR_STRING=Your App Just Cratered

我创建了一个“getBundle()”方法,因为我喜欢捕捉运行时并添加一条有意义的消息,这样我就可以了解它的来源。如果您出于某种原因一时兴起使用属性文件并且没有正确更新所有内容,这并不难,并且可以提供帮助。我有时将其设为私有,因为它有时是类中的辅助方法(对我而言)。这使 try catch 杂乱无章地远离有意义的代码。

如果您对组织有其他想法,则使用文件的完整路径可以将其放在默认位置/目录以外的位置。

public/private ResourceBundle getMessageResourceBundle(){
    String messageBundle = "com.full.package.path.to.messages.errormessages";
    ResourceBundle bundle = null;
    try{
        bundle = ResourceBundle.getBundle(messageBundle);
    }catch(MissingResourceException ex){
        Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
                    "Unable to find message bundle in XYZ Class", ex);
        throw ex;
    }

}

public void doSomethingWithBundle(){

    ResourceBundle bundle = getMessageResourceBundle();
    String someString = bundle.getString("SOME_ERROR_STRING");
    ...
}
于 2012-09-05T08:06:27.313 回答