Ответ 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
пример витрины.