Ras*_*nke 8 database jsf jpa resourcebundle internationalization
我正在使用JPA/EJB/JSF开发Java EE6项目,我在为实体设计多语言支持方面遇到了一些麻烦.有三个相关实体:
语言(具有id)
能力(具有id)
CompetenceName(具有能力参考,语言参考和字符串)
Competence对使用Map实现的CompetenceName有一对多的引用,每个语言都包含一个对象,其中存在一个Competence的名称.请注意,权限是动态创建的,因此它们的名称不能存在于资源包中.
在网页上列出Competences时,我希望它们以当前登录用户的语言显示,它存储在Session Scoped Managed Bean中.
有没有什么好方法可以在不破坏MVC设计的情况下实现这一目标?我的第一个想法是通过FacesContext直接从Competence实体中的"getName"方法获取会话范围bean,并在CompetenceNames的地图中查找如下:
public class Competence
{
...
@MapKey(name="language")
@OneToMany(mappedBy="competence", cascade=CascadeType.ALL, orphanRemoval=true)
private Map<Language, CompetenceName> competenceNames;
public String getName(String controller){
FacesContext context = FacesContext.getCurrentInstance();
ELResolver resolver = context.getApplication().getELResolver();
SessionController sc = (SessionController)resolver.getValue(context.getELContext(), null, "sessionController");
Language language = sc.getLoggedInUser().getLanguage();
if(competenceNames.get(language) != null)
return competenceNames.get(language).getName();
else
return "resource missing";
}
Run Code Online (Sandbox Code Playgroud)
这个解决方案感觉非常粗糙,因为实体依赖于Controller层,并且每次我想要它的名字时都必须获取会话控制器.更符合MVC的解决方案是采用Language参数,但这意味着来自JSF的每一次调用都必须包含从会话作用域托管bean中获取的语言,这也不是一个好的解决方案.
有没有人对此问题有任何想法或设计模式?
Bal*_*usC 18
国际化/本地化应该优选完全在视图方面完成.该模型不应该意识到这一点.
在JSF中,XHTML中的<resource-bundle>输入faces-config.xml和输入<f:loadBundle>也可以指向一个完整的ResourceBundle类而不是.properties文件的基本名称.在Java SE 6中,有一个新的ResourceBundle.ControlAPI可以完全控制加载和填充包.
了解这些事实后,应该可以使用自定义ResourceBundle和加载来自数据库的捆绑消息Control.这是一个启动示例:
public class CompetenceBundle extends ResourceBundle {
protected static final String BASE_NAME = "Competence.messages"; // Can be name of @NamedQuery
protected static final Control DB_CONTROL = new DBControl();
private Map<String, String> messages;
public CompetenceBundle() {
setParent(ResourceBundle.getBundle(BASE_NAME,
FacesContext.getCurrentInstance().getViewRoot().getLocale(), DB_CONTROL));
}
protected CompetenceBundle(Map<String, String> messages) {
this.messages = messages;
}
@Override
protected Object handleGetObject(String key) {
return messages != null ? messages.get(key) : parent.getObject(key);
}
@Override
public Enumeration<String> getKeys() {
return messages != null ? Collections.enumeration(messages.keySet()) : parent.getKeys();
}
protected static class DBControl extends Control {
@Override
public ResourceBundle newBundle
(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException
{
String language = locale.getLanguage();
Map<String, String> messages = getItSomehow(baseName, language); // Do your JPA thing. The baseName can be used as @NamedQuery name.
return new CompetenceBundle(messages);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这样你就可以在下面声明如下faces-config.xml:
<resource-bundle>
<base-name>com.example.i18n.CompetenceBundle</base-name>
<var>competenceBundle</var>
</resource-bundle>
Run Code Online (Sandbox Code Playgroud)
或者在Facelet中如下:
<f:loadBundle basename="com.example.i18n.CompetenceBundle" var="competenceBundle" />
Run Code Online (Sandbox Code Playgroud)
无论哪种方式,您都可以通常的方式使用它:
<h:outputText value="#{competenceBundle.name}" />
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5922 次 |
| 最近记录: |