在Web应用中如果遇到大数据集要处理时,分页显示往往是一个很好的解决方法。但是在JSF中没有直接实现分页显示的组件。但在Myfaces里的分页组件dataScroller如果直接显示的话,必须一次性的比所有要显示的记录都要检索出来,如果有10000条记录的话,一次性把这些记录全部检索出来的话,那么所消耗的内存是不敢想像的。所以我们应该做的是需要一页就检索一页。我最近在
http://wiki.apache.org/myfaces/WorkingWithLargeTables上页看到的一篇文章就实现了我所实现的功能。下面是我应用此方法所实现的一个分页显示:
首先得写一个用来包装一个页面数据的类:
package doorban.business;
import java.util.List;
public class DataPage {
private int datasetSize; //数据集的记录总数
private int startRow; //从哪一条记录开始取数据
private List data; //一个页面的记录集
public DataPage(int datasetSize, int startRow, List data) {
this.datasetSize = datasetSize;
this.startRow = startRow;
this.data = data;
}
/**
* Return the number of items in the full dataset.
*/
public int getDatasetSize() {
return datasetSize;
}
/**
* Return the offset within the full dataset of the first element in the
* list held by this object.
*/
public int getStartRow() {
return startRow;
}
/**
* Return the list of objects held by this object, which is a continuous
* subset of the full dataset.
*/
public List getData() {
return data;
}
}
第二个用户包装DataModel的类
package doorban.business;
import javax.faces.model.DataModel;
/**
* A special type of JSF DataModel to allow a datatable and datascroller to page
* through a large set of data without having to hold the entire set of data in
* memory at once.
* Any time a managed bean wants to avoid holding an entire dataset, the managed
* bean should declare an inner class which extends this class and implements
* the fetchData method. This method is called as needed when the table requires
* data that isn\'t available in the current data page held by this object.
* This does require the managed bean (and in general the business method that
* the managed bean uses) to provide the data wrapped in a DataPage object that
* provides info on the full size of the dataset.
*/
public abstract class PagedListDataModel extends DataModel {
int pageSize;
int rowIndex;
DataPage page;
/**
* Create a datamodel that pages through the data showing the specified
* number of rows on each page.
*/
public PagedListDataModel(int pageSize) {
super();
this.pageSize = pageSize;
this.rowIndex = -1;
this.page = null;
}
/**
* Not used in this class; data is fetched via a callback to the fetchData
* method rather than by explicitly assigning a list.
*/
public void setWrappedData(Object o) {
if (o instanceof DataPage) {
this.page = (DataPage) o;
} else {
throw new UnsupportedOperationException("setWrappedData");
}
}
public int getRowIndex() {
return rowIndex;
}
/**
* Specify what the "current row" within the dataset is. Note that the
* UIData component will repeatedly call this method followed by getRowData
* to obtain the objects to render in the table.
*/
public void setRowIndex(int index) {
rowIndex = index;
}
/**
* Return the total number of rows of data available (not just the number of
* rows in the current page!).
*/
public int getRowCount() {
return getPage().getDatasetSize();
}
/**
* Return a DataPage object; if one is not currently available then fetch
* one. Note that this doesn\'t ensure that the datapage returned includes
* the current rowIndex row; see getRowData.
*/
private DataPage getPage() {
if (page != null) {
return page;
}
int rowIndex = getRowIndex();
int startRow = rowIndex;
if (rowIndex == -1) {
// even when no row is selected, we still need a page
// object so that we know the amount of data available.
startRow = 0;
}
// invoke method on enclosing class
page = fetchPage(startRow, pageSize);
return page;
}
/**
* Return the object corresponding to the current rowIndex. If the DataPage
* object currently cached doesn\'t include that index then fetchPage is
* called to retrieve the appropriate page.
*/
public Object getRowData() {
if (rowIndex < 0) {
throw new IllegalArgumentException(
"Invalid rowIndex for PagedListDataModel; not within page");
}
// ensure page exists; if rowIndex is beyond dataset size, then
// we should still get back a DataPage object with the dataset size
// in it if (page == null)
{
page = fetchPage(rowIndex, pageSize);
}
int datasetSize = page.getDatasetSize();
int startRow = page.getStartRow();
int nRows = page.getData().size();
int endRow = startRow + nRows;
if (rowIndex >= datasetSize) {
throw new IllegalArgumentException("Invalid rowIndex");
}
if (rowIndex < startRow) {
page = fetchPage(rowIndex, pageSize);
startRow = page.getStartRow();
} else if (rowIndex >= endRow) {
page = fetchPage(rowIndex, pageSize);
startRow = page.getStartRow();
}
return page.getData().get(rowIndex - startRow);
}
public Object getWrappedData() {
return page.getData();
}
/**
* Return true if the rowIndex value is currently set to a value that
* matches some element in the dataset. Note that it may match a row that is
* not in the currently cached DataPage; if so then when getRowData is
* called the required DataPage will be fetched by calling fetchData.
*/
public boolean isRowAvailable() {
DataPage page = getPage();
if (page == null) {
return false;
}
int rowIndex = getRowIndex();
if (rowIndex < 0) {
return false;
} else if (rowIndex >= page.getDatasetSize()) {
return false;
} else {
return true;
}
}
/**
* 这个方法在每一个业务里里必须要被实现
* startRow 每页的第一条记录在数据集里的位置
* pageSize 每页的记录数
*/
public abstract DataPage fetchPage(int startRow, int pageSize);
}
接着就应该来写一个具体的业务类
package doorban.business;
import java.util.ArrayList;
import java.util.List;
import javax.faces.model.DataModel;
import doorban.dao.hb.TempCardActionHB;
public class TCB {
private DataModel dataModel = null;
private int dataSetSize;
// dataSetSize = actionHB.getTotal();
TempCardActionHB actionHB = new TempCardActionHB();
public DataModel getDataModel() {
if (dataModel == null) {
dataModel = new LocalDataModel(5);
}
return dataModel;
}
private class LocalDataModel extends PagedListDataModel {
public LocalDataModel(int pageSize) {
super(pageSize);
try {
dataSetSize = actionHB.getTotal();
} catch (Exception e) {
e.printStackTrace();
}
}
public DataPage fetchPage(int startRow, int pageSize) {
TempCardActionHB actionHB = new TempCardActionHB();
List list = new ArrayList();
try {
list = actionHB.getTempCards(startRow, pageSize);
} catch (Exception e) {
e.printStackTrace();
}
DataPage dataPage = null;
try {
dataPage = new DataPage(dataSetSize, startRow, list);
} catch (Exception e) {
e.printStackTrace();
}
return dataPage;
}
}
}