Download as pdf or txt
Download as pdf or txt
You are on page 1of 7

PrimeFaces DataTable and server side pagination, filtering and sorting | ... https://tillias.wordpress.com/2013/11/17/primefaces-datatable-and-serve...

Tillias's Blog

PrimeFaces DataTable and server side pagination, filtering and sorting

November 17, 2013 — tillias


Recently I’ve tried PrimeFaces 4x DataTable once again (after year or so working with Apache Wicket). One thing — I like it. It is now possible to
implement scallable server side pagination, filtering and sorting logic without too much hacks

Fist of all let’s examine org.primefaces.model package in order to undestand how LazyDataModel<T> works. Concrete implementation of this abstract
class will be extensively used in this post (because this is also a core class for DataTable as you can see from stock
examples -> LazyCarDataModel.java)

As you can see from the picture above LazyDataModel<T> extends core javax.faces.model.DataModel<T> and adds sorting / filtering capabilities.

Let’s concentrate on this :

1 of 7 3/28/20, 11:01 PM
PrimeFaces DataTable and server side pagination, filtering and sorting | ... https://tillias.wordpress.com/2013/11/17/primefaces-datatable-and-serve...
1 /*
2 * Copyright 2009-2013 PrimeTek.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 *...
6 */
7 public abstract class LazyDataModel<T> extends DataModel<T> implements SelectableDataModel<T>, Serializable
8
9 ...
10
11 public List<T> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,String> fil
12         throw new UnsupportedOperationException("Lazy loading is not implemented.");

This is completely fine. Even string based  Map<String,String> filters parameter(s) because you provide stings as filter value by default in the
DataTable

But what to do if you have layered architecture? For example actual sorting is performed in the REST / SOA back-end? I’m strongly agains using
front-end entities / libraries / packages inside back-end.

One possible approach is to introduce your own set of entities for server side handling:

2 of 7 3/28/20, 11:01 PM
PrimeFaces DataTable and server side pagination, filtering and sorting | ... https://tillias.wordpress.com/2013/11/17/primefaces-datatable-and-serve...

The core of the back-end framework is PageableDataProvider<T> interface. Concrete implementation(s) of this interface can act like front-end proxies
for retreival of data:

So you DataTable in the view binds to the LazyStudentsDataModel – concrete implementation of TableDataModel. The trick is
that TableDataModel handles conversion of the front-end  entities into server-side ones and manages “magic” rowCount property:

3 of 7 3/28/20, 11:01 PM
PrimeFaces DataTable and server side pagination, filtering and sorting | ... https://tillias.wordpress.com/2013/11/17/primefaces-datatable-and-serve...
1 public abstract class TableDataModel<T> extends LazyDataModel<T> {
2
3     private static final long serialVersionUID = -6074599821435569629L;
4
5     private int rowCount;
6
7     @Override
8     public int getRowCount() {
9         return rowCount;
10     }
11
12     public void setRowCount(int rowCount) {
13         this.rowCount = rowCount;
14     }
15
16     @Override
17     public List<T> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, String> filters)
18         throw new UnsupportedOperationException();
19     }
20
21     @Override
22     public List<T> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String>
23         LoadOptions loadOptions = convert(first, pageSize, sortField, sortOrder, filters);
24         PagedList<T> data = getData(loadOptions);
25
26         Long longSize = Long.valueOf(data.getTotalSize());
27
28         setRowCount(longSize.intValue());
29
30         return data;
31     }
32
33     protected abstract PagedList<T> getData(LoadOptions loadOptions);
34
35     private LoadOptions convert(int first, int pageSize, String sortField, SortOrder sortOrder,
36             Map<String, String> filters) {
37         List<SortMeta> sorts = new ArrayList<>();
38
39         if (!StringUtils.isBlank(sortField)) {
40             SortMeta sort = new SortMeta();
41             sort.setSortField(sortField);
42             sort.setSortOrder(sortOrder);
43             sorts.add(sort);
44         }
45
46         return convert(first, pageSize, sorts, filters);
47     }
48
49     private LoadOptions convert(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, String>
50         LoadOptions loadOptions = new LoadOptions();
51         loadOptions.setSkipItems(first);
52         loadOptions.setTakeItems(pageSize);
53
54         List<SortOption> sorts = new ArrayList<>();
55         for (int i = 0; i < multiSortMeta.size(); ++i) {
56             SortMeta sortMeta = multiSortMeta.get(i);
57             if (sortMeta != null) {
58                 String sortField = sortMeta.getSortField();
59                 if (!StringUtils.isBlank(sortField)) {
60                     SortOption sort = new SortOption();
61                     sort.setSortField(sortField);
62                     sort.setSortDirection(convert(sortMeta.getSortOrder()));
63                     sort.setRank(i);
64                     sorts.add(sort);
65                 }
66             }
67         }
68         loadOptions.setSorts(sorts);
69
70         List<String> filterFields = new ArrayList<>(filters.keySet());
71         List<FilterOption> filterOptions = new ArrayList<>();
72         for (String filterField : filterFields) {
73             if (!StringUtils.isBlank(filterField)) {
74                 String filterValue = filters.get(filterField);
75                 FilterOption filterOption = new FilterOption();
76                 filterOption.setField(filterField);
77                 filterOption.setValue(filterValue);
78                 filterOptions.add(filterOption);
79             }
80         }
81         loadOptions.setFilters(filterOptions);
82
83         return loadOptions;
84     }
85
86     private SortDirection convert(SortOrder sortOrder) {
4 of 7 3/28/20, 11:01 PM
PrimeFaces DataTable and server side pagination, filtering and sorting | ... https://tillias.wordpress.com/2013/11/17/primefaces-datatable-and-serve...
87         switch (sortOrder) {
88         case ASCENDING:
89             return SortDirection.ASCENDING;
90         case DESCENDING:
91             return SortDirection.DESCENDING;
92         case UNSORTED:
93             return SortDirection.UNSORTED;
94         default:
95             throw new IllegalArgumentException("Unknown sort order");
96         }
97     }
}

