Seam 2.3 + JSF + AJAX。当重新渲染一个面板时,其他面板中的方法也会被调用
Seam 2.3 + JSF + AJAX. When re-rendering one panel methods in other panel get called too
我的项目是使用 JBoss Seam 2.3、JSF 2.1 和 richfaces 构建的。在使用 richfaces aj4 调用重新渲染组件时,有些事情我不完全理解。
当使用 a4j 执行某些操作并且渲染属性的值指向某些 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;
}
}
test.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() 被调用一次。当我单击 "Dumb action" link 时,会记录以下内容:
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 生命周期之类的东西,你能给我一些提示吗?谢谢!!
I do know getters are called multiple times, but does this apply to all methods too?
它不像 JSF 知道特定方法是 getter。如果您在需要数据的地方使用,例如@value 那么它是一个 getter.
您看到多次调用 getters 的原因是当 JSF/RichFaces 正在寻找某个元素时,它必须遍历它之前的所有元素。在你的情况下,为了找到 timesDumbActionPanel
它必须经过 listPanel
并检查 a4j:repeat
.
The only problem is when data changes. I need to manually call initList() again and it's not enough with just re-rendering it's panel.
您可以从任何正在更改数据的方法中调用 initList()
。
我的项目是使用 JBoss Seam 2.3、JSF 2.1 和 richfaces 构建的。在使用 richfaces aj4 调用重新渲染组件时,有些事情我不完全理解。
当使用 a4j 执行某些操作并且渲染属性的值指向某些 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;
}
}
test.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() 被调用一次。当我单击 "Dumb action" link 时,会记录以下内容:
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 生命周期之类的东西,你能给我一些提示吗?谢谢!!
I do know getters are called multiple times, but does this apply to all methods too?
它不像 JSF 知道特定方法是 getter。如果您在需要数据的地方使用,例如@value 那么它是一个 getter.
您看到多次调用 getters 的原因是当 JSF/RichFaces 正在寻找某个元素时,它必须遍历它之前的所有元素。在你的情况下,为了找到 timesDumbActionPanel
它必须经过 listPanel
并检查 a4j:repeat
.
The only problem is when data changes. I need to manually call initList() again and it's not enough with just re-rendering it's panel.
您可以从任何正在更改数据的方法中调用 initList()
。