首页 文章

为什么@PostConstruct回调每次都会触发,即使bean是@ViewScoped? JSF

提问于
浏览
31

我在页面上使用datatable并使用绑定属性将其绑定到我的支持bean . 这是我的代码: -

<?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:p="http://primefaces.prime.com.tr/ui">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
            <h:form prependId="false">

                <h:dataTable var="item" value="#{testBean.stringCollection}" binding="#{testBean.dataTable}">
                    <h:column>
                        <h:outputText value="#{item}"/>
                    </h:column>
                    <h:column>
                        <h:commandButton value="Click" actionListener="#{testBean.action}"/>
                    </h:column>
                </h:dataTable>

            </h:form>

    </h:body>
</html>

这是我的 beans 子: -

package managedBeans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.html.HtmlDataTable;

@ManagedBean(name="testBean")
@ViewScoped
public class testBean implements Serializable {

    private List<String> stringCollection;

    public List<String> getStringCollection() {
        return stringCollection;
    }

    public void setStringCollection(List<String> stringCollection) {
        this.stringCollection = stringCollection;
    }

    private HtmlDataTable dataTable;

    public HtmlDataTable getDataTable() {
        return dataTable;
    }

    public void setDataTable(HtmlDataTable dataTable) {
        this.dataTable = dataTable;
    }

    @PostConstruct
    public void init(){
        System.out.println("Post Construct fired!!");
        stringCollection = new ArrayList<String>();
        stringCollection.add("a");
        stringCollection.add("b");
        stringCollection.add("c");

    }

    public void action(){
        System.out.println("Clicked!!");

    }
}

请告诉我为什么@PostConstruct每次点击按钮都会触发?只要我在同一页面上,它应该只触发一次,因为我的bean是@ViewScoped . 此外,如果我删除绑定属性,那么一切正常,@ PostConstruct回调只触发一次 . 那么为什么每次我使用绑定属性?我需要绑定属性,并且想要执行初始化任务,例如只从webservice等获取数据一次 . 我该怎么办?我应该在哪里写我的初始化任务?

5 回答

  • 32

    有趣的是,当您在视图范围bean上使用组件绑定时,视图范围会中断 .

    我不确定这是否是JSF2中的错误,我必须首先阅读整个JSF2规范 . 到目前为止,最好的办法是暂时删除组件绑定,并通过新的EL 2.2方法参数语法传递所选项:

    <h:dataTable var="item" value="#{testBean.stringCollection}">
        <h:column>
            <h:outputText value="#{item}"/>
        </h:column>
        <h:column>
            <h:commandButton value="Click" action="#{testBean.action(item)}"/>
        </h:column>
    </h:dataTable>
    

    另见:


    Update (2012年12月):这确实是JSF2中的一个错误 . 这是一个鸡蛋问题 . 视图范围bean存储在JSF视图状态中 . 因此视图范围bean仅在还原视图阶段后可用 . 但是, binding 属性在还原视图阶段运行,而视图范围Bean尚不可用 . 这会导致创建一个全新的视图范围bean实例,然后由实际视图范围bean替换,该实例存储在已恢复的JSF视图状态中 .

    报告为JSF issue 1492JSF spec isssue 787,将为JSF 2.2修复 . 在此之前,您最好的选择是仅在请求范围内的bean上使用 binding ,或者为特定功能需求寻找替代方法 .


    Update (2015年3月):JSF 2.2修复程序被移植到Mojarra 2.1.18 . 所以,如果你最好升级到至少那个版本 . 另见a.o. What is component binding in JSF? When it is preferred to be used?JSTL in JSF2 Facelets... makes sense?

  • 0

    正如其他人所说,我想说最好的办法是删除组件绑定(这里不需要它) .

    但我想补充一点,你可以通过使用动作参数以更加面向对象的方式实现相同的目标,如下所示:

    <h:commandButton value="Click" action="#{testBean.action(item)}"/>
    

    ...并在您的Java代码中:

    public void action(Item item){
        System.out.println("Clicked!!" + item);
    }
    
  • 0

    如果您有一个viewscoped bean,并且如果您想保留在表单上输入的值或者不希望触发postconstruct,那么您应该从action方法返回null .

    如果您返回一些结果(例如无效),然后使用faces-config.xml将无效结果指向同一页面,则会重新创建viewscoped bean,从而导致postconstruct再次触发 .

  • 4

    其他方案:

    • 将HtmlDataTable绑定在请求范围bean中 .

    • 在视图范围bean中注入此请求范围bean .

    JBoss Seam使用此解决方案将JSF组件绑定到会话范围组件 .

  • 0

    balusc的答案对我帮助很大,我想说我有mojarra版本2.1.7的那个bug,我目前正在使用2015年1月发布的2.1.29-01并且这个bug已修复,我的问题是绑定了tabview到一个viewscoped bean . 有了这个版本,我没有那个bug,绑定和postconstruct正常工作 . 我使用Jboss 5.2,我必须使用mojarra 2.1.x所以我希望这个答案可以帮助其他人处于相同的情况 .

    http://mvnrepository.com/artifact/com.sun.faces/jsf-api/2.1.29-01 http://mvnrepository.com/artifact/com.sun.faces/jsf-impl/2.1.29-01

相关问题