Почему flash.keep() удаляет ключ, если он находится в бине, а не в EL на странице Facelets?

Итак, у меня есть очень маленький пример JSF:

<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
    <title>Index</title>
</h:head>
<h:body>
    <h:form>
        <h:commandButton action="#{reqScopedBackingBean.foo()}" value="Submit"/>
    </h:form>
</h:body>
</html>

и foo реализуется, как показано ниже:

package biz.tugay.jsftags;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

@ManagedBean
@RequestScoped
public class ReqScopedBackingBean {
    public String foo() {
        FacesContext.getCurrentInstance().getExternalContext().getFlash().put("message", "Success!!");
        return "hello?faces-redirect=true";
    }
}

и наконец hello.xhtml как следует:

<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
    <title>Hello</title>
</h:head>
<h:body>
    <h:outputText value="#{flash.keep.message}"/>
</h:body>
</html>

в приведенном выше примере, когда я нажму "Отправить", я буду перенаправлен в hello.xhtml и увижу "Успех!!" текст просто отлично. И когда я обновлю страницу, я все равно увижу сообщение, потому что я вызываю метод keep, как показано ниже:

#{flash.keep.message}

Теперь перейдем к другому примеру:

index.xhtml и ReqScopedBackingBean одинаковы, однако на этот раз hello.xhtml выглядит следующим образом:

<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
    <title>Hello</title>
</h:head>
<h:body>
    #{otherBean.pullValuesFromFlash()}
    <h:outputText value="#{otherBean.message}"/>
</h:body>
</html>

а также OtherBean.java как следует:

@ManagedBean
@RequestScoped
public class OtherBean {

    private String message;

    public void pullValuesFromFlash() {
        final Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
        flash.keep("message");
        final String message = (String) flash.get("message");
        setMessage(message);
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Я ожидаю, что поведение будет таким же, как в первом примере. Однако, когда я нахожусь на hello.xhtml, я не увижу сообщение об успехе. Однако, если я закомментирую строку:

// flash.keep("message");

тогда появится сообщение (но обновление hello.xhtml не отобразит сообщение об успехе, как в первом примере).

У меня вопрос, в чем здесь разница? Как

#{flash.keep.message}

и отличается от

flash.keep("message");
final String message = (String) flash.get("message");

?

1 ответ

Решение

Вы попали в ошибку Мохарры Flash#keep(), По сути, Mojarra излишне удаляет запись из текущей области флэш-памяти, прежде чем поместить ее в следующую область флэш-памяти.

Это будет работать, если вы измените порядок логики, как показано ниже.

public void pullValuesFromFlash() {
    Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
    String message = (String) flash.get("message");
    flash.keep("message");
    setMessage(message);
}

Я исправил эту ошибку согласно проблеме 4167.


Не связанные с конкретной проблемой, те, <h:outputText> с не нужны. Вы можете безопасно удалить их, чтобы уменьшить шаблон. См. Также Предлагается ли использовать h:outputText для всего?

Другие вопросы по тегам