Pagination in JSF with PrimeFaces
The <h:dataTable> component in JSF (JavaServer Faces) is used to display lists of data a in table format, such as a collection of Java…
Pagination in JSF with PrimeFaces
The <h:dataTable> component in JSF (JavaServer Faces) is used to display lists of data a in table format, such as a collection of Java Objects
<h:dataTable value="#{pagedCities.cities}" var="city">
<h:column>
<f:facet name="header">
#{mensages.cityId}
</f:facet>
<h:outputText value="#{city.id}" />
</h:column>
<h:column>
<f:facet name="header">
#{mensages.cityName}
</f:facet>
<h:outputText value="#{city.name}" />
</h:column>
<h:column>
<f:facet name="header">
#{mensages.cityState}
</f:facet>
<h:outputText value="#{city.state}" />
</h:column>
</h:dataTable>
However, the h:dataTable> component is not one of the most elegant or practical choices, because, for example, if our list has 100,000 items, all of them will be displayed and kept in memory, which makes rendering on the screen slow.
To solve this problem, we can use the primefaces for paginate our list.
<p:dataTable value="#{paginatedCities.cities}" var="city"
paginator="true" rows="10" paginatorTemplate="{CurrentPageReport}
{FirstPageLink} {PreviousPageLink} {PageLinks}
{NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15" style="width: 40%">
<p:column>
<f:facet name="header">
#{messages.cityId}
</f:facet>
<h:outputText value="#{city.id}" />
</p:column>
<p:column>
<f:facet name="header">
#{messages.cityName}
</f:facet>
<h:outputText value="#{city.name}" />
</p:column>
<p:column>
<f:facet name="header">
#{messages.cityState}
</f:facet>
<h:outputText value="#{city.state}" />
</p:column>
</p:dataTable>
With PrimeFaces pagination, the entire list is handled on the client side, because if the query were performed on the server side returning many objects, it could easily exceed the avaible memory.
Lazy Pagination
Lazy paganition treats each click to the next page as a new query, thus loading only the request items.
<p:dataTable value="#{paginatedCitiesMB.lazyCities}" var="city"
paginator="true" rows="10" paginatorTemplate="{CurrentPageReport}
{FirstPageLink} {PreviousPageLink} {PageLinks}
{NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15" style="width: 40%" lazy="true">
Notice that the structure is very similar to regular PrimeFaces pagination, but with the addition of the lazy attribute, and in thevalue property we are using lazyCities
public class PaginatedCitiesMB implements Serializable {
private List<City> cities;
private LazyDataModel<City> lazyCities;
public List<City> getCities() {
if (cities == null) {
CityDAO cityDAO = AbstractManagedBean.getCityDAO();
cities = cityDAO.listAll();
}
return cities;
}
public void setCities(List<City> cities) {
this.cities = cities;
}
public LazyDataModel<City> getLazyCities() {
if (lazyCities == null) {
lazyCities = new CityLazyList();
}
return lazyCities;
}
public void setLazyCities(LazyDataModel<City> lazyCities) {
this.lazyCities = lazyCities;
}
}
public class CityLazyList extends LazyDataModel<City> {
private List<City> cities;
@Override
public List<City> load(int firstRowPosition,
int pageSize,
String sortField,
SortOrder sortOrder,
Map<String, String> filters) {
String order = sortOrder.toString();
if (SortOrder.UNSORTED.equals(sortOrder)) {
order = SortOrder.ASCENDING.toString();
}
cities = getDAO().findByPagination(
firstRowPosition,
pageSize,
sortField,
order,
filters
);
if (getRowCount() <= 0 || (filters != null && !filters.isEmpty())) {
setRowCount(getDAO().countAll(filters));
}
setPageSize(pageSize);
return cities;
}
private CityDAO getDAO() {
return AbstractManagedBean.getCityDAO();
}
@Override
public City getRowData(String rowKey) {
for (City city : cities) {
if (rowKey.equals(String.valueOf(city.getId()))) {
return city;
}
}
return null;
}
@Override
public Object getRowKey(City city) {
return city.getId();
}
@Override
public void setRowIndex(int rowIndex) {
if (rowIndex == -1 || getPageSize() == 0) {
super.setRowIndex(-1);
} else {
super.setRowIndex(rowIndex % getPageSize());
}
}
}
All pagination responsibility was also delegated to the abstract class **CityLazyList, where `lazyCities`** is just one of its attributes.
It is interesting to note that the **CityLazyList class extends the `org.primefaces.model.LazyDataModel** class and, as a result, inherits several methods that are already implemented. One of the most well-known examples of this concept is when creating a **Servlet**, where the extended class isHttpServlet`.
The public List load method receives as parameters all the necessary arguments to perform a query.
int firstRowPosition indicates from which row in the database the query should start. Thus, if its value is 10, the query will start from the tenth record returned by the database..
int pageSize indicates the number of records to be displayed on each page. If this value is set to 20, each query executed on the database will return only 20 results to be displayed..
SortOrderis an enum from PrimeFaces that indicates whether the sorting should be ASCENDING (ascending), DESCENDING (descending), or UNSORTED (no sorting)..
The methods setRowIndex, getRowKey, and getRowData are used when a row in the DataTable is selected. If a DataTable is used without lazy pagination, these methods are not necessary. They simply indicate which row is selected, the object contained in that row, and the ID of the object in the selected row.
In the DAO methods, it is always important to use your database’s features to retrieve only the information that needs to be displayed. In MySQL, for example, you can use the **LIMIT** clause, which will return only a specific range of results.
메타데이터
- post_id
- e3d49f9c2129
- slug
- paginação-no-jsf-com-primefaces-e3d49f9c2129
- url
- https://medium.com/@heryque08/pagina%C3%A7%C3%A3o-no-jsf-com-primefaces-e3d49f9c2129
- canonical_url
- https://medium.com/@heryque08/pagina%C3%A7%C3%A3o-no-jsf-com-primefaces-e3d49f9c2129
- author_url
- https://medium.com/@heryque08
- status
- ok
- fetched_at
- 2026-07-19 21:04:01