質問

ユーザーをいくつかの特定のページ (項目を表示または編集できるページなど) に直接送信できる Web アプリケーションがあります。これを実現するために、特定の URL を提供します。これらの URL は次のとおりです。 現在の Web アプリケーション (つまり、別の Web アプリケーションまたは電子メールに存在する可能性があります)。

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

  • アクション ユーザーがリダイレクトされるページを表します。これは次のように考えることができます。 from-outcome の JSF アクションの navigation-casefaces-config.xml.
  • アクションパラメータ 前のアクションのパラメータ (通常はアイテム 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.xhtml, view.xhtml または access-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> 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

役に立ちましたか?

解決

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>

このようにリクエストは forward.jsf?action=outcome1&actionParam=123 JSF に設定させます action そして actionParam パラメータとして action そして actionParam のプロパティ ForwardBean.

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

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

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

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


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

他のヒント

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

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

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

そして、close メソッドでは、次のように修正します。

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

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

もちろん、この五線はすべて中間ページではなく、オリジナルのページに記述する必要があります。そしてその中に close() このメソッドでは、パラメータを使用してリダイレクト先を動的に選択できます。

編集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();
            }
        }
    }
}

(少なくとも最初のテストに関しては) 機能しますが、実装方法がまだ気に入りません...もっと良いアイデアはありますか?


編集 この解決策は、 ない 仕事。確かに、 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 呼び出しは含まれていません。 作品 する ない 仕事。

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

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

次に、Java (サービス) クラスでのダイレクトのメソッドを確認します。

 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>
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top