Jsf PrimeFaces LazyDataModel在实时滚动后错误解析行?
我试图使用PrimeFaces5.3(结合JSF2.2)实现一个包含项的数据表,每个项都有一个用于执行服务器端操作的命令按钮列表。我使用primefaces LazyDataModel,因为我有巨大的数据集,无法在加载视图时加载所有项。但在实时滚动发生后,行的行为与预期不符 我设置了一个小项目来说明我的问题。(文章末尾的完整来源) 问题 当我按A0时,必须在控制台上打印“已执行A0”(依此类推) 对于第一个数据集,一切正常。以下是我按下前三个按钮时发生的情况:Jsf PrimeFaces LazyDataModel在实时滚动后错误解析行?,jsf,jsf-2,primefaces,datatable,el,Jsf,Jsf 2,Primefaces,Datatable,El,我试图使用PrimeFaces5.3(结合JSF2.2)实现一个包含项的数据表,每个项都有一个用于执行服务器端操作的命令按钮列表。我使用primefaces LazyDataModel,因为我有巨大的数据集,无法在加载视图时加载所有项。但在实时滚动发生后,行的行为与预期不符 我设置了一个小项目来说明我的问题。(文章末尾的完整来源) 问题 当我按A0时,必须在控制台上打印“已执行A0”(依此类推) 对于第一个数据集,一切正常。以下是我按下前三个按钮时发生的情况: Fetching startin
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键时,UIData#brodacast(FacesEvent)被一个包含字段rowIndex=1的事件调用。因此,它在这一点上工作正常
然后,我真的不明白会发生什么。但在过程结束时,目标方法在错误的实例上执行
源代码
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;
}
}
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);
}
}
公共类服务{
私有静态最终整数项\u计数=8;
public int getItemsCount(){
退货项目数量;
}
公共列表检索项(int startIndex、int pageSize){
列表结果=新的ArrayList(页面大小);
int endIndex=startIndex+pageSize;
如果(结束索引>项目计数){
endIndex=项目数量;
}
对于(int index=startIndex;index而言,问题在于LazyDataModel实现,该实现用于页面而非实时滚动,尤其是以下代码段:
if(rowIndex == -1 || pageSize == 0)
this.rowIndex = -1;
else
this.rowIndex = (rowIndex % pageSize);
我用自己的实现将LazyDataModel子类化以解决这个问题
LiveScrollLazyDataModel.java
public abstract class LiveScrollLazyModel<T> extends LazyDataModel<T> {
private int rowIndex;
@Override
public void setRowIndex(int rowIndex) {
int oldIndex = getRowIndex();
if (rowIndex == -1 || getPageSize() == 0){
super.setRowIndex(-1);
this.rowIndex = -1;
}else{
super.setRowIndex(rowIndex);
this.rowIndex = rowIndex;
}
if (getResults() == null) {
return;
}
DataModelListener[] listeners = getDataModelListeners();
if (listeners != null && oldIndex != this.rowIndex) {
Object rowData = null;
if (isRowAvailable()) {
rowData = getRowData();
}
DataModelEvent dataModelEvent = new DataModelEvent(this, rowIndex, rowData);
for (int i = 0; i < listeners.length; i++) {
listeners[i].rowSelected(dataModelEvent);
}
}
}
@Override
public T getRowData() {
return getResults().get(this.rowIndex);
}
@Override
public boolean isRowAvailable() {
if(getResults() == null) {
return false;
}
return rowIndex >= 0 && rowIndex < getResults().size();
}
/**
* The complete list of results
* @return
*/
public abstract List<T> getResults();
}
公共抽象类LiveScrollLazModel扩展了LazyDataModel{
私有索引;
@凌驾
公共void setRowIndex(int-rowIndex){
int oldIndex=getRowIndex();
如果(rowIndex=-1 | | getPageSize()==0){
super.setRowIndex(-1);
this.rowIndex=-1;
}否则{
super.setRowIndex(rowIndex);
this.rowIndex=rowIndex;
}
如果(getResults()==null){
返回;
}
DataModelListener[]监听器=getDataModelListeners();
if(侦听器!=null&&oldIndex!=this.rowIndex){
对象rowData=null;
如果(isRowAvailable()){
rowData=getRowData();
}
DataModelEvent DataModelEvent=新的DataModelEvent(this,rowIndex,rowData);
for(int i=0;i=0&&rowIndex
实现者需要实现getResults()方法,该方法提供完整的结果列表。如果看到xhtml调用viewScoped bean value=“#{dtScrollView.cars6}”,该bean值反过来声明ManagedProperty(“org.primefaces.showcase.service”)。CarService@da2d11")private CarService service;其中CarService声明为ManagedBean(name=“CarService”)应用程序范围。我温和地要求您执行类似的方法,而不是value=“#{datatableLazyModel}”。我的应用程序中的LazyDatamodels根本没有使用ManagedBean或scope进行注释。它们只是作为变量驻留在MB中,并在构造后进行初始化。感谢您的反馈。不幸的是,我的数据集很大,无法一次加载所有内容,这就是我使用LazyDataModel的原因。我编辑了这个问题以反映在。我既没有要求您立即加载所有内容,也没有要求您删除LazyDataModel。一个正确编写的加载方法将解决此问题。我认为我们使用的是两种不同的语言。希望其他人回答您。祝您好运。拜您所赐,您告诉我使用与value=“#{dtScrollView.cars6}”相同的方法。这里的值是一个列表,而不是LazyDataModel。我如何使用这种方法和惰性数据模型?我的意思是将cars6初始化为私有DatatableLazyModel cars6。在ViewScoped MB的PostConstruct中初始化cars6。在LazyDataModel的load方法中,沿查询行添加一些内容。setFirstResult(first);query.setMaxResults(pageSize);currentObjectList=query.getResultList();返回currentObjectList;祝你好运。
<?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>
<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>
if(rowIndex == -1 || pageSize == 0)
this.rowIndex = -1;
else
this.rowIndex = (rowIndex % pageSize);
public abstract class LiveScrollLazyModel<T> extends LazyDataModel<T> {
private int rowIndex;
@Override
public void setRowIndex(int rowIndex) {
int oldIndex = getRowIndex();
if (rowIndex == -1 || getPageSize() == 0){
super.setRowIndex(-1);
this.rowIndex = -1;
}else{
super.setRowIndex(rowIndex);
this.rowIndex = rowIndex;
}
if (getResults() == null) {
return;
}
DataModelListener[] listeners = getDataModelListeners();
if (listeners != null && oldIndex != this.rowIndex) {
Object rowData = null;
if (isRowAvailable()) {
rowData = getRowData();
}
DataModelEvent dataModelEvent = new DataModelEvent(this, rowIndex, rowData);
for (int i = 0; i < listeners.length; i++) {
listeners[i].rowSelected(dataModelEvent);
}
}
}
@Override
public T getRowData() {
return getResults().get(this.rowIndex);
}
@Override
public boolean isRowAvailable() {
if(getResults() == null) {
return false;
}
return rowIndex >= 0 && rowIndex < getResults().size();
}
/**
* The complete list of results
* @return
*/
public abstract List<T> getResults();
}