JSF @ViewScoped Bean State丢失了

时间:2012-10-09 08:59:22

标签: jsf-2 richfaces

我正在使用@ViewScoped Bean进行小型CRUD应用程序我有一个编辑和查看页面但是当我单击按钮(编辑)时,它将呈现编辑表单。出现编辑表单后,保存按钮或取消按钮不会调用该功能,而是呈现整个页面。根本不调用actionListener函数,并初始化everthing。我的bean和页面有问题吗?我正在使用带有richfaces和facelet的JSF 2。

          //ViewScoped Bean   

            /*
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package com.legendMgr.Legend;

    import java.io.Serializable;
    import java.sql.SQLException;
    import java.util.List;


    import java.util.logging.Logger;
    import javax.annotation.PostConstruct;

    import javax.faces.application.FacesMessage;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ViewScoped;

import javax.faces.context.FacesContext;

/**
 *
 * @author kitex
 */
@ManagedBean(name = "legendbean")
@ViewScoped
public class LegendController implements Serializable {

    LegendDTO legendDTO;
    String selectedLegend;
    List<LegendDTO> legendDTOs;
    boolean edit;

    public List<LegendDTO> getLegendDTOs() {
        return legendDTOs;
    }

    public void setLegendDTOs(List<LegendDTO> legendDTOs) {
        this.legendDTOs = legendDTOs;
    }

    @PostConstruct
    void initialiseSession() {
        FacesContext.getCurrentInstance().getExternalContext().getSession(true);
    }

    public LegendController() {
        if (!edit) {
            legendDTO = new LegendDTO();
            legendDTO.getList().add(new Legend());
            legendDTOs = getLegends();
        }
    }


    public String getSelectedLegend() {
        return selectedLegend;
    }

    public void setSelectedLegend(String selectedLegend) {
        this.selectedLegend = selectedLegend;
    }

    public boolean isEdit() {
        return edit;
    }

    public void setEdit(boolean edit) {
        this.edit = edit;
    }

    public LegendDTO getLegendDTO() {
        return legendDTO;
    }

    public void setLegendDTO(LegendDTO legendDTO) {
        this.legendDTO = legendDTO;
    }

    public void addLegendRange() {
        Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());
        legendDTO.getList().add(new Legend());
        Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());

    }

    public void removeLegendRange(Legend legend) {
        if (legendDTO.getList().size() != 1) {
            legendDTO.getList().remove(legend);
        }
    }

    public String saveLegend() {
        Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
        LegendDAO dao = new LegendDAO();
        if (dao.addLegend(legendDTO, edit)) {
            edit = false;
            Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
        } else {

            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Could Not Save Confim if you have already defined Legend " + legendDTO.getLegendName() + "!"));
        }
        return "";
    }

    public String cancel() {
        edit = false;
        legendDTO = new LegendDTO();
        legendDTO.getList().add(new Legend());
         return "";
    }

    public List<LegendDTO> getLegends() {
        LegendDAO dao = new LegendDAO();
        return dao.getLegendDTO();
    }

    //All function from here are for legend  delete
    public void deleteLegendType(LegendDTO dto) {
        LegendDAO dao = new LegendDAO();
        if (dao.deleteLegendType(dto.getLegendName())) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted !"));
        } else {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted Error !"));
        }
    }

    //All function from here is to legend edit
    public void editLegendType(LegendDTO dto) {
        edit = true;
        Logger.getLogger(LegendController.class.getName()).warning("DTO : " + dto.legendName);
        legendDTO = dto;
        LegendDAO dao = new LegendDAO();
        Logger.getLogger(LegendController.class.getName()).warning("Edit dto set");
        try {
            List<Legend> legends = dao.getDetailForEditLegend(dto.getLegendName());
            if (legends == null || legends.isEmpty()) {
                dto.getList().add(new Legend());
            } else {
                dto.setList(legends);
            }
        } catch (SQLException ex) {
            Logger.getLogger(LegendController.class.getName()).warning("SQL EXception has occoured");
        }
        Logger.getLogger(LegendController.class.getName()).warning("In Edit Legend Function The size of list" + dto.getList().size());

    }
}

