ViewScope:定位“正确”的复合组件的对象实例

时间:2013-03-21 10:30:26

标签: jsf-2

进一步了解jsf 2视图范围的理解过程,我再次遇到问题。

创建了我的复合组件绑定对象的多个实例,并且设置值似乎不是针对“正确”的。

我的初始设置与Auto-instantiate session-scoped bean from view-scoped bean

相同

现在我创建了一个复合组件:

<composite:interface componentType="helloWidget">

</composite:interface>

<composite:implementation>
    <h:outputText value="Visible state of this composite component: #{cc.visibleState}"/>
</composite:implementation>

及其java对应

@FacesComponent(value = "helloWidget")
public class HelloWidget extends UINamingContainer implements Serializable {

    private static final long serialVersionUID = 2L;
    private boolean visible;

    public void show() {
        System.out.println("Setting visible state to true " + this);
        visible = true;
    }

    public void hide() {
        System.out.println("Setting visible state to false " + this);
        visible = false;
    }

    public String getVisibleState() {
        System.out.println("Getting visible state of " + this + "(" + visible + ")");
        return String.valueOf(visible);
    }
}

然后我升级了我的ViewBean.java

private HelloWidget helloWidget;
private boolean visible;

public String getVisibleState() {
    return String.valueOf(visible);
}

public void actionShow(ActionEvent ae) {

    visible = true;
    helloWidget.show();
}

public void actionHide(ActionEvent ae) {

    visible = false;
    helloWidget.hide();
}

public HelloWidget getHelloWidget() {
    return helloWidget;
}

public void setHelloWidget(HelloWidget helloWidget) {
    this.helloWidget = helloWidget;
}

和我的hello.xhtml:

<f:view>
    <h:form>
        <h:outputText value="View-scoped bean visible value: #{viewBean.visibleState}"/>
        <br/>
        <mycc:helloWidget binding="#{viewBean.helloWidget}"/>
        <br/>
        <h:commandButton value="Show" actionListener="#{viewBean.actionShow}"/>
        <h:commandButton value="Hide" actionListener="#{viewBean.actionHide}"/>
    </h:form>
</f:view>

当我现在点击show / hide按钮时,视图范围bean中“visible”属性的值会按预期更改。 HelloWidget属性的“可见”值也会更改,但是当显示页面时,会显示一个不同的HelloWidget实例,其可见设置为(默认)false。

我在这里做错了什么?我绑定复合组件的方式有问题吗?

1 个答案:

答案 0 :(得分:1)

在构建/恢复视图期间实例化组件。因此它们基本上是请求作用域。您希望在视图范围中保留的任何状态都需要存储在JSF视图状态中。通常的做法是让表示视图作用域状态的属性的getter / setter委托给UIComponent#getStateHelper()

所以,这应该做:

@FacesComponent(value = "helloWidget")
public class HelloWidget extends UINamingContainer implements Serializable {

    private static final long serialVersionUID = 2L;

    public void show() {
        setVisible(true);
    }

    public void hide() {
        setVisible(false);
    }

    public Boolean getVisible() {
        return (Boolean) getStateHelper().eval("visible");
    }

    public void setVisible(Boolean visible) {
        getStateHelper().put("visible", visible);
    }
}

然而,您有另一个与此问题无关的潜在问题:在视图范围的bean属性上使用binding会导致在每个请求期间重新创建视图范围bean本身。谨慎使用binding attribtue。这个问题与JSTL in JSF2 Facelets... makes sense?中已经解释过的理由相同。