gpt4 book ai didi

database - 使用从数据库加载的 ResourceBundle 条目在 JSF 中进行国际化

转载 作者:太空狗 更新时间:2023-10-30 01:45:24 24 4
gpt4 key购买 nike

我正在使用 JPA/EJB/JSF 开发一个 Java EE6 项目,但在为实体设计多语言支持时遇到了一些问题。存在三个相关实体:

语言(有id)
权限(有id)
能力名称(具有能力引用、语言引用和字符串)

Competence 有一个对 CompetenceName 的一对多引用,使用 Map 实现,包含一个对象对应存在 Competence 名称的每种语言。请注意,权限是动态创建的,因此它们的名称不能存在于资源包中。

在网页上列出能力时,我希望它们以当前登录用户的语言显示,这存储在 session 范围的托管 Bean 中。

有没有什么好的方法可以在不破坏良好的 MVC 设计的情况下实现这一点?我的第一个想法是通过 FacesContext 直接从 Competence 实体中的“getName”方法获取 session 范围的 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";
}

这个解决方案感觉非常粗糙,因为实体依赖于 Controller 层,并且每次我需要它的名字时都必须获取一个 session Controller 。一个更符合 MVC 的解决方案是采用语言参数,但这意味着来自 JSF 的每个调用都必须包括从 session 范围的托管 bean 中获取的语言,这也不是一个好的解决方案。

有没有人对这个问题有什么想法或设计模式?

最佳答案

国际化/本地化最好完全在 View 端完成。模型不应该意识到这一点。

在 JSF 中,<resource-bundle>输入 faces-config.xml<f:loadBundle>在 XHTML 中也可以指向一个完整的 ResourceBundle类而不是 .properties 的基名文件。在 Java SE 6 中有一个新的 ResourceBundle.Control 可用的 API 允许完全控制加载和填充包。

了解这些事实后,应该可以使用自定义 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);
}

}

}

这样就可以在faces-config.xml中声明如下:

<resource-bundle>
<base-name>com.example.i18n.CompetenceBundle</base-name>
<var>competenceBundle</var>
</resource-bundle>

或者在Facelet中如下:

<f:loadBundle basename="com.example.i18n.CompetenceBundle" var="competenceBundle" />

无论哪种方式,您都可以按常规方式使用它:

<h:outputText value="#{competenceBundle.name}" />

关于database - 使用从数据库加载的 ResourceBundle 条目在 JSF 中进行国际化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4499732/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com