// xhtml代码

       <?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:rich="http://richfaces.org/rich"
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <ui:composition template="/legendTemplate.xhtml">
            <ui:define name="windowTitle">Change Legend</ui:define>
            <ui:define name="content">


                <h:messages globalOnly="true"/>
                <rich:panel id="firstPanel">
                    <h:form id="nis_viewLegend">
                        <rich:dataTable id="data_tbl" value="#{legendbean.legendDTOs}" var="legendDTOvar" style="width:100%" rendered="#{!legendbean.edit and not empty legendbean.legendDTOs}">
                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="Description"/>
                                </f:facet>
                                <h:outputText value="#{legendDTOvar.desc}"/>
                            </rich:column>

                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="Legend Type"/>
                                </f:facet>
                                <h:outputText value="#{legendDTOvar.legendName}"/>
                            </rich:column>

                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="Legend Type"/>
                                </f:facet>
                                <h:outputText value="#{legendDTOvar.legendFor}"/>
                            </rich:column>

                            <rich:column>

                                <a4j:commandLink value="Delete" actionListener="#{legendbean.deleteLegendType(legendDTOvar)}" render=":firstPanel"/>
                                <h:outputText value="/"/>
                                <a4j:commandLink value="Edit" actionListener="#{legendbean.editLegendType(legendDTOvar)}" render=":secondPanel :editLegendForm :nis_viewLegend"/>

                            </rich:column>

                        </rich:dataTable>
                    </h:form>
                </rich:panel>

                <rich:panel id="secondPanel">
                    <h:form id="editLegendForm" rendered="#{legendbean.edit}">
                        <h:outputText value="Legend Name"/><br/>
                        <h:inputText value="#{legendbean.legendDTO.legendName}"  readonly="true"/><br/>

                        <h:outputText value="Description"/><br/>
                        <h:inputText value="#{legendbean.legendDTO.desc}"/><br/>

                        <h:outputText value="Legend For"/><br/>
                        <h:inputText value="#{legendbean.legendDTO.legendFor}"/><br/>
                        <br/> 
                        <h:outputText value="Range"  />  
                        <rich:dataTable id="editDataPnl" value="#{legendbean.legendDTO.list}" var="legend" style="width:100%">

                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="SN"/>
                                </f:facet>
                                <h:inputText value="#{legend.sn}"/>
                            </rich:column>

                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="Description"/>
                                </f:facet>
                                <h:inputText value="#{legend.desc}"/>
                            </rich:column>

                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="Lower Range"/>
                                </f:facet>
                                <h:inputText value="#{legend.lowerRange}"/>
                            </rich:column>

                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="Upper Range"/>
                                </f:facet>
                                <h:inputText value="#{legend.upperRange}"/>
                            </rich:column>

                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="Color"/>
                                </f:facet>
                                <h:inputText value="#{legend.color}"/>
                            </rich:column>

                            <rich:column>
                                <a4j:commandLink value="Add" actionListener="#{legendbean.addLegendRange}" render=":secondPanel"/>
                                <h:outputText value=" / "/>
                                <a4j:commandLink value="Remove" actionListener="#{legendbean.removeLegendRange(legend)}" render=":secondPanel"/>
                            </rich:column>
                        </rich:dataTable>

                        <br/>
                        <center>
                            <a4j:commandButton value="SAVE" action="#{legendbean.saveLegend()}" render=":firstPanel :secondPanel"/>
                            <a4j:commandButton value="CANCEL" action="#{legendbean.cancel()}" render=":firstPanel :secondPanel"/>
                        </center>
                    </h:form>
                </rich:panel>

            </ui:define>

        </ui:composition>
    </h:body>
</html>

3 个答案:

答案 0 :(得分:1)

在ViewScope中,一旦构建了视图,例如form.xhtml,其数据将持续很长时间,您不会离开此视图。要保持相同的视图,您应该调用返回类型为void的方法(通常在actionListener属性中使用)或返回null,以便返回导航结果。

  • 方法表达

在您的情况下,您的方法无效,但不是将其传递给您在视图中调用它的动作侦听器。

尝试更改类似的代码:

<a4j:commandButton value="SAVE" actionListener="#{legendbean.saveLegend()}" render="mainPnl"/>

对此:

<a4j:commandButton value="SAVE" actionListener="#{legendbean.saveLegend}" render="mainPnl"/>

由于actionListener属性已经需要方法表达式。

  • 数据表格内的表格

另外我注意到你的dataTable中有一个表单。这可能会导致奇怪的行为,因为您的表单有一个id,它将在结果页面中重复出现。为此,您应该尝试将表单放在dataTable之外。

更好的是,只有一个表单包含整个代码,因为嵌套表单是无效的HTML代码。

我建议您检查legendTemplate.xhtml对抗嵌套表单。

  • Bean构建

为了初始化bean状态,建议使用@PostContruct方法而不是bean构造函数。

尝试改变:

        public LegendController() {
            legendDTO = new LegendDTO();
            legendDTO.getList().add(new Legend());
        }

对此:

        @PostConstruct
        public void reset() {
            legendDTO = new LegendDTO();
            legendDTO.getList().add(new Legend());
        }

删除你的构造函数。

只要您在相同的视图(也就是.xhtml页面)中,您的bean数据就应该保留。

我希望它有所帮助。

答案 1 :(得分:1)

我遇到了同样的问题。我不认为上面的答案真正解决了这个问题。由于提交任何表单,他没有遇到任何问题 - 按下这些按钮本身会导致整个页面重新呈现,这意味着在按下按钮之前,对视图状态的引用已经消失。这也是我所观察到的。对我来说,它只发生在有很多大型搜索结果时,只需重新提交相同的搜索,我就重新渲染页面(不执行搜索)。我认为问题与对表单中可以传递给服务器的数据量的限制有关:在视图范围内,所有数据都被序列化并在一个长隐藏值中作为表单中的值传递。如果该值太长,服务器将不接受它,因此将不记得先前的状态。

我知道这不是确定的,但这只是关于我能找到的这个问题的线索所以我希望它有助于为其他人提供亮点或激发更好的信息。如果您有更明确的内容,请告诉我们。

编辑:我现在确信这是问题所在。我的模型bean有一个文件blob的引用。一旦我用布尔值替换了该引用(只需要知道它是否存在),问题就消失了。尝试传递对DTO / DAO的引用而不是对象本身,或将它们标记为“瞬态”,而不需要它们持久存在。或者,如果可能的话,像我一样照亮物体。

答案 2 :(得分:0)

您是否尝试为函数saveLegend()和cancel()返回null而不是返回空字符串?

public String saveLegend() {
     ---------
     return null;
}

public String cancel() {
     ----------
     return null;
}

对于ajax请求,返回也可以是无效的。但是,如果我正确地记住了richfaces返回null是唯一的解决方案。试试看。 :) cancel()在重新初始化bean时起作用。

正如Bento所回答的那样,您无法使用actionListener传递值。改为使用动作。

进一步阅读: