如何在 JSF 1.x 中对页面加载进行重定向

2022-09-01 12:00:00

我有一个Web应用程序,用户可以直接发送到某些特定页面(例如他可以查看或编辑项目的页面)。为此,我们提供了一个特定的网址。这些网址位于当前Web应用程序之外(即它们可以存在于另一个Web应用程序中,也可以存在于电子邮件中)。

该网址如下所示,其中:http://myserver/my-app/forward.jsf?action=XXX&param=YYY

  • 操作表示将重定向到用户的页面。您可以将此视为 中任何 JSF 操作的操作。from-outcomenavigation-casefaces-config.xml
  • actionParam 是上一个操作的参数(通常是项目 ID)

例如,我可以拥有这些类型的网址:

  • http://myserver/my-app/forward.jsf?action=viewItem&actionParam=1234
  • http://myserver/my-app/forward.jsf?action=editItem&actionParam=1234

当然,我有一个Java类(bean),它将检查一些安全约束(即是否允许用户查看/编辑相应的项目?),然后将用户重定向到正确的页面(例如,或)。edit.xhtmlview.xhtmlaccess-denied.xhtml


当前实现

目前,我们有一个基本的方法来完成前进。当用户单击该链接时,将调用以下 XHTML 页:

<html>
    <body id="forwardForm">
        <h:inputHidden id="myAction" binding="#{forwardBean.hiddenAction}"/>
        <h:inputHidden id="myParam" binding="#{forwardBean.hiddenActionParam}"/>
        <h:commandButton id="forwardBtn" actionListener="#{forwardBean.doForward}" style="display: none;"/>
    </body>
    <script type="text/javascript">
        document.getElementById('forwardForm:forwardBtn').click();
    </script>
</html>

如您所见,我在 Java Bean 中绑定了两个组件。它们将用于存储两者和请求参数的值(使用 )。我还提供了在呈现页面时将立即调用的方法,该方法将(再次)将用户重定向到真实页面。方法是:<h:inputHidden>actionactionParamFacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("actiontParam");doForward

public void doForward(ActionEvent evt) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    String redirect = // define the navigation rule that must be used in order to redirect the user to the adequate page...
    NavigationHandler myNav = facesContext.getApplication().getNavigationHandler();
    myNav.handleNavigation(facesContext, null, redirect);
}

这个解决方案是有效的,但我有两个问题:

  • 我不喜欢它的实现方式。我相信我可以有更简单的东西(使用Servlet?)。
  • 这个解决方案使用Javascript,我一定不能使用Javascript(因为这个转发可能被旧的黑莓用户使用,其中Javascript不受支持)。

所以我的问题是如何重构这个重定向/转发功能?

技术资料

Java 1.6, JSF 1.2, Facelets, Richfaces


答案 1

将 GET 查询参数设置为 托管属性,这样您就不需要手动收集它们:faces-config.xml

<managed-bean>
    <managed-bean-name>forward</managed-bean-name>
    <managed-bean-class>com.example.ForwardBean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
    <managed-property>
        <property-name>action</property-name>
        <value>#{param.action}</value>
    </managed-property>
    <managed-property>
        <property-name>actionParam</property-name>
        <value>#{param.actionParam}</value>
    </managed-property>
</managed-bean>

这样,请求将让 JSF 将 和 参数设置为 和 属性。forward.jsf?action=outcome1&actionParam=123actionactionParamactionactionParamForwardBean

创建一个小视图(小到适合默认响应缓冲区(通常为 2KB),以便导航处理程序可以重置它,否则您必须在 servletcontainer 的配置中增加响应缓冲区),这将调用 :forward.xhtmlbeforePhasef:view

<!DOCTYPE html>
<html xmlns:f="http://java.sun.com/jsf/core">
    <f:view beforePhase="#{forward.navigate}" />
</html>

可以看起来像这样:ForwardBean

public class ForwardBean {
    private String action;
    private String actionParam;

    public void navigate(PhaseEvent event) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        String outcome = action; // Do your thing?
        facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, outcome);
    }

    // Add/generate the usual boilerplate.
}

不言自明(注意那些可以做的条目,而不是在幕后):navigation-rule<redirect />ExternalContext#redirect()ExternalContext#dispatch()

<navigation-rule>
    <navigation-case>
        <from-outcome>outcome1</from-outcome>
        <to-view-id>/outcome1.xhtml</to-view-id>
        <redirect />
    </navigation-case>
    <navigation-case>
        <from-outcome>outcome2</from-outcome>
        <to-view-id>/outcome2.xhtml</to-view-id>
        <redirect />
    </navigation-case>
</navigation-rule>

另一种方法是用作forward.xhtml

<!DOCTYPE html>
<html>#{forward}</html>

并更新要调用的方法(将在 bean 的构造和所有托管属性设置之后调用):navigate()@PostConstruct

@PostConstruct
public void navigate() {
    // ...
}    

它具有相同的效果,但是视图侧并不是真正的自我记录。它基本上所做的就是打印(如果还不存在,则特此隐式构造bean)。ForwardBean#toString()


请注意,对于 JSF2 用户,有一种更清晰的参数传递方式,以及更可靠的方法来处理 重定向/导航。另请参阅以下内容:<f:viewParam><f:event type="preRenderView">


答案 2
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
response.sendRedirect("somePage.jsp");

推荐