【发布时间】:2016-02-24 17:47:06
【问题描述】:
我正在尝试使用 PrimeFaces 5.3(带有 JSF 2.2)来实现一个包含项目的数据表,并且每个项目都有一个命令按钮列表来执行服务器端操作。我使用 primefaces LazyDataModel 因为我有巨大的数据集并且在视图加载时无法加载所有项目。但在进行实时滚动后,行的行为与预期不同。
我设置了一个小项目来说明我的问题。 (完整来源在文章末尾)
问题
当我按下 A0 时,必须在控制台上打印“Executed A0”(等等)。
第一个数据集一切正常。当我按下前三个按钮时会发生以下情况:
Fetching starting at 0 //expected result
Executed A0 //A0
Executed A1 //A1
Executed A2 //A2
但是当我滚动并加载其他 3 个项目时,前三行无法正常工作。
当我按顺序按下所有按钮时会发生以下情况:
Fetching starting at 3 //expected result
Executed A3 //A0
Executed A4 //A1
Executed A5 //A2
Executed A3 //A3
Executed A4 //A4
Executed A5 //A5
前三个按钮执行后三个按钮的操作:(
服务器端问题
这不是客户端问题,我已经监控了发送的请求。
当我按下 A0 时,请求包含以下 POST 参数:
j_idt8:resultsTable:0:j_idt12:0:j_idt13=j_idt8:resultsTable:0:j_idt12:0:j_idt13
javax.faces.source=j_idt8:resultsTable:0:j_idt12:0:j_idt13
当我按下 A3 时:
j_idt8:resultsTable:3:j_idt12:0:j_idt13=j_idt8:resultsTable:3:j_idt12:0:j_idt13
javax.faces.source=j_idt8:resultsTable:3:j_idt12:0:j_idt13
resultsTable 后面引用了正确的行:
调试模式
我也弄乱了调试模式。当我按下 A1 时,将使用包含字段 rowIndex=1 的事件调用 UIData#brodacast(FacesEvent)。所以此时它工作正常。
然后,我真的不明白会发生什么。但是在流程结束时,目标方法在错误的实例上执行...
源代码
Item.java
public class Item {
private int id;
private String name;
private List<ItemAction> actions;
public Item(int id, String name, List<ItemAction> actions) {
this.id = id;
this.name = name;
this.actions = actions;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public List<ItemAction> getActions() {
return actions;
}
}
ItemAction.java
public class ItemAction {
private String label;
public ItemAction(String label) {
this.label = label;
}
public void execute(){
System.out.println("Executed " + label);
}
public String getLabel() {
return label;
}
}
TheService.java
public class TheService {
private static final int ITEMS_COUNT = 8;
public int getItemsCount() {
return ITEMS_COUNT;
}
public List<Item> retrieveItems(int startIndex, int pageSize){
List<Item> result = new ArrayList<>(pageSize);
int endIndex = startIndex + pageSize;
if(endIndex > ITEMS_COUNT){
endIndex = ITEMS_COUNT;
}
for(int index=startIndex; index<endIndex; index++){
result.add(generateItem(index));
}
return result;
}
private Item generateItem(int id){
List<ItemAction> actions = new ArrayList<>(2);
actions.add(new ItemAction("A" + id));
actions.add(new ItemAction("B" + id));
return new Item(id, "Item " + id, actions);
}
}
DatatableLazyModel.java
@ManagedBean
@ViewScoped
public class DatatableLazyModel extends LazyDataModel<Item>{
private TheService service;
private List<Item> allResults;
public DatatableLazyModel() {
this.service = new TheService();
this.allResults = new ArrayList<>();
}
@Override
public int getRowCount() {
return service.getItemsCount();
}
@Override
public List<Item> load(int first, int pageSize, String sortField, SortOrder sortOrder,
Map<String, Object> filters) {
System.out.println("Fetching starting at " + first);
List<Item> pageResults = service.retrieveItems(first, pageSize);
allResults.addAll(pageResults);
return pageResults;
}
}
index.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui" template="template/ui.xhtml">
<ui:define name="body">
<h3>Datatablelazy load</h3>
<h:form>
<p:dataTable id="resultsTable" var="item"
value="#{datatableLazyModel}" liveScroll="true" scrollRows="3"
scrollHeight="100" scrollable="true" lazy="true">
<p:column headerText="Name">
<h:outputText value="#{item.name}" />
</p:column>
<p:column headerText="Actions">
<ui:repeat var="action" value="#{item.actions}">
<p:commandButton action="#{action.execute()}" value="#{action.label}">
</p:commandButton>
</ui:repeat>
</p:column>
</p:dataTable>
</h:form>
</ui:define>
</ui:composition>
pom.xml 依赖项
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>5.3</version>
</dependency>
问题
我已经尝试过加载更多项目。每次只执行最后加载的集合上的方法。即使是旧组件。
所以基本上,问题是:“我怎样才能使所有按钮按预期工作?”
为什么方法没有在正确的实例上执行?目标实例如何解析?
感谢您的帮助:)
【问题讨论】:
-
如果你看到primefaces.org/showcase/ui/data/datatable/scroll.xhtml,xhtml 调用 viewScoped bean value="#{dtScrollView.cars6}" 依次声明 ManagedProperty("org.primefaces.showcase.service.CarService@da2d11")私家车服务;其中 CarService 被声明为 ManagedBean(name = "carService") ApplicationScoped。我轻轻地请你做一个类似的方法,而不是 value="#{datatableLazyModel}"。我的应用程序中的 LazyDatamodels 根本没有使用 ManagedBean 或范围进行注释。它们只是作为变量驻留在 MB 中,并在 PostConstruct 上初始化。
-
感谢您的反馈。不幸的是,我的数据集很大,我无法一次加载所有内容,这就是我使用 LazyDataModel 的原因。我已经编辑了问题以反映这一点。
-
我既没有要求您一次加载所有内容,也没有要求您删除 LazyDataModel。正确编写的加载方法将处理它。我认为我们正在谈论两种不同的语言。希望别人回答你。祝你好运。再见
-
你告诉我做与 value="#{dtScrollView.cars6}" 相同的方法。这里的值是 List 而不是 LazyDataModel。如何使用这种方法和惰性数据模型?
-
我的意思是 cars6 被初始化为私有 DatatableLazyModel
- cars6。在 ViewScoped MB 的 PostConstruct 中初始化 car6。在您的 LazyDataModel 的 load 方法中添加一些类似于 query.setFirstResult(first);query.setMaxResults(pageSize); 的内容currentObjectList = query.getResultList();返回当前对象列表;祝你好运。
标签: jsf jsf-2 primefaces datatable el