2

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

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

我的初始设置与从视图范围的 bean 自动实例化会话范围的 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>

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

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

4

1 回答 1

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);
    }
}

You've however another potential problem not related to this issue: using binding on a view scoped bean property causes the view scoped bean itself to be recreated during every request. Use the binding attribtue with extreme care. This problem has the same grounds as already explained in JSTL in JSF2 Facelets... makes sense?.

于 2013-03-21T16:46:44.360 回答