【问题标题】:Implementing a Locale provider that works in JSF and JAX-RS实现在 JSF 和 JAX-RS 中工作的语言环境提供程序
【发布时间】:2013-09-03 14:14:17
【问题描述】:

我一直很高兴地使用omnifaces 的Faces.getLocale() 来获取当前登录用户使用的语言环境(这反过来又从<f:view> 定义中获取)。我真的很喜欢从视图到客户端再到系统默认区域设置的后备方法,因为它符合我的应用程序中区域设置选择的要求:

  1. 如果用户已登录,请使用他的语言偏好(从后端实体获得)
  2. 如果找不到用户偏好,请使用Accept-Languages HTTP 标头中排名最高的语言
  3. 如果此时尚未选择区域设置,请使用系统默认设置。

现在我已经开始使用 JAX-RS(resteasy 实现),并且发现很难编写一个服务来为我的后端代码提供当前用户的语言环境。

我不能使用 Faces.getLocale(),因为这需要 FacesContext,而在 JAX-RS 请求处理期间不存在。

我不能在 @Provider(这将给我用户首选的语言环境)或 @Context HttpHeaders(访问客户端语言环境)中使用 @Context SecurityContext 注释,因为 JAX-RS 仅在使用提供者本身,而不是在我的后端代码实例化类时。

而且我不想在我的方法签名中乱扔Locale 参数,因为几乎一切都需要存在语言环境。

举一个具体的例子:我有一个 vcard 生成器,它根据用户的首选语言环境生成很少的 NOTE 字段。我都可以通过 JSF/EL 调用 vcard 生成方法:

<h:commandLink action="#{vcfGenerator.forPerson(person)}" 
    value="Go" target="_blank" />

通过 REST 服务:

@GET @Path('person/{id:[1-9][0-9]*}/vcard')
@Produces('text/vcard')
String exportVcard(@PathParam('id') Long personId, @Context HttpHeaders headers) {
    VcfGenerator exporter = Component.getInstance(VcfGenerator) as VcfGenerator

    Person person = entityManager.find(Person, personId)
    if (! person)
        return Response.noContent().build()

    def locale = headers.acceptableLanguages[0] ?: Locale.ROOT
    return exporter.generateVCF(person, locale).toString()
}

这可行(VcfGenerator 有一组使用 Faces.getLocale() 的仅限 JSF 的方法),但维护起来很痛苦。因此,与其传递Locale 对象,不如说:

Vcard generateVCF(Person person) {
    Locale activeLocale = LocaleProvider.instance().getContext(VcfGenerator.class)
    ResourceBundle bundle = ResourceBundle.getBundle("messages", activeLocale, new MyControl())
    // use bundle to construct the vcard
}

有没有人做过类似的工作并且可以分享见解?

【问题讨论】:

  • 那么,流程基本上是 JSF 视图 JSF backing bean JAX-RS 服务 业务服务?为什么要添加额外的 JAX-RS 层? JSF 支持 bean 不能直接调用该业务服务吗?否则,您必须自己设置请求标头或在 JAX-RS Web 服务请求上添加请求参数。即物理上完全不同的 HTTP 请求。
  • @BalusC 不,JSF 支持 bean 正在与业务服务对话,而 JAX-RS 服务正在调用支持 bean 代码,两者都是独立的。我正在寻找一种方法让业务服务说 LocaleProvider.instance().getContext(this.getClass())LocaleProvider 根据可用信息确定应该从哪里获取语言环境。

标签: jsf localization jax-rs resteasy omnifaces


【解决方案1】:

我知道这已经发布了一段时间,但由于它尚未被标记为已解决,因此我是如何为这种特定情况找到解决方法的:

  • 首先我得到了一个自定义 ResourceBundle 工作,正如@BalusC 所述:http://balusc.blogspot.fr/2010/10/internationalization-in-jsf-with-utf-8.html
  • 然后我更新了构造函数以检测 FacesContext 当前是否正在使用中,来自:

    public Text() {
        setParent(ResourceBundle.getBundle(BUNDLE_NAME, 
        FacesContext.getCurrentInstance().getViewRoot().getLocale(), UTF8_CONTROL));
    }
    
  • 到这里:

    public Text() {
        FacesContext ctx = FacesContext.getCurrentInstance();
        setParent(ResourceBundle.getBundle(BUNDLE_NAME, 
        ctx != null ? ctx.getViewRoot().getLocale() : Locale.ENGLISH, UTF8_CONTROL));
    }
    

这现在可以在 JSF 和 JAX-RS 上下文中使用。

希望对您有所帮助,

【讨论】:

  • Jup,这是直观的解决方案,但没有满足 JAX-RS 下的要求 1 和 2?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-18
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 2016-01-30
  • 1970-01-01
相关资源
最近更新 更多