My company develops a Spring web application that exposes a REST API and right now we're starting to look into pagination for the methods that load data from some heavy tables.
We initially looked into Spring Data JPA but had some difficulties in integrating the Repository logic so in the end I integrated only the beans that handle the Pageable
page request and the Page
response from the methods.
Since I have to return a Page
that contains the data and the total number of elements I created a wrapper object that I called PaginationHelper
in order to avoid creating two separate methods with the same query logic, one for calculating the total number of elements and the other to actually return the current requested page.
This is a code example from the Rest Controller to the DAO:
PaginationHelper
public class PaginationHelper<T> {
private long numTotalElements;
private List<T> page;
public PaginationHelper() {
}
public PaginationHelper(List<T> page, long numTotalElements) {
this.page = page;
this.numTotalElements = numTotalElements;
}
//getters and setters
}
Controller search method
@RequestMapping(value="/search",method=RequestMethod.GET)
public Page<Foo> findFoo(@RequestParam (value = "filterParam1", required=false) String param1,
@RequestParam(value="filterParam2", required=false) String param2,
@RequestParam(value="filterParam3", required=false) boolean param3,
Pageable pageRequest)
{
Page<Foo> retPage=null;
boolean flCount = false;
PaginationHelper pagHelper = myService.search(param1, param2, param3, pageRequest);
if(pagHelper!=null && pagHelper.getPage()!=null)
{
retPage = new PageImpl(pagHelper.getPage(), pageRequest, pagHelper.getNumTotalElements())
}
return retPage;
}
Service
public PaginationHelper search(String param1,
String param2, boolean param3, Pageable pageRequest) {
//--> I'm not so sure about this, seems very dirty to me
PaginationHelper<Foo> paginationHelper = new PaginationHelper<Foo>();
paginationHelper = myDao.search(true, param1, param2, param3, pageRequest, paginationHelper);
paginationHelper = myDao.search(false, param1, param2, param3, pageRequest, paginationHelper);
return wpRet;
}
DAO
@Override
@Transactional
public PaginationHelper<Foo> search(boolean flCount, String param1, String param2, boolean param3,
Pageable pageRequest, PaginationHelper<WrapperDiscussioneForumEPT> paginationHelper) {
Session session = sessionManager.getFilteredSession(FilterType.NONE);
String hql = "FROM " + Foo.class.getName() + " f WHERE f.param1 = param1 AND f.param2 = param2 AND f.param3 = param3";
Query q = session.createQuery(hql);
q.setParameter("param1", param1);
q.setParameter("param2", param2);
q.setParameter("param3", param3);
if(flCount)
{
long numElementi = (long)q.uniqueResult();
paginationHelper.setNumElementiTotali(numElementi);
}
else
{
q.setFirstResult(pageRequest.getPageNumber()*pageRequest.getPageSize()).setMaxResults(pageRequest.getPageSize());
retLst = q.list();
paginationHelper.setPage(retLst);
}
return paginationHelper;
}
So in short, the sole reason for the PaginationHelper
existence is to avoid writing two methods very similar to access the data from the DBMS. Instead, just one method will do the count or the page retrieve based on a flag passed. I fear this is not a good approach. And I fear is not a good approach to instantiate a paginationHelper instance and pass it to both the two calls of the DAo search method.
Our stack:
- Spring -> 4.1.1.RELEASE
- Hibernate -> 4.3.5.Final
- Spring Security -> 3.2.4.RELEASE
- spring-data-jpa -> 1.8.2.RELEASE
- spring-data-commons -> 1.10.2.RELEASE