您的位置:首页 > 大数据

JSF Datatable 大数据集分页

2008-07-30 05:00 302 查看


译文[未完成]:

使用datatable时,通常的做法是取出所有的数据,把数据绑定到datatable,然后让组件来完成分页动作,一般来说,当数据集较小时这样可以,但是,如果数据集有数百行,数千行,甚至更大量的的数据行会如何呢,这样很有可能引起内存问题,所以不是一个好的实现.之前在我们的项目中发生过这种最糟糕的事情.好消息是经过努力.在javax.faces.DataModel 上找到了解决方案.

实际上,扩展自uidata的组件 ,例如 DataTable,通过一个适配类和它的数据交互.DataModel. This class wraps the actual collection for example, if a list is bound to a datatable then a ListDataModel is created and the component use this ListDataModel to access it’s data. DataModel provides methods like getWrappedData, isRowAvailable, getRowData, getRowCount letting the component access the wrapped data the way datamodel determines. To give an example, In case the wrapped data is a list, getRowCount returns list.size().

The solution to the large data problem is to use a custom data model and show only the data page allowed by the page size of the datatable. Whenever a paging occurs, the data of the next page is fetched and displayed, by this way the whole data is never read, the idea is to load only the page size of data when needed. There are two key attributes of a datatable, “first” and “rows”, first refers to the starting element and rows refers to the page size to be displayed. So when the first is 10 and rows is 5, then data between 10 and 15 is displayed. A pager simply sets the first attribute and the rows elements of the datatable, and then datatable displays it’s data considering these attributes. Also when the pages defines the number of pages, it looks at the datatable’s getRowCount method. Following is the PagedDataModel class providing the solution based on these informations.

package forca.barca;

import java.util.List;
import javax.faces.model.DataModel;

public class PagedListDataModel extends DataModel{

private int rowIndex = -1;

private int totalNumRows;

private int pageSize;

private List list;

public PagedListDataModel() {
super();
}

public PagedListDataModel(List list, int totalNumRows, int pageSize) {
super();
setWrappedData(list);
this.totalNumRows = totalNumRows;
this.pageSize = pageSize;
}

public boolean isRowAvailable() {
if(list == null)
return false;

int rowIndex = getRowIndex();
if(rowIndex >=0 && rowIndex < list.size())
return true;
else
return false;
}

public int getRowCount() {
return totalNumRows;
}

public Object getRowData() {
if(list == null)
return null;
else if(!isRowAvailable())
throw new IllegalArgumentException();
else {
int dataIndex = getRowIndex();
return list.get(dataIndex);
}
}

public int getRowIndex() {
return (rowIndex % pageSize);
}

public void setRowIndex(int rowIndex) {
this.rowIndex = rowIndex;
}

public Object getWrappedData() {
return list;
}

public void setWrappedData(Object list) {
this.list = (List) list;
}

}
The key point is to fool the pager by returning the total list size as the row count. Pager components use this value when rendering themselves, for example a simple pager divides this number to the page size and use the result to render the page numbers. Other important thing is always return the mod(rowIndex) as the rowIndex. Let’s say we have a datatable with page sizes:10. The rendering algorithm of a datatable initially gets the first element and sets it as the rowIndex and then renders the data until the rowIndex <= pagesize. When the user wants to see the next page, since pager sets the first attribute of the datatable as 10, the rowIndex is initially set to 10. Problem occurs here, since we use custom paging and load only 10 blocks of data (0-9), the 10th element is null and isRowAvailable returns false. In order to hack it, whenever the rowIndex is needed, the (rowIndex mod(page)) is returned. This means when the 10th element is needed 10 mod(10) = 0 is returned. Similarly referring to 15th element returns 5th element in the list.

In order to the custom paging at the view layer, we need features to do the same thing at business layer. I’m going to present a way with Hibernate Criteria API, also Query API should do the job. If you are not using spring and hibernate there are other options to fetch paged data like oracle’s rownum. Anyway the method below is located at an Hibernate DAO class and accessed via Spring beans. Also there is another one to return only the size of the actual data.

public List getPagedData(SomeCriteriaObject someObject, int start, int page) {
try {
Criteria criteria = getSession().createCriteria(ClassToBeQueried.class);
//Build Criteria object here
criteria.setFirstResult(start);
criteria.setMaxResults(page);
return criteria.list();
} catch (HibernateException hibernateException) {
//do something here with the exception
}
}
public int getDataCount(SomeCriteriaObject someObject) {
Criteria criteria = getSession().createCriteria(ClassToBeQueried.class);
criteria.setProjection(Projections.rowCount());

// Build Criteria object here
Number nuofRecords = ((Number) criteria.uniqueResult());
return nuofRecords == null ? 0 : nuofRecords.intValue();
}
Since all the stuff is ready to do custom paging, how to enable it? The first thing is to bind the custom data model to the datatable component as the value.

<h:datatable id=”table1″ value=”#{didYouSeeZidanesHeaderToMaterazzi.myPagedDataModel}“>



</h:datatable>

Finally the last job is to create a PagedDataModel and return it in the getter as;

public DataModel getMyPagedDataModel() {
int totalListSize = getSomeBusinessService().getDataCount(getSomeCriteriaObject());
List pagedList = getSomeBusinessService().getPagedData(getSomeCriteriaObject(), getTable1().getFirst(), getTable1().getRows());
PagedDataModel dataModel = new PagedDataModel(pagedList, tatalListSize, getTable1().getRows());
return dataModel;
}
The SomeBusinessService is not important and just a business bean providing access to the hibernate daos, also the somecriteriaobject is a simple bean whose members are bound to the page components used when building the criteria object. As I mentioned these are the stuff I’ve used to do custom paging at business level, you can replace it with your own stuff. The important idea is to use a custom data model to enable custom paging at view layer

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: