Подтвердить что ты не робот

Добавление сообщения лиц на перенаправленную страницу с помощью ExternalContext.redirect()

Я использую метод 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");

Как сказал Мэтт Ханди в своем ответе, я использовал Flash.setKeepMessages(true);, но он не работает с ExternalContext.redirect. (Хотя он работает, когда я перенаправляю, возвращая имя страницы из метода действия bean.)

Теперь, как я могу добавить FacesMessage, чтобы он был видимым на странице перенаправленного (script.xhtml)?

4b9b3361

Ответ 1

Кажется, это проблема времени. Этот метод прослушивателя вызывается во время события 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 будет устанавливать cookie только в том случае, если флэш файл 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 пример витрины.

Ответ 2

Используйте флеш-память для хранения сообщений по перенаправлению.

Добавьте эти две строки в свой код перед перенаправлением:

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

Обратите внимание, что есть некоторые проблемы с реализацией флэш-сферы Mojarra. Имейте это в виду, если вы используете его.