0

我的项目是使用 JBoss Seam 2.3、JSF 2.1 和 Richfaces 构建的。在使用richfaces aj4 调用重新渲染组件时,有些事情我并不完全理解。

当使用 a4j 执行某些操作并且 render 属性的值指向某个 h:panelGroup id 时,也会调用其他面板中的方法。

我准备了一些代码来演示这一点。

BeanA.java。模拟数据访问。

package test;

import java.util.Arrays;
import java.util.List;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;

@Scope(ScopeType.CONVERSATION)
@Name("beanA")
public class BeanA {

    @Logger
    private Log log;

    public List<Integer> list() {
        log.info("beanA.list()");
        // DB Query simulation
        Integer[] result = {1,2,3};
        return Arrays.asList(result);
    }

}

BeanB.java。简单的点击计数器。

package test;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;

@Scope(ScopeType.CONVERSATION)
@Name("beanB")
public class BeanB {

    @Logger
    private Log log;

    private int counter = 0;

    public void dumbAction() {
        // do nothing
        log.info("beanB.dumbAction()");
        counter++;
    }

    public int getCounter() {
        return counter;
    }

    public void setCounter(int counter) {
        this.counter = counter;
    }

}

测试.xhtml

<f:view xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:a="http://richfaces.org/a4j"
    xmlns:richext="http://java.sun.com/jsf/composite/richext"
    xmlns:s="http://jboss.org/schema/seam/taglib" contentType="text/html"
        xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:html>
    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>TEST</title>
    </h:head>
    <h:body>

        <h:panelGroup id="listPanel">
            <ul>
                <li>
                    <h:outputText value="a:repeat" />
                </li>
                <a:repeat value="#{beanA.list()}" var="i">
                    <li>
                        <h:outputText value="#{i}" />
                    </li>
                </a:repeat>
            </ul>
<!--            <ul> -->
<!--                <li> -->
<!--                    <h:outputText value="ui:repeat" /> -->
<!--                </li> -->
<!--                <ui:repeat value="#{beanA.list()}" var="i"> -->
<!--                    <li> -->
<!--                        <h:outputText value="#{i}" /> -->
<!--                    </li> -->
<!--                </ui:repeat> -->
<!--            </ul> -->
<!--            <ul> -->
<!--                <li> -->
<!--                    <h:outputText value="c:foreach" /> -->
<!--                </li> -->
<!--                <c:forEach items="#{beanA.list()}" var="i"> -->
<!--                    <li> -->
<!--                        <h:outputText value="#{i}" /> -->
<!--                    </li> -->
<!--                </c:forEach> -->
<!--            </ul> -->
        </h:panelGroup>

        <h:form>
            <a:commandLink value="Dumb action" action="#{beanB.dumbAction()}"
                execute="@this" render="timesDumbActionPanel" />
        </h:form>

        <h:panelGroup id="timesDumbActionPanel">
            <h:outputText value="#{beanB.counter}" />
        </h:panelGroup>
    </h:body>
    </h:html>
</f:view>

当我加载页面 /test.seam beanA.list() 被调用一次。当我单击“哑操作”链接时,将记录以下内容:

19:28:21,461 INFO  [test.BeanA] (http--0.0.0.0-80-1) beanA.list()
19:28:21,461 INFO  [test.BeanB] (http--0.0.0.0-80-1) beanB.dumbAction()
19:28:21,461 INFO  [test.BeanA] (http--0.0.0.0-80-1) beanA.list()

beanA.list() 被调用了两次,我不明白为什么。当使用 ui:repeat 而不是 a:repeat beanA.list() 被调用了 11 次。我也试图改变范围,但结果是一样的。

我期望的行为只是调用 beanB.dumbAction() 并重新渲染面板以刷新计数器。

我知道 getter 被多次调用,但这是否也适用于所有方法?

我为避免这种情况所做的只是为列表创建一个字段并修改getter以初始化它(如果不是)。像这样的东西:

@Name("beanA")
public class BeanA {

    @Logger
    private Log log;

    private List<Integer> list;

    public void initList() {
        log.info("beanA.list()");
        // DB Query simulation
        Integer[] result = { 1, 2, 3 };
        setList(Arrays.asList(result));
    }

    public List<Integer> getList() {
        if (list == null)
            initList();
        return list;
    }

    public void setList(List<Integer> list) {
        this.list = list;
    }

}

getter 仍然被调用,但不是 initList() ,这很好。这样我就可以避免不必要地执行查询。唯一的问题是数据何时更改。我需要再次手动调用 initList() 并且仅重新渲染它的面板是不够的。

也许我错过了 JSF 生命周期之类的东西,你能给我一些提示吗?谢谢!!

4

1 回答 1

0

我知道 getter 被多次调用,但这是否也适用于所有方法?

JSF 并不知道特定方法是 getter。如果您在需要数据的地方使用,例如@value,那么它就是一个吸气剂。

您看到对 getter 的多次调用的原因是,当 JSF/RichFaces 查找某个元素时,它必须遍历它之前的所有元素。在您的情况下,为了找到timesDumbActionPanel它,必须通过listPanel并检查a4j:repeat.

唯一的问题是数据何时更改。我需要再次手动调用 initList() 并且仅重新渲染它的面板是不够的。

您可以initList()从任何更改数据的方法调用。

于 2017-05-12T08:46:14.530 回答