So the concrete implementations of TableDataModel are becoming plain simple (and without tons of boilerplate code):

1 @Service
2 @SessionScope
3 public class LazyStudentsDataModel extends TableDataModel<Student> {
4
5     private static final long serialVersionUID = -544764175489727755L;
6
7     @Autowired
8     private StudentsDataProvider dataProvider;
9
10     @Override
11     protected PagedList<Student> getData(LoadOptions loadOptions) {
12         return dataProvider.getObjects(loadOptions);
13     }
14
15 }

Easy isn’t it?

Your server-side data provider implementation may look like:

5 of 7 3/28/20, 11:01 PM
PrimeFaces DataTable and server side pagination, filtering and sorting | ... https://tillias.wordpress.com/2013/11/17/primefaces-datatable-and-serve...
1 @Repository
2 @DefaultProfile
3 public class StudentsDataProviderImpl implements StudentsDataProvider {
4
5     private static final Logger LOG = LoggerFactory.getLogger(StudentsDataProviderImpl.class);
6
7     @Autowired
8     private SessionFactory sessionFactory;
9
10     @Autowired
11     private MappingService mappingService;
12
13     @Transactional
14     @Override
15     public PagedList<Student> getObjects(LoadOptions loadOptions) {
16         Session session = sessionFactory.getCurrentSession();
17
18         PagedList<Student> result = new PagedList<>();
19
20         try {
21             Criteria countCriteria = session.createCriteria(StudentEntity.class);
22             fillCriteria(countCriteria, loadOptions, true);
23
24             long rowsCount = (long) countCriteria.uniqueResult();
25
26             if (rowsCount > 0) {
27                 Criteria criteria = session.createCriteria(StudentEntity.class);
28                 fillCriteria(criteria, loadOptions, false);
29
30                 List<StudentEntity> dataEntities = criteria.list();
31                 for (StudentEntity de : dataEntities) {
32                     Student student = mappingService.map(de, Student.class);
33                     result.add(student);
34                 }
35             }
36
37             result.setTotalSize(rowsCount);
38         } catch (Exception ex) {
39             LOG.error("Error loading students", ex);
40         }
41
42         return result;
43     }
44
45 private void fillCriteria(Criteria source, LoadOptions loadOptions, boolean countOnly) {
46         List<FilterOption> filters = loadOptions.getFilters();
47         if (CollectionUtils.hasItems(filters)) {
48             for (FilterOption f : filters) {
49                 source.add(Restrictions.eq(f.getField(), f.getValue()));
50             }
51         }

The trick here is the usage of PagedList<T>.  First call to the database counts total number of records to be displayed in the front-end table based on
LoadOptions (thus filtering, sorting, page size etc). Second call fetches data to be displayed only in one front-end data table “page”.

Posted in Java. Tags: application layers, best practices, framework, hibernate, integration, java, JavaEE, performance, primefaces, query object,
services, spring famework, spring orm. 1 Comment »

6 of 7 3/28/20, 11:01 PM
PrimeFaces DataTable and server side pagination, filtering and sorting | ... https://tillias.wordpress.com/2013/11/17/primefaces-datatable-and-serve...

One Response to “PrimeFaces DataTable and server side pagination, filtering and sorting”

mousavi Says:
May 28, 2014 at 4:33 pm
hi
that,s very good code.
can you put a sample project to use this code?

Reply

« Hibernate Tools and Custom DelegatingReverseEngineeringStrategy

RestTemplate and Proxy Authentication explained »

Blog at WordPress.com. Do Not Sell My Personal Information

7 of 7 3/28/20, 11:01 PM

You might also like