JSF Datatable 大資料集分頁(簡單,已在項目中使用)

來源:互聯網
上載者:User

使用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

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.