如何拦截JSF视图解析以替换结果页面



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

因此,总的来说,我想在方法返回后的实际视图渲染前的<strong]处将"/private/myview.jsf"转换为"/private/other/myview.jsf"。>

如何做到这一点?


环境:

  1. Eclipse Luna
  2. Java 1.7
  3. JSF 2

当前条件

Web应用程序完全可操作,但不是为支持可访问性功能而开发的。

下一版本的要求

成为一个足够好的应用程序,供使用屏幕阅读器的盲人使用。

详细信息

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

我们将为每个页面设计这样的可访问版本,问题是何时显示不可访问版本以及何时显示可访问版本。

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

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

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

提前感谢!

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

如果您已经使用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>

正如我所看到的,有两种可能的解决方案

  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>

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

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

最新更新