如何在Ajax调用或重载后将对象保持在JSF Flash作用域上

How to keep objects on JSF Flash Scope after Ajax call or Reload?

本文关键字:JSF 作用域 对象 Flash Ajax 调用 重载      更新时间:2023-09-26

我有一个'大'项目,大表和很多关系…因此,在我的表单中,我有几个选项卡,一些对话框和许多PrimeFaces命令按钮来管理所有带有Ajax请求的CRUD。

xhtml结构是这样的:

<ui:define name="content">
<h:body>
    <p:growl id="growl"/>
    <h:form id="formCars" enctype="multipart/form-data">
        <p:tabView id="formTabView" scrollable="true" >
            <p:tab title="Tab1">
                <ui:include src="tabOne/tabOne.xhtml" />
            </p:tab>
            <p:tab title="Tab2">...</p:tab>
            ...
            <p:tab title="Tab8">...</p:tab>
        </p:tabView>
        <br />
        <div align="center">
            <p:commandButton id="cmdSave" value="Save" 
                action="#{controllerMB.save}" icon="ui-icon-disk" 
                update="@form :growl" process="@form @this" validateClient="true" />
        </div>
    </h:form>
    <p:dialog header="Car Color" id="modalCarColor" widgetVar="modalCarColor" appendToBody="true" modal="true" height="500" width="700" dynamic="true" closeOnEscape="true" >
        <p:ajax event="close" listener="#{controllerMB.closeModalCarColor}" update="@this,:formCarColor"/>
        <h:form id="formCarColor">
            <ui:include src="tabTwo/carColor/carColor.xhtml" />
        </h:form>
    </p:dialog>
    <p:dialog header="Car Size" ...>
        <p:ajax event="close" .../>
        <h:form id="formCarColor">...</h:form>
    </p:dialog>
</h:body>
</ui:define>

它完美地工作…问题是当我尝试重新加载页面时…我通过使用

来保持主要对象在闪光灯上
FacesContext.getCurrentInstance().getExternalContext().getFlash().keep(key)

在@ViewScoped控制器的@PostConstruct上。如果我访问页面,不触摸ajax按钮,我可以重新加载页面没有问题…但是,如果我触摸任何引起ajax请求的东西,JSF Flash scope就会丢失主对象,因此我无法重新加载页面。

我的控制器是这样构建的:

@ManagedBean(name="controllerMB")
@ViewScoped
public class ControllerMB implements Serializable{
    // attributes
    // ----------
    @PostConstruct
    public void init(){
        if(FacesContext.getCurrentInstance().getExternalContext().getFlash().containsKey("car")) {
            car = (Car) FacesContext.getCurrentInstance().getExternalContext().getFlash().get("car");
            FacesContext.getCurrentInstance().getExternalContext().getFlash().keep("car");
        }
        if(car==null) { 
            redirect_back();
            return;
        }
        // attributes initialization and form preparation
        // -----
    }
    // methods
    // ----------
}

作为主要对象的"car"只是一个例子。

对此有任何解决方案或变通方法吗?

我想在"意外重新加载"后保持状态,但是,它不能与Flash一起工作。

此外,是否有可能捕获/处理从浏览器(也许与js)重新加载事件?我的意思是,这样我就可以在重载之前在主对象中处理表单。

我在我的项目中使用PrimeFaces 5.3, JSF 2, Maven, Tomcat 7和Java 7。

提前感谢大家。


编辑1:在尝试了用户NightEagle提到的解决方案后,它几乎工作了…我修改了代码:

<ui:composition ....>
    <f:metadata>
      <f:event type="preRenderView" listener="#{controllerMB.preRender}"/>
    </f:metadata>
    <ui:define name="title">...</ui:define>
    <ui:define name="header">...</ui:define>
    <ui:define name="content">...</ui:define>
</ui:composition>

public void preRender()
{
    System.out.print("PRE-RENDER ");
    if(FacesContext.getCurrentInstance().getExternalContext().getFlash().containsKey("car")) {
        System.out.println("KEEP");
        FacesContext.getCurrentInstance().getExternalContext().getFlash().keep("car");
    } else {
        System.out.println("PUT");
        FacesContext.getCurrentInstance().getExternalContext().getFlash().put("car",car);
    }
}

奇怪的是,第一个ajax调用是好的,第二个之后…开始弹出JSF1095错误。

一些对话框打开后的输出:

PRE-RENDER PUT
PRE-RENDER KEEP
PRE-RENDER KEEP
Jul 14, 2017 11:43:59 AM com.sun.faces.context.flash.ELFlash setCookie
WARNING: JSF1095: The response was already committed by the time we tried to set the outgoing cookie for the flash.  Any values stored to the flash will not be available on the next request.
PRE-RENDER PUT
Jul 14, 2017 11:44:00 AM com.sun.faces.context.flash.ELFlash setCookie
WARNING: JSF1095: The response was already committed by the time we tried to set the outgoing cookie for the flash.  Any values stored to the flash will not be available on the next request.
PRE-RENDER PUT
Jul 14, 2017 11:44:04 AM com.sun.faces.context.flash.ELFlash setCookie
WARNING: JSF1095: The response was already committed by the time we tried to set the outgoing cookie for the flash.  Any values stored to the flash will not be available on the next request.

提前感谢大家,仍在寻找解决方案

我想我知道如何解决它(它在我的项目中帮助了我)

<f:metadata>
  <f:event type="preRenderView" listener="#{myBean.preRender}"/>
</f:metadata>
支持bean:

public class MyBean
{
    @PostConstruct
    public void init(){
        if(FacesContext.getCurrentInstance().getExternalContext().getFlash().containsKey("car")) {
            car = (Car) FacesContext.getCurrentInstance().getExternalContext().getFlash().get("car");
            FacesContext.getCurrentInstance().getExternalContext().getFlash().keep("car");
        }
    }
    public void preRender()
    {
        if(FacesContext.getCurrentInstance().getExternalContext().getFlash().containsKey("car")) {
            FacesContext.getCurrentInstance().getExternalContext().getFlash().keep("car");
        }
    }
}

"preRenderView事件在每个HTTP请求(是的,这也包括ajax请求!)上被调用。"(c) https://stackoverflow.com/a/9844616/3163475