【问题标题】:Use of JSTL/core tags screws up ViewScoped Bean使用 JSTL/core 标签搞砸了 ViewScoped Bean
【发布时间】:2011-08-27 16:47:19
【问题描述】:

我想我在 Mojarra 2.1.0 中遇到了一个错误。也许我错过了什么,但如果我能看到它该死的。

我依靠很多 @ViewScoped bean 来保存状态,而浏览器对服务器执行大量 AJAX。我发现当我使用某些标签时,@ViewScoped bean 在不应该被重新实例化时开始重新实例化。这是我的测试用例支持 bean:

/*
 * TestStuff.java
 */
package test;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;

/**
 * Backing bean for test.xhtml -- working out AJAX/SVG connection
 *
 */

@ManagedBean 
@ViewScoped
public class TestStuff implements Serializable {

private int counter = 0;

public TestStuff() {
    log("TestStuff(): {0}", this);
}

public String getRandomNumber() { 
    int i = (int) (Math.random() * 1000000.0);
    return String.format("%d", i);
}

public int getCounter() { return counter; }

public List<String> getStuff() {
    return Arrays.asList("big", "bad", "wolf");
}

public void pushButton(ActionEvent evt) {
    log("TestStuff.pushButton({0}): {1}", 
            new Object[] { evt, ++counter });
}

}

这里是使用它的 JSF Facelets 页面:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:p="http://primefaces.prime.com.tr/ui"
  xmlns:ui="http://java.sun.com/jsf/facelets"  
  xmlns:f="http://java.sun.com/jsf/core" 
  xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
    <title>Test Page</title>
</h:head>
<h:body>
    <h1>Test Page</h1>
    <p>If you are reading this text, the server
        is not properly configured.</p>
    <ui:composition id="compRoot" template="/template5.xhtml">

        <ui:define name="content">
            <h1>Test</h1>
            <h:form id="formTest">

                <p:commandButton value="Do Me" 
                                 actionListener="#{testStuff.pushButton}"
                                 update="testUpdate" />

                <p:panel id="testUpdate" >
                    <h:outputText value="Random output is: " />
                    <h:outputText
                        value="#{testStuff.randomNumber}"
                        />
                    <h:outputText value=" Counter is: "/>
                    <h:outputText 
                        value="#{testStuff.counter}"
                        />
                </p:panel>

                <h:panelGrid columns="5" border="1" >
                    <c:forEach items="#{testStuff.stuff}" var="x">
                        <h:outputText value="#{x}" />
                    </c:forEach>
                </h:panelGrid>                  

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

所以这就是问题所在。当您单击“Do Me”命令按钮时,每次都会创建一个新的支持 bean 实例,就像它是一个 @RequestScoped bean 一样。我可以通过构造函数中的 log() 调用看到这一点。

如果您将 bean 更改为 @SessionScoped,则不会发生这种情况。无论按钮被点击多少次,您都会得到一个 bean 实例。

但是——如果您将其保留为@ViewScoped,并取出 c:foreach 元素及其内容,它现在不再在每次单击时重新实例化 bean。换句话说,它现在按预期工作。

这是一个 mojarra 错误还是我在这里做错了什么?

【问题讨论】:

    标签: jsf jsf-2 jstl mojarra


    【解决方案1】:

    这是一个已知的“错误”:issue 1665。关于部分状态保存,这是一个鸡蛋问题。

    但是,在您的情况下,您也可以只使用 &lt;ui:repeat&gt;

    <ui:repeat value="#{testStuff.stuff}" var="x">
        <h:outputText value="#{x}" />
    </ui:repeat>
    

    最好的办法是在使用@ViewScoped 时尽量避免使用JSTL 标签。唯一的选择是通过web.xml 中的上下文参数禁用部分状态保存:

    <context-param>
        <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
        <param-value>false</param-value>
    </context-param>
    

    但这会让视图更占用内存。

    【讨论】:

    • 我从 ui:repeat 开始,但问题是它将整个集合视为单个组件。换句话说,如果它在 h:panelGrid 内,您将获得一个包含一个单元格的表格。谢谢,虽然我认为我可以解决这个问题,但它确实让我发疯了,很高兴知道这是一个真正的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    相关资源
    最近更新 更多