13

私はExternalContext.redirect(String);を使用しています。ユーザーを別のページにリダイレクトする方法:

FacesContext.getCurrentInstance().addMessage(new FacesMessage("Bla bla bla..."));
FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(true);
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/scenario.xhtml");

Matt Handyが彼の回答で述べたように、私はFlash.setKeepMessages(true);を使用しました。ただし、ExternalContext.redirectでは機能しないようです。(ただし、Beanのアクションメソッドからページ名を返すことでリダイレクトすると機能します。)

リダイレクトされた(scenario.xhtml)ページに表示されるようにFacesMessageを追加するにはどうすればよいですか?

4

3 に答える 3

18

これはタイミングの問題のようです。preRenderViewこのリスナー メソッドは、イベント中に呼び出されます。ELFlash(によって返される Mojarra のFlash実装)のソース コードによると、ExternalContext#getFlash()現在レンダリング レスポンス フェーズにあり、現在のリクエストに対してまだフラッシュ Cookie が設定されていない場合、フラッシュ Cookie が設定されないことがわかります。 :

からの関連行は次のELFlashとおりです。

if (currentPhase.getOrdinal() < PhaseId.RENDER_RESPONSE.getOrdinal()) {
    flashInfo = flashManager.getPreviousRequestFlashInfo();
} else {
    flashInfo = flashManager.getNextRequestFlashInfo(this, true);
    maybeWriteCookie(context, flashManager);
}

maybeWriteCookie、Flash Cookie を 2 回目に渡す必要がある場合 (つまり、リダイレクトされたページが別のページにリダイレクトされる場合) にのみ Cookie を設定します。

これは残念なコーナーケースです。このELFlashロジックは理にかなっていますが、これは実際に必要なものではありません。基本的INVOKE_APPLICATIONに、代わりにフェーズ中にメッセージを追加する必要があります。ただし、 のようなイベントはありませんpostInvokeAction。新しい JSF 2.2<f:viewAction>タグを使用すると、アプリケーションの呼び出し段階で実際に実行されるため、可能になるはずです。

<f:viewAction action="#{bean.onload}" />

まだ JSF 2.2 を使用していない限り、別の方法を探す必要があります。最も簡単な方法は、カスタム を作成することComponentSystemEventです。

@NamedEvent(shortName="postInvokeAction")
public class PostInvokeActionEvent extends ComponentSystemEvent {

    public PostInvokeActionEvent(UIComponent component) {
        super(component);
    }

}

ここで、このイベントを公開するためのフックが必要です。最も賢明な場所は、のPhaseListenerフェーズの後のリスニングですINVOKE_APPLICATION

public class PostInvokeActionListener implements PhaseListener {

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.INVOKE_APPLICATION;
    }

    @Override
    public void beforePhase(PhaseEvent event) {
        // NOOP.
    }

    @Override
    public void afterPhase(PhaseEvent event) {
        FacesContext context = FacesContext.getCurrentInstance();
        context.getApplication().publishEvent(context, PostInvokeActionEvent.class, context.getViewRoot());
    }

}

に以下のように登録するとfaces-config.xml

<lifecycle>
    <phase-listener>com.example.PostInvokeActionListener</phase-listener>
</lifecycle>

その後、次のように新しいイベントを使用できます

<f:event type="postInvokeAction" listener="#{bean.onload}" />

これを更新すると、JSF ユーティリティ ライブラリOmniFacesでも​​利用できるため、自作する必要はありません。InvokeActionEventListenerショーケースの例も参照してください。

于 2012-06-04T20:26:44.720 に答える
16

フラッシュを使用して、リダイレクト経由でメッセージを保持します。

リダイレクトするに、次の 2 行をコードに追加します。

FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getFlash().setKeepMessages(true);

Mojarra のフラッシュ スコープの実装にはいくつかの問題があることに注意してください。使用する場合は、この点に注意してください。

于 2012-05-15T07:17:47.113 に答える
-2

Matt Handy の例を参照として使用して、私にとって非常にうまく機能する以下のメソッドを作成しました。

public static void Message(String message) {
    FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_INFO, mensagem, null);
    FacesContext context = FacesContext.getCurrentInstance();
    context.getExternalContext().getFlash().setKeepMessages(true);
    context.addMessage(null, fm);
}
于 2020-01-18T15:50:36.077 に答える