JSTL/核心标签的使用将ViewScoped Bean搞砸了 [英] Use of JSTL/core tags screws up ViewScoped Bean

查看:81
本文介绍了JSTL/核心标签的使用将ViewScoped Bean搞砸了的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为我在Mojarra 2.1.0中遇到了一个错误.也许我错过了一些东西,但是如果我看得到就该死.

I think I have run into a bug in Mojarra 2.1.0. Maybe I missed something but damned if I can see it.

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

I rely a lot of @ViewScoped beans to save state whilst the browser does a lot of AJAX to the server. I find when I use certain tags, the @ViewScoped bean starts getting re-instantiated when it shouldn't be. Here is my test case backing 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页面:

And here is the JSF Facelets page that uses it:

<!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()调用看到这一点.

So here is what goes wrong. When you click on the "Do Me" command button, a new instance of the backing bean gets created each time, just as if it were a @RequestScoped bean. I can see this via the log() call in the constructor.

如果将bean更改为@SessionScoped,则不会发生.无论单击按钮多少次,都可以获得一个Bean实例.

If you change the bean to @SessionScoped, this doesn't happen. You get one instance of the bean no matter how many times the button is clicked.

但是-如果将其保留为@ViewScoped,并取出 c:foreach 元素及其内容,则现在不再是每次单击都重新实例化Bean.换句话说,它现在可以按预期工作.

HOWEVER -- if you leave it as @ViewScoped, and you take out the c:foreach element and its content, it now no longer re-instantiates the bean each click. In other words it now works as expected.

这是mojarra的错误,还是我在这里做错了什么?

Is this a mojarra bug or am I doing something wrong here?

推荐答案

这是一个已知的错误":

This is a known "bug": issue 1665. It's a chicken-egg issue with regard to partial state saving.

但是,您也可以只使用<ui:repeat>.

In your case, however, you could also just use <ui:repeat>.

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

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

Your best bet is to try to avoid JSTL tags when using @ViewScoped. The only alternative is to disable partial state saving by a context param in web.xml:

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

但是它使视图更多地占用了内存.

But it makes the views more memory hogging.

这篇关于JSTL/核心标签的使用将ViewScoped Bean搞砸了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