JSF 

In this tutorial I will show how to create effective pagination example in jsf2, hibernate and mysql. There are lots of built-in API for datatable paginations like PrimeFaces, RichFaces, Openfaces, SmartFaces, ICEFaces etc. but if someone wants to create his/her own pagination then it might be useful at least for beginners.

You can create this web application in any JEE based IDE like Netbeans, Eclipse etc. Before beginning you have to have the below set of jar files in your classpath. So please download the below jar files from the respective sites and put the jars under WEB-INF/lib directory.
I have created this project in Netbeans so I did not need to download any jars because the jars already available with the Netbeans.

1. Once you create the web application, create a hibernate configuration and hibernate reverse engineer files in the classpath. Here the default table ‘cdcol’ supplied with MySQL database has been used. You can use any table as per your requirements. The below hibernate configuration file contains database dialect, database connection details, hibernate XML and Java mapping files. It builds the Session Factory from all these configurations.

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/cdcol?zeroDateTimeBehavior=convertToNull</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.current_session_context_class">thread</property>
    <property name="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.format_sql">true</property>
    <mapping resource="in/sblog/domain/Cds.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

The below reverse engineering file contains database schema and tables included in the schema. The schema name is cdcol and the table name is cds for this example.

hibernate.reveng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd">
<hibernate-reverse-engineering>
    <schema-selection match-catalog="cdcol"/>
    <table-filter match-name="cds"/>
</hibernate-reverse-engineering>

2. Now generate or create domain or model object for the cds table in cdcolable schema. XML file name does not need to contain the ‘hbm’ but it is a naming convention. In the below mapping file the primary key column is mapped with <id> and all other regular columns are mapped using <property> tag. Here the primary key column generation type is identity because we want the column value should be auto-generated.

Cds.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="in.sblog.domain.Cds" table="cds" catalog="cdcol">
        <id name="id" type="java.lang.Long">
            <column name="id" />
            <generator class="identity" />
        </id>
        <property name="titel" type="string">
            <column name="titel" length="200" />
        </property>
        <property name="interpret" type="string">
            <column name="interpret" length="200" />
        </property>
        <property name="jahr" type="java.lang.Integer">
            <column name="jahr" />
        </property>
    </class>
</hibernate-mapping>

The below class is required to map the table columns with Java attributes using the above XML mapping file.

Cds.java

public class Cds implements java.io.Serializable {

    private Long id;
    private String titel;
    private String interpret;
    private Integer jahr;

    public Cds() {
    }

    public Cds(String titel, String interpret, Integer jahr) {
        this.titel = titel;
        this.interpret = interpret;
        this.jahr = jahr;
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitel() {
        return this.titel;
    }

    public void setTitel(String titel) {
        this.titel = titel;
    }

    public String getInterpret() {
        return this.interpret;
    }

    public void setInterpret(String interpret) {
        this.interpret = interpret;
    }

    public Integer getJahr() {
        return this.jahr;
    }

    public void setJahr(Integer jahr) {
        this.jahr = jahr;
    }

}

3. Create hibernate util class for creating single SessionFactory. This SessionFactory later will be used to produce non-thread-safe sessions.

import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;

/**
 * Hibernate Utility class with a convenient method to get Session Factory
 * object.
 *
 * @author admin
 */
public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    static {
        try {
            // Create the SessionFactory from standard (hibernate.cfg.xml)
            // config file.
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Log the exception.
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

4. Now create the helper class which is used to execute the queries for database transactions. We have used hibernate’s Criteria API to quwry the database.

import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @author admin
 */
public class CDHelper {

    Session session = null;

    public CDHelper() {
        session = HibernateUtil.getSessionFactory().getCurrentSession();
    }

    public List<Cds> getListOfCds(int firstRow, int rowCount) {
        List<Cds> cdList = null;
        try {
            Transaction transaction = session.beginTransaction();
            Criteria criteria = session.createCriteria(Cds.class);
            criteria.setFirstResult(firstRow);
            criteria.setMaxResults(rowCount);
            if (criteria != null) {
                cdList = (List<Cds>) criteria.list();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cdList;
    }

    public int countRows() {
        try {
            Transaction transaction = session.beginTransaction();
            Criteria criteria = session.createCriteria(Cds.class);
            if (criteria != null) {
                return criteria.list().size();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}

5. Now create the jsf managed bean class which will be used to interact with the view and display data to the view. Here I am not using faces-config.xml file so using the annotation. I have also kept the managed bean in ViewScope so that the state will be automatically maintained by the jsf API. We have handled using the below code different scenarios. We will show total pages for the returned data. We will provide links for first page, next page, page numbers etc.

import java.io.Serializable;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UICommand;
import javax.faces.event.ActionEvent;

/**
 *
 * @author admin
 */
@ManagedBean
@ViewScoped
public class JsfPaginationBean implements Serializable {

    private List<Cds> cdList;
    private CDHelper cDHelper;

    /**
     * pagination stuff
     */
    private int totalRows;
    private int firstRow;
    private int rowsPerPage;
    private int totalPages;
    private int pageRange;
    private Integer[] pages;
    private int currentPage;

    /**
     * Creates a new instance of JsfPaginationBean
     */
    public JsfPaginationBean() {
        cDHelper = new CDHelper();
        // Set default values somehow (properties files?).
        rowsPerPage = 15; // Default rows per page (max amount of rows to be displayed at once).
        pageRange = 10; // Default page range (max amount of page links to be displayed at once).
    }

    public List<Cds> getCdList() {
        if (cdList == null) {
            loadCdList();
        }
        return cdList;
    }

    public void setCdList(List<Cds> cdList) {
        this.cdList = cdList;
    }

    public int getTotalRows() {
        return totalRows;
    }

    public void setTotalRows(int totalRows) {
        this.totalRows = totalRows;
    }

    public int getFirstRow() {
        return firstRow;
    }

    public void setFirstRow(int firstRow) {
        this.firstRow = firstRow;
    }

    public int getRowsPerPage() {
        return rowsPerPage;
    }

    public void setRowsPerPage(int rowsPerPage) {
        this.rowsPerPage = rowsPerPage;
    }

    public int getTotalPages() {
        return totalPages;
    }

    public void setTotalPages(int totalPages) {
        this.totalPages = totalPages;
    }

    public int getPageRange() {
        return pageRange;
    }

    public void setPageRange(int pageRange) {
        this.pageRange = pageRange;
    }

    public Integer[] getPages() {
        return pages;
    }

    public void setPages(Integer[] pages) {
        this.pages = pages;
    }

    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }

    private void loadCdList() {
        cdList = cDHelper.getListOfCds(firstRow, rowsPerPage);
        totalRows = cDHelper.countRows();

        // Set currentPage, totalPages and pages.
        currentPage = (totalRows / rowsPerPage) - ((totalRows - firstRow) / rowsPerPage) + 1;
        totalPages = (totalRows / rowsPerPage) + ((totalRows % rowsPerPage != 0) ? 1 : 0);
        int pagesLength = Math.min(pageRange, totalPages);
        pages = new Integer[pagesLength];

        // firstPage must be greater than 0 and lesser than totalPages-pageLength.
        int firstPage = Math.min(Math.max(0, currentPage - (pageRange / 2)), totalPages - pagesLength);

        // Create pages (page numbers for page links).
        for (int i = 0; i < pagesLength; i++) {
            pages[i] = ++firstPage;
        }
    }

    // Paging actions -----------------------------------------------------------------------------
    public void pageFirst() {
        page(0);
    }

    public void pageNext() {
        page(firstRow + rowsPerPage);
    }

    public void pagePrevious() {
        page(firstRow - rowsPerPage);
    }

    public void pageLast() {
        page(totalRows - ((totalRows % rowsPerPage != 0) ? totalRows % rowsPerPage : rowsPerPage));
    }

    public void page(ActionEvent event) {        
        page(((Integer) ((UICommand) event.getComponent()).getValue() - 1) * rowsPerPage);
    }

    private void page(int firstRow) {
        this.firstRow = firstRow;
        loadCdList();
    }
}

6. Now create the view file – index.xhtml. I am not using jsp file because xhtml has better support for jsf 2.x and it also supports facelets.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <h:head>
        <title>List of CDs</title>
    </h:head>
    <h:body>
        <h:form id="form" prependId="false">
            <!--The sortable datatable-->
            <h:dataTable value="#{jsfPaginationBean.cdList}" var="cd" rendered="#{jsfPaginationBean.cdList ne null}">
                <h:column>
                    <f:facet name="header">
                        CD ID
                    </f:facet>
                    <h:outputText value="#{cd.id}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        Title
                    </f:facet>
                    <h:outputText value="#{cd.titel}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        Interpret
                    </f:facet>
                    <h:outputText value="#{cd.interpret}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        Jahr
                    </f:facet>
                    <h:outputText value="#{cd.jahr}" />
                </h:column>
            </h:dataTable>

            <!--The paging buttons-->
            <h:commandButton value="first" action="#{jsfPaginationBean.pageFirst}"
                             disabled="#{jsfPaginationBean.firstRow == 0}" />
            <h:commandButton value="prev" action="#{jsfPaginationBean.pagePrevious}"
                             disabled="#{jsfPaginationBean.firstRow == 0}" />
            <h:commandButton value="next" action="#{jsfPaginationBean.pageNext}"
                             disabled="#{jsfPaginationBean.firstRow + jsfPaginationBean.rowsPerPage &gt;= jsfPaginationBean.totalRows}" />
            <h:commandButton value="last" action="#{jsfPaginationBean.pageLast}"
                             disabled="#{jsfPaginationBean.firstRow + myBean.rowsPerPage &gt;= jsfPaginationBean.totalRows}" />
            <h:outputText value="Page #{jsfPaginationBean.currentPage} / #{jsfPaginationBean.totalPages}" />
            <br />

            <!--The paging links-->
            <ui:repeat value="#{jsfPaginationBean.pages}" var="page">
                <h:commandLink value="#{page}" actionListener="#{jsfPaginationBean.page}"
                               rendered="#{page != jsfPaginationBean.currentPage}" />
                <h:outputText value="&lt;b&gt;#{page}&lt;/b&gt;" escape="false"
                              rendered="#{page == jsfPaginationBean.currentPage}" />
            </ui:repeat>
            <br />

            <!-- Set rows per page -->
            <h:outputLabel for="rowsPerPage" value="Rows per page" />
            <h:inputText id="rowsPerPage" value="#{jsfPaginationBean.rowsPerPage}" size="3" maxlength="3" />
            <h:commandButton value="Set" action="#{jsfPaginationBean.pageFirst}" />
            <h:message for="rowsPerPage" errorStyle="color: red;" />
        </h:form>
    </h:body>
</html>

7. You can verify your deployment descriptor file as well.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsf</welcome-file>
    </welcome-file-list>
</web-app>

That’s all. Thank you for your patience. If you have any question please do not forget to leave a comment.

Tags:

I am a professional Web developer, Enterprise Application developer, Software Engineer and Blogger. Connect me on Roy Tutorials | TwitterFacebook Google PlusLinkedin | Reddit

1 thought on “Effective pagination example in jsf 2

Leave a Reply

Your email address will not be published. Required fields are marked *