1

@ViewScoped在为页面上的不同表单多次创建 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:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html">
<h:head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</h:head>
<h:body>
    <h:form id="f1">
        <h:commandButton value="action 1" action="#{testController.action}">
            <f:ajax />
        </h:commandButton>
    </h:form>
    <h:form id="f2">
        <h:commandButton value="action 2" action="#{testController.action}">
            <f:ajax />
        </h:commandButton>
    </h:form>
</h:body>
</html>

和一个支持bean:

@ManagedBean
@ViewScoped
public class TestController implements Serializable {
    private static final long serialVersionUID = 1L;

    public TestController() {
        System.out.println("TestController created");
    }

    public String action() {
        System.out.println("action() invoked");
        return null;
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        System.out.println("serialization");
        out.defaultWriteObject();
    }

    private void readObject(ObjectInputStream in) throws IOException,
            ClassNotFoundException {
        System.out.println("deserialization");
        in.defaultReadObject();
    }
}

这是 web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>WebTest</display-name>
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
    <context-param>
        <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
        <param-value>1</param-value>
    </context-param>
    <context-param>
        <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
        <param-value>resources.application</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>

    <listener>
        <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>
</web-app>

当我单击action 1按钮时,会创建一个新TestControllerbean,然后使用writeObject方法进行序列化。然后,当我单击action 2按钮时,我希望它会被反序列化,但相反,会创建一个新的 bean,这两个 bean 分别为每个<h:commandButton>.

我用 Mojarra 和 Myfaces 都遇到了这个问题,所以我想这不是库中的错误。

也许我犯了一些愚蠢的错误或错过了什么,但@ViewScoped无论页面上的数量如何,bean 不应该是当前视图的唯一 bean<h:form>吗?

更新:我发现删除<f:ajax>标签时问题消失了;不幸的是,这不是我的选择。

更新2:我想我找到了问题的原因:使用多个表单时,只有请求表单ViewState会自动更新。在我的示例中,如果我使用第一个表单发送请求,则第二个表单的视图状态不会更新,除非我render=":f2"<f:ajax>第一个表单中添加。并且由于@ViewScopedbean 存储在视图状态中,第二个表单的视图状态将不包含该 bean,因此在从第二个表单发送请求时将创建一个新的 bean。因此,如果我的推理是正确的,我必须使用render属性手动更新视图中的所有表单,以保持跨表单的视图状态相同。但这似乎不方便,特别是如果页面上有很多表格。没有其他解决方案吗?

4

1 回答 1

0

到目前为止发布的代码并没有这样做。至少,在默认的 JSF 游乐场项目中对我来说不是。

然而,当您将视图范围的 bean 属性绑定到标记处理程序的任何属性(如 JSTL <c:forEach>、Facelets <ui:include>、JSF <f:attribute>)或JSF UI 组件的id或属性时,这些症状是可以识别的。binding

标签处理程序属性和 UI 组件的属性中的任何 EL 表达式都会idbinding构建和恢复视图期间执行。在回发期间恢复视图时,视图范围的 bean 仅恢复视图后可用(因为它们存储在其中)。因此,在视图恢复时它们不可用,这就解释了为什么每次都构建它们。

也可以看看:

于 2012-10-16T11:00:03.973 回答