我的项目是使用 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 生命周期之类的东西,你能给我一些提示吗?谢谢!!