web-dev-qa-db-ja.com

JSF 1.xでページの読み込み時にリダイレクトを行う方法

ユーザーを特定のページ(アイテムを表示または編集できるページなど)に直接送信できるWebアプリケーションがあります。それを実現するために、特定のURLを提供します。これらのURLは、外部現在のWebアプリケーションに配置されます(つまり、別のWebアプリケーションまたは電子メールに存在できます)。

URLはhttp://myserver/my-app/forward.jsf?action=XXX&param=YYYのようになります。ここで、

  • actionは、ユーザーがリダイレクトされるページを表します。これは、from-outcomenavigation-caseにあるJSFアクションのfaces-config.xmlと見なすことができます。
  • actionParamは前のアクションのパラメーターです(通常はアイテムID)

たとえば、次のようなURLを使用できます。

  • 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>

ご覧のとおり、2つの<h:inputHidden>コンポーネントをmy Java Bean。にバインドします。これらはactionおよびactionParamリクエストの両方の値を格納するために使用されますパラメータ(FacesContext.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);
}

このソリューションは機能していますが、それには2つの問題があります。

  • 私はそれが実装される方法が好きではありません。 (サーブレットを使用して)よりシンプルなものを作成できると確信しています。
  • このソリューションはJavascriptを使用していますが、Javascriptを使用しないでください(これは、Javascriptがサポートされていない古いBlackberryユーザーによって使用される可能性があるためです)。

だから私の質問はこのリダイレクション/フォワード機能をリファクタリングする方法?

技術情報

Java 1.6、JSF 1.2、Facelets、Richfaces

30
Romain Linsolas

手動で収集する必要がないように、faces-config.xmlでGETクエリパラメーターを管理プロパティとして設定します。

<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>

このように、リクエストforward.jsf?action=outcome1&actionParam=123は、JSFがactionおよびactionParamパラメーターをactionactionParamおよびForwardBeanプロパティとして設定できるようにします。

Beanメソッドを呼び出す小さなビューforward.xhtml(ナビゲーションハンドラーによってリセットできるようにデフォルトの応答バッファー(多くの場合2KB)に収まるほど小さい)を作成します。そうしないと、サーブレットコンテナーの構成で応答バッファーを増やす必要があります。 f:viewbeforePhase

<!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はそれ自身を表しています(表紙の下ではExternalContext#redirect()の代わりにExternalContext#dispatch()を行う<redirect />エントリに注意してください):

<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>

@PostConstructで呼び出されるnavigate()メソッドを更新します(Beanの構築とすべての管理プロパティ設定の後に呼び出されます)。

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

同じ効果がありますが、ビュー側は実際には自己文書化されていません。基本的には、ForwardBean#toString()を印刷するだけです(まだ存在しない場合は、暗黙的にBeanを構築します)。


JSF2ユーザーへの注意:<f:viewParam>でパラメーターを渡すよりクリーンな方法と、<f:event type="preRenderView">によるリダイレクト/ナビゲーションを処理するより堅牢な方法があります。特に以下も参照してください。

30
BalusC
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
response.sendRedirect("somePage.jsp");
5
jnr

actionListenerの代わりにactionを使用する必要があります。

_<h:commandLink id="close" action="#{bean.close}" value="Close" immediate="true" 
                                   />
_

そして、近い方法であなたは次のようなものを正しい:

_public String close() {
   return "index?faces-redirect=true";
}
_

ここで、indexはページの1つです(index.xhtml)

もちろん、このスタッフはすべて、中級者ではなく、元のページに書く必要があります。 close()メソッド内では、パラメーターを使用して、リダイレクト先を動的に選択できます。

2
Vladimir Ivanov

編集2

私はそのような私の前方行動を実装することで最終的に解決策を見つけました:

_private void applyForward() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    // Find where to redirect the user.
    String redirect = getTheFromOutCome();

    // Change the Navigation context.
    NavigationHandler myNav = facesContext.getApplication().getNavigationHandler();
    myNav.handleNavigation(facesContext, null, redirect);

    // Update the view root
    UIViewRoot vr = facesContext.getViewRoot();
    if (vr != null) {
        // Get the URL where to redirect the user
        String url = facesContext.getExternalContext().getRequestContextPath();
        url = url + "/" + vr.getViewId().replace(".xhtml", ".jsf");
        Object obj = facesContext.getExternalContext().getResponse();
        if (obj instanceof HttpServletResponse) {
            HttpServletResponse response = (HttpServletResponse) obj;
            try {
                // Redirect the user now.
                response.sendRedirect(response.encodeURL(url));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
_

(少なくとも最初のテストに関しては)動作しますが、それが実装される方法がまだ好きではありません...より良いアイデアはありますか?


編集このソリューションはnotを行います。実際、doForward()関数が呼び出されたとき、JSFライフサイクルはすでに開始されており、新しい要求を再作成することはできません。


この問題を解決するための1つのアイデアですが、私は本当に好きではありませんが、doForward()メソッドのいずれかでsetBindedInputHidden()アクションを強制することです。

_private boolean actionDefined = false;
private boolean actionParamDefined = false;

public void setHiddenActionParam(HtmlInputHidden hiddenActionParam) {
    this.hiddenActionParam = hiddenActionParam;
    String actionParam = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("actionParam");
    this.hiddenActionParam.setValue(actionParam);
    actionParamDefined = true;
    forwardAction();
}

public void setHiddenAction(HtmlInputHidden hiddenAction) {
    this.hiddenAction = hiddenAction;
    String action = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("action");
    this.hiddenAction.setValue(action);
    actionDefined = true;
    forwardAction();
}

private void forwardAction() {
    if (!actionDefined || !actionParamDefined) {
        // As one of the inputHidden was not binded yet, we do nothing...
        return;
    }
    // Now, both action and actionParam inputHidden are binded, we can execute the forward...
    doForward(null);
}
_

このソリューションにはJavascript呼び出しは含まれません。 働く notは機能します。

1
Romain Linsolas

Foo.jspがjspファイルであると仮定します。次のコードは、リダイレクトするボタンです。

<h:commandButton value="Redirect" action="#{trial.enter }"/>  

そして、Java(service)クラスで指示するためのメソッドをチェックします

 public String enter() {
            if (userName.equals("xyz") && password.equals("123")) {
                return "enter";
            } else {
                return null;
            }
        } 

そして今、これはfaces-config.xmlファイルの一部です

<managed-bean>
        <managed-bean-name>'class_name'</managed-bean-name>
        <managed-bean-class>'package_name'</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
    </managed-bean>


    <navigation-case>
                <from-outcome>enter</from-outcome>
                <to-view-id>/foo.jsp</to-view-id>
                <redirect />
            </navigation-case>
0
berkancetin