【问题标题】:How to intercept JSF view resolving in order to replace the outcome page?如何拦截 JSF 视图解析以替换结果页面?
【发布时间】:2016-10-10 12:39:42
【问题描述】:

某个托管 bean 有一个返回 "/private/myview.jsf" 的操作方法。但是,不更改此代码,我想执行一些检查并最终呈现视图"/private/other/myview.jsf"

因此,总而言之,我想将"/private/myview.jsf" 转换为"/private/other/myview.jsf" 某处方法返回之后之前 实际视图渲染。

如何实现?


环境:

  1. 日食月神
  2. Java 1.7
  3. JSF 2

现状

Web 应用程序可完全运行,但为支持无障碍功能而开发。

下一个版本的要求

成为一款足以让使用屏幕阅读器的盲人使用的应用程序。

详情

经过一些研究,我们得出的结论是,我们现在必须拥有每个页面的可访问版本。

我们会为每个页面设计这样的无障碍版本,问题是什么时候显示不可访问的版本,什么时候显示可访问的版本。

我们决定当用户点击页面顶部的某个链接时,应用程序将转为可访问模式(这将不是默认状态)。在可访问模式下,仅呈现页面的可访问版本。

我们不想审查所有的应用程序,我们想要的是截取 JSF 的某个阶段并替换应该呈现的结果。例如,考虑以下情况:

  1. 某个页面有指向另一个页面的链接或按钮,比如"mysettings.xhtml"
  2. 在可访问模式下,我们想告诉 JSF 不要渲染 "mysettings.xhtml",而应该渲染 "mysettings_ac.xhtml""accessible/mysettings.xhtml"
  3. 两个页面都将与完全相同的托管 bean 进行交互,并提供完全相同的功能,但其中一个页面对看得见的人有好处,而另一个页面的设计会让屏幕阅读器用户感到舒适。

提前致谢!

【问题讨论】:

  • 为什么你不能使用非残疾人的“新的可访问页面”?
  • @Kukeltje:因为页面对盲人用户有利,但对看得见的用户不利。
  • @BalusC:托管 bean 中现在返回 "myseetings.xhtml" 并且在可访问模式下应该返回 "mysettings_ac.xhtml" 的操作怎么样?我的问题不仅限于页面导航。在 JSF 应用程序中,通过运行域规则并导航到其他页面(例如保存记录并返回上一页)来响应事件是很常见的。
  • @AlexSC:如果我没记错这方面的所有“标准”,那么在使用 jsf 直通属性时,您应该(没有太多麻烦)能够使用 1 页。 PrimeFaces 已经内置了很多这样的功能。因此,如果您遇到失败或应该失败的特定问题,我很好奇。
  • @Kukeltje:在我们的某些页面中,我们的面板仅在用户单击某个按钮时才显示其内容。我们的用户更喜欢这样,因为只有在极少数情况下才需要此类面板的内容。对于有屏幕阅读器的盲人,我们将通过导航到不同的页面来处理此问题。

标签: jsf jsf-2 resources accessibility facelets


【解决方案1】:

因此,总而言之,我想将"/private/myview.jsf" 转换为"/private/other/myview.jsf" 的某处在方法返回之后 实际视图渲染之前。 em>

如果您已经使用 JSF 2.2,则可以通过提供自定义 ResourceHandeler 来实现此目的,其中您根据某些条件在 createViewResource() 中返回所需的视图资源。

public class YourResourceHandler extends ResourceHandlerWrapper {

    private ResourceHandler wrapped;

    public YourResourceHandler(ResourceHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ViewResource createViewResource(FacesContext context, final String name) {
        if (someCondition) {
            name = name.replace("/private/", "/private/other/");
        }

        return super.createViewResource(context, name);
    }

    @Override
    public ResourceHandler getWrapped() {
        return wrapped;
    }

}

faces-config.xml注册如下:

<application>
    <resource-handler>com.example.YourResourceHandler</resource-handler>
</application>

或者,如果您还没有使用 JSF 2.2,那么请改用 ResourceResolver

public class YourResourceResolver extends ResourceResolver {

    private ResourceResolver parent;

    public YourResourceResolver(ResourceResolver parent) {
        this.parent = parent;
    }

    @Override
    public URL resolveUrl(String path) {
        if (someCondition) {
            path = path.replace("/private/", "/private/other/");
        }

        return parent.resolveUrl(path);
    }

}

web.xml注册如下:

<context-param>
    <param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
    <param-value>com.example.YourResourceResolver</param-value>
</context-param>

【讨论】:

    【解决方案2】:

    如我所见,可能有两种解决方案。

    1. 使用redirect()方法

      returnAction(){ ExternalContext context = FacesContext.getCurrentInstance().getExternalContext(); context.redirect("/private/other/myview.jsf"); //Relative path might vary based upon your business logic }

    2. 动作返回后的条件重定向;我们可以在 faces-config.xml 中维护一个导航规则,如下所示:

        <navigation-rule>
            <navigation-case>
                <from-action>#{yourManagedBean.actionMethod}</from-action>
                <if>#{yourManagedBean.redirectAccessibleFlag}</if>   <!-- We maintain a boolean variable redirectAccessibleFlag in the managed Bean and set its value to true or false conditionally-->
                <to-view-id>/private/other/myview.jsf</to-view-id>
               <redirect/>
            </navigation-case>
        </navigation-rule>

    在第二种选择中,您可以在 ApplicationScope 中放置托管 bean,以便在多个 JSF 页面中使用。

    虽然这些解决方案来自一般概念,但它们可能不一定属于“方法返回之后和实际视图渲染之前的某个地方。”但是您可以检查它是否解决了目的。

    【讨论】:

      猜你喜欢
      • 2013-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-01
      • 2011-06-05
      相关资源
      最近更新 更多