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;
}
Другие вопросы по тегам