我偶然发现了 JSF / PrimeFaces 问题,虽然我设法通过更改支持bean的范围来实现它,但我仍然想了解它失败的原因在第一种情况下。所以,这是一个缩小的例子,它重现了行为:
我们有一个简单的 xhtml 页面,它在表单中显示两个 p:dataTables ,一个在另一个下面。顶部 p:dataTable 显示数字,第二个显示除数。所以我们有一个经典的主 - 细节视图。一个按钮允许我们更新页面,所以当从顶部表格中选择一个新的数字时,我们可以在底部表格中查看它的除数:
<h:form id="NUMBERS-form">
<p:dataTable id="dt1" var="item" value="#{numbersController.divisorSets}"
rowKey="#{item}" rows="10" selection="#{numbersController.selectedDivisorSet}"
selectionMode="single">
<p:column>
#{item}
</p:column>
</p:dataTable>
<p:dataTable id="dt2" var="item" value="#{numbersController.divisors}"
rowKey="#{item}" rows="10" selection="#{numbersController.selectedDivisor}"
selectionMode="single">
<p:column id>
#{item}
</p:column>
</p:dataTable>
<p:commandButton id="Update" ajax="true" update=":NUMBERS-form"
action="#{numbersController.foo}" value="update"/>
</h:form>
支持bean定义了两个只读集合:一个用于 DivisorSets (即我们想要查找其除数的数字),另一个用于当前所选数字的除数。它还有两个字段和属性getter / setter,用于当前选定的数字和当前选定的该数字的除数:
@ManagedBean
@ViewScoped // if this is toggled to @RequestScoped it stops working
public class NumbersController implements Serializable {
private static final Logger l = Logger.getLogger(NumbersController.class.getName());
public List<DivisorSet> getDivisorSets() {
List<DivisorSet> retValue = new ArrayList<DivisorSet>();
for (int i = 10 ; i < 20 ; i++)
retValue.add( new DivisorSet(i) );
return retValue;
}
public List<Integer> getDivisors() {
if (selectedDivisorSet != null)
return selectedDivisorSet.getDivisors();
else return null;
}
private DivisorSet selectedDivisorSet;
// getter and setter ...
private Integer selectedDivisor;
// getter and setter ...
public String foo() { return null; }
}
首次加载页面时,只会填充顶部的 p:dataTable 。选择顶部表格的一行并按下 p:commandButton 时,会在底部的 p:dataTable 中获取该数字的除数。到现在为止还挺好。问题出现了:当从顶部表中选择一行并且从底部表中选择一行并按下 p:commandButton 时,我在setter中的日志消息显示:
请注意,在这个简单的示例中没有业务逻辑,因此必须从底部选择一个数字 p:dataTable - 这只是我遇到的同样问题的缩小版本在真实的背景下。任何人都可以解释JSF生命周期中导致底层表选择值未在视图 RequestScoped (而不是 ViewScoped 成功)的情况下正确设置的步骤吗?