我有一个用于本地化的属性文件:
foo=Bar
title=Widget Application
这与faces-config中的resource-bundle
相关联:
<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);
问题在于:我希望这些消息来自属性文件,以便它们也可以根据区域设置进行更改。有没有一种简单的方法可以使用注入来访问属性文件?
答案 0 :(得分:16)
我在SO上提出了一个非常相关的问题: How to inject 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;
}
}
然后你需要一个LocaleProducer,它使用FacesContextProducer。我也从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() );
}
}
现在你可以@Inject ResourceBundle到你的bean。注意必须将它注入瞬态属性,否则你会得到一个例外,抱怨ResourceBundle不可序列化。
@Named
public class MyBean {
@Inject
private transient ResourceBundle bundle;
public void testMethod() {
bundle.getString("SPECIFIC_BUNDLE_KEY");
}
}
答案 1 :(得分:2)
更容易使用,例如MyFaces CODI的消息模块!
答案 2 :(得分:2)
您可以单独使用JSF执行此操作。
首先在您的辅助bean上定义托管属性。在JSF配置中,您可以将托管属性的值设置为引用资源包的EL表达式。
我使用Tomcat 6完成了类似下面的操作。唯一需要注意的是,您无法从支持bean的构造函数中访问此值,因为JSF尚未初始化它。如果在bean的生命周期的早期需要值,则在初始化方法上使用@PostConstruct
。
<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和资源包的引用。
答案 3 :(得分:0)
以下是如何执行此操作的示例: http://www.laliluna.de/articles/javaserver-faces-message-resource-bundle-tutorial.html
您想查看ResourceBundle.getBundle()
部分。
问候, 拉斯
答案 4 :(得分: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");
...
}