Flash-сообщения не отображаются после перенаправления в MyFaces, пока он работал в Мохарре
У меня есть свой собственный ExceptionHandlerWrapper для управления ViewExpiredException и других ошибок.
Идея состоит в том, чтобы перехватить ошибку, добавить некоторое сообщение об ошибке и перенаправить (с перенаправлением, а не с навигацией) на страницу индекса, где будет отображаться сообщение об ошибке.
fc.getExternalContext().getFlash().setKeepMessages(true);
Messages.addFlashError(null, "my message");
Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
flash.put("foo", "hello");
fc.getExternalContext().redirect("index.xhtml");
Однако флэш-сообщения не сохраняются (но в области видимости присутствует foo).
Это работало в мохарре, но я перешел на мои лица 2.2.4, и оно перестало работать. Любая идея? (также используя omnifaces 1.8.1) Спасибо.
2 ответа
Я посмотрел на исходный код MyFaces, и оказалось, что им явно требуется дополнительная Flash#setRedirect()
позвонить сверху Flash#setKeepMessages()
, Хотя Javadoc, по общему признанию, не совсем ясен в этом вопросе, я ожидаю, что setRedirect(true)
необходим только для атрибутов Flash, а не для сообщений Flash, имеющих свои setKeepMessages(true)
вызов.
Итак, в основном вы должны делать следующее:
fc.getExternalContext().getFlash().setKeepMessages(true);
Messages.addFlashError(null, "my message");
Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
flash.put("foo", "hello");
fc.getExternalContext().getFlash().setRedirect(true); // <-- Add this.
fc.getExternalContext().redirect("index.xhtml");
Однако, поскольку вы уже используете служебную библиотеку JSF OmniFaces, которая уже неявно вызывает setKeepMessages(true)
когда вы используете Messages#addFlashXxx()
методы, а также неявные вызовы setRedirect(true)
когда вы используете Faces#redirect()
метод, вы могли бы получить только следующее, что делает точно так же, как и выше "беспорядок":
Messages.addFlashGlobalError("my message");
Faces.setFlashAttribute("foo", "hello");
Faces.redirect("index.xhtml");
Нет необходимости в пользовательском слушателе фазы.
Я решил это временно с помощью PhaseListener. Мне это не нравится, но пока работает
Что я делаю, когда я добавляю флэш-сообщение, я также помещаю его во флеш-область:
Messages.addFlash(null, new FacesMessage(severity, summary, detail));
context.getExternalContext().getFlash().put("messages", context.getMessageList());
Затем я восстанавливаю их в phaseListener
public void beforePhase(final PhaseEvent event) {
FacesContext facesContext = event.getFacesContext();
if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId())) {
if (!facesContext.getResponseComplete()) {
this.restoreMessages(facesContext);
}
}
}
private int restoreMessages(final FacesContext facesContext) {
final Object flash = facesContext.getExternalContext().getFlash().get("messages");
if (flash != null) {
List<FacesMessage> messages = (List<FacesMessage>) flash;
int restoredCount = messages.size();
for (Object element : messages) {
facesContext.addMessage(null, (FacesMessage) element);
}
return restoredCount;
}
return 0;
}