`

Handle Big Dataset with Real Pagination with Primefaces 3.3 LazyDataModel

 
阅读更多

If you have millions of records in your database, you would like to use real pagination to provide viewing of the data. By "real" (or true or proper, whatever) pagination, it means that the searching function only fetches a few records for viewing on the current page, and the count of the total records that matche the searching criteria.

 

Primefaces 3.3 has built-in support for this real pagination. To use this mechanisam, the application needs to implement "org.primefaces.model.LazyDataModel " that wraps the data loading and paging etc required for the pagination.

 

Since the backing bean does not cache anything, it could be session scoped safely. As a matter of fact, it would not be working if request scoped. @ViewScoped? don't know.

 

To enable sorting as well, the application needs to provide a java.util.Comparator and use java.util.Collections to sort the loaded list.

 

Let's first take a look at the front end jsf page "/student/studentSearch.xhtml":

 

<ui:composition xmlns="http://www.w3.org/1999/xhtml"  
                    xmlns:h="http://java.sun.com/jsf/html"  
                    xmlns:f="http://java.sun.com/jsf/core"  
                    xmlns:ui="http://java.sun.com/jsf/facelets"  
                    xmlns:p="http://primefaces.org/ui"  
                    template="/template/template1.xhtml">  
      
<ui:define name="title">#{msgs.studentSearch}</ui:define>  
          
<ui:define name="content">  
<h:form id="searchForm">  
	<p:panel header="#{msgs.studentSearch}">  
		<h:panelGrid columns="3">  
		<h:outputLabel value="#{msgs.name}: "/>  
		<h:inputText value="#{ssp.nameFilter}"></h:inputText>  
		<h:commandButton type="submit" value="#{msgs.search}" 
									  action="#{ssp.findByName}"/>  
		</h:panelGrid>  
	</p:panel>  
</h:form>  

<p:panel header="#{msgs.studentList}">  
	<h:form id="dataListForm">  
	<!-- search result list -->  
	<p:dataTable id="idStuDataTable" 
			var="st" value="#{ssp.lazyModel}" lazy="true"  
			paginator="true" rows="5" rowsPerPageTemplate="5,10,20"
			paginatorPosition="bottom"
			paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink}
						{PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}">
							
			<f:facet name="header">
				#{msgs.studentFound}: #{ssp.lazyModel.rowCount}
			</f:facet>

			<p:column headerText="#{msgs.name}" sortBy="#{st.name}">
				<h:outputText value="#{st.name}" />
			</p:column>

			<p:column headerText="#{msgs.mobile}" sortBy="#{st.mobile}">
				<h:outputText value="#{st.mobile}"/>
			</p:column>

			......

	</p:dataTable>
	</h:form>
</p:panel>
      
......   

 

U can see the primefaces data table now gets data from variable "lazyModel" in the backing bean.

 

Here's the source code of the backing bean:

package com.jxee.action.student;

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;

import org.apache.log4j.Logger;
import org.primefaces.model.LazyDataModel;

import com.jxee.action.ActionBase;
import com.jxee.action.pagination.PmfLazyDataModel;
import com.jxee.ejb.student.StudentDAO;
import com.jxee.model.student.Student;

/**
 * <li>
 * this search bean implements so called "real/true" pagination, 
 * in that it would calculate the total number of records based on the query but
 * only retrieve the necessary records for the page to display.
 * </li>
 * <li>
 * this virtually means that any clicking on sorting and a page number, would result
 * in a query issued to the database to retrieve data.
 * </li>
 * <li>
 * good thing is that you don't need to cache any data
 * </li>
 * <li>
 * it would use Primefaces support for pagination
 * </li>  
 */
@ManagedBean(name="ssp")
@SessionScoped
public class StudentSearchPagination extends ActionBase {

  private static final Logger log = Logger.getLogger(StudentSearchPagination.class);
  private static final String SEARCH_PAGE = "/student/studentSearch.xhtml";
  
  private LazyDataModel<Student> lazyModel;
  private @EJB StudentDAO stDao;

  private String nameFilter;
  
    
  public String findByName() {
    log.debug("Search student by nameFilter: " + nameFilter);
    this.lazyModel = new StudentLazyDataModel(this.stDao, this.nameFilter);
    return SEARCH_PAGE;
  }
  
  public String getNameFilter() {
    return nameFilter;
  }

  public void setNameFilter(String afilter) {
    this.nameFilter = afilter;
  }

  public LazyDataModel<Student> getLazyModel() {
    return lazyModel;
  }

  public void setLazyModel(LazyDataModel<Student> lazyModel) {
    this.lazyModel = lazyModel;
  }

}

  

It becomes simpler compared to previous implementations, since the data retrieving and etc is now handled in the Primefaces LazyDataModel. We need to implement it and here it is:

 

package com.jxee.action.pagination;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;

import com.jxee.ejb.student.StudentDAO;
import com.jxee.model.student.Student;


public class StudentLazyDataModel extends LazyDataModel<Student> {
  
  private static final Logger log = Logger.getLogger(StudentLazyDataModel.class);
  
  private List<Student> data;
  private StudentDAO dao;
  private String filter;
  
  public StudentLazyDataModel(StudentDAO dao, String filter) {
    this.dao = dao;
    this.filter = filter;
    log.debug("lazy data model inited");
  }
    
  @Override
  public List<Student> load(int startAt, int maxPerPage, String sortField, SortOrder sortOrder, Map<String,String> filters) {
    
    log.debug("Lazy data model loading data...");
    
    try {
      log.debug(String.format("Searching for filter: %s, startAt=%s, maxPerPage=%s", filter, startAt, maxPerPage));
      data = this.dao.findStudent(filter, startAt, maxPerPage);
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    
    // if sorting
    if(sortField != null) {
      log.debug(">>> sortField: " + sortField);
      log.debug(">>> sortOrder: " + sortOrder.toString());
      Collections.sort(data, new StudentLazySorter(sortField, sortOrder));  
    }  
    
    // set the total number of students that have been found
    if(super.getRowCount() <= 0){
      Long total = dao.getFindTotal(filter);
      this.setRowCount(total.intValue());
    }
    
    // set the page size
    this.setPageSize(maxPerPage);
    
    log.debug("Total record match searching criteria: " + getRowCount());
    
    return data;
  }
}

 

 

Here's our sorting comparator, it uses java reflection api to get the values of the sorting fields for comparison:

 

 

package com.jxee.action.pagination;

import java.lang.reflect.Field;
import java.util.Comparator;

import org.apache.log4j.Logger;
import org.primefaces.model.SortOrder;

import com.jxee.model.student.Student;


public class StudentLazySorter implements Comparator<Student> {

  private static final Logger log = Logger.getLogger(LazySorter.class);
  
  private String sortField;
  private SortOrder sortOrder;
  
  
  public LazySorter(String sortField, SortOrder sortOrder) {
    this.sortField = sortField;
    this.sortOrder = sortOrder;
  }

  public int compare(Student t1, Student t2) {
    try {
      Field f = Student.class.getDeclaredField(this.sortField);
      f.setAccessible(true);
      
      log.debug(">>> compare field: " + f.getName());

      Object value1 = f.get(t1);
      Object value2 = f.get(t2);

      int cmp = ((Comparable)value1).compareTo(value2);
      
      return SortOrder.ASCENDING.equals(sortOrder) ? cmp : -1 * cmp;
    }
    catch(Exception e) {
      throw new RuntimeException(e);
    }
  }
}

 

Here's the two methods form the StudentDAO:

 

public List<Student> findStudent(String nameFilter, int start, int max) {
    String filter = nameFilter != null ? "%" + nameFilter + "%" : "%";
    String sql = "select s from Student s where s.name like :pattern order by s.name";
    Query q = em.createQuery(sql);
    q.setParameter("pattern", filter);
    q.setFirstResult(start);  // set start index to retrieve (the page number)
    q.setMaxResults(max);  // set amount of records to retrieve (rows per page)
    return q.getResultList();
}
  
public Long getFindTotal(String nameFilter) {
    String filter = nameFilter != null ? "%" + nameFilter + "%" : "%";
    String sql = "select count(s) from Student s where s.name like :pattern";
    Query q = em.createQuery(sql);
    q.setParameter("pattern", filter);
    return (Long)q.getSingleResult();
}

 

OK, Let take a look at the screen shot:

 


 

Drawbacks:

every click on the page number, or sorting column header, would results a database query executed. it shifts the durden from your application and the application server to database.  but it only retrieves a controlled number of records, say 5/10/20, so it's not a big deal for the database.

 

Further dev:

you can generalize the implementation by java generics.

 

  • 大小: 60.6 KB
分享到:
评论

相关推荐

    iam handwrting dataset with word level label

    iam handwrting dataset with word level label

    Frank Kane's Taming Big Data with Apache Spark and Python

    这本书《Taming Big Data with Apache Spark and Python》由Frank Kane所著,主要讲解了如何使用Apache Spark和Python来分析大规模数据集,并提供了真实的案例帮助读者理解和实践。Apache Spark是一个开源的分布式...

    matlab泊松过程代码-denoising-fluorescence:CVPR2019:荧光显微镜去噪(FMD)数据集

    Dataset with Real Fluorescence Microscopy Images}, author={Yide Zhang and Yinhao Zhu and Evan Nichols and Qingfei Wang and Siyuan Zhang and Cody Smith and Scott Howard}, booktitle={CVPR}, year={2019} ...

    口罩遮挡人脸数据集(Real-World Masked Face Dataset,RMFD)

    真实口罩人脸识别数据集:从网络爬取样本,经过整理、清洗和标注后,含525人的5千张口罩人脸、9万正常人脸。

    USA Real Estate Dataset Updated

    USA Real Estate Dataset Updated This dataset contains Real Estate listings in the US broken by State and zip code. Data was collected via web scraping using python libraries. kaggle data-science-bowl-...

    Big+Data+Analytics+with+Java-Packt+Publishing(2017).pdf

    But with the rise of big data, these technologies have gone mainstream now. So, using these technologies, you can now predict which advertisement the user is going to click on next, or which product ...

    NFPA_dataset.zip

    NFPA_dataset.zip是一个包含280张图片的数据集,专门用于识别NFPA(美国国家消防协会)相关的图像和进行物体检测。NFPA标准涉及消防安全,其图像可能包含各种与消防设备、标志或火源相关的内容。这个数据集的独特之...

    Machine Learning Projects with TensorFlow 2.0:Supercharge your Machine Learning

    33 Picking a Base Model Suitable for Transfer Learning with Our Dataset 34 Implementing our Transfer Learning approach 35 How Well Are We Doing and Can We Do Better 36 Conclusions and Future Work

    big data analytics with java

    This book covers case studies such as sentiment analysis on a tweet dataset, recommendations on a movielens dataset, ...This book is an end-to-end guide to implement analytics on big data with Java.

    Excel_2016_Power_Programming_with_VBA

    For most of us, the path to Excel VBA programming starts with the need to perform some task that can’t be done with the standard tools in Excel. That task is different for each of us. Maybe that task...

    C#中DataSet的用法(很详细)

    在C#编程中,DataSet是ADO.NET框架中的一个重要组件,它是内存中数据的容器,能够离线存储和处理数据。DataSet不仅包含多个DataTable,用于存储实际的数据,还提供了丰富的功能,如浏览、排序、搜索、过滤和缓存更改...

    dataset

    在IT行业中,数据处理是至关重要的任务,而`DataSet`是.NET Framework提供的一种数据处理组件,它能够存储和操作多个相关的数据表。在这个场景中,我们看到一个Web应用程序的事件处理函数,其目标是将从数据库查询...

    DataSet详细用法(最全面)

    、可以在任何时候查看DataSet中任意行的内容,允许修改查询结果的方法。 、处理分级数据 、缓存更改 、XML的完整性:DataSet对象和XML文档几乎是可互换的。 、创建DataSet对象: 、查看调用SqlDataAdapter....

    c# xml转dataset

    在.NET框架中,C#提供了一种方便的方式来处理XML数据,可以将XML文档转换为DataSet对象,以便于进一步的数据操作和处理。`XmlDataDocument`是这个过程中的关键类,它继承自`System.Xml.XmlDocument`,并添加了与.NET...

    xiaomi note 10 real world dataset part1

    xiaomi note 10 real world dataset part1

    xiaomi note 10 real world dataset part3

    xiaomi note 10 real world dataset part3

    C# DataSet和XML文件的相互转换

    在.NET框架中,`DataSet`是用于存储和操作数据的强大工具,它可以被看作是一个内存中的数据库。同时,XML(可扩展标记语言)是用于数据交换的通用格式。在C#编程中,经常需要在`DataSet`和XML文件之间进行转换,以...

Global site tag (gtag.js) - Google Analytics