Friday, January 25, 2013

Spring MVC + Hibnerate + jQuery DataTables + Pagination

JQuery datatables (http://www.datatables.net/) always gets all data from server for its build-in pagination, it is not good for huge data, the better approach is to pass current position and page size to server and get data from database batch by batch.

so refer to http://datatables.net/usage/server-side, there are some para we must pass from client to server.

1) on the client side,


oTBExample2 = $("#example2").dataTable({
"bProcesing" : true,
"bServerSide" : true,
"bLenthChange" : false,
"iDisplayLength" : 10,
"sAjaxSource" : "users2.do",
"aoColumns" : [
{
"sTitle" : "User ID",
"mData" : "userid"
},
{
"sTitle" : "Password",
"mData" : "password"
},
{
"sTitle" : "Date & Time",
"mData" : "timeStamp"
},
{
"mData" : "checked",
"fnRender" : function(obj) {
if (obj.aData.checked == "1")
return '<input type="checkbox" name="aCheckBox" class="dt_checked" checked value="'+obj.aData.checked+'\"/>';

return '<input type="checkbox" name="aCheckBox"  class="dt_checked" value="'+obj.aData.checked+'\"/>';
}
},
{
"mData" : null,
"sClass" : "center",
"sDefaultContent" : '<a href="" class="editor_remove" >Delete</a>'
} ],
"fnServerData" : function(sSource, aoData, fnCallback) {
$.ajax({
"dataType" : 'json',
"type" : "GET",
"url" : sSource,
"data" : aoData,
"success" : fnCallback
});
},
"sPaginationType" : "full_numbers"

});// dataTable



<table id="example2" cellpadding="0" cellspacing="0" border="0"
class="display datatable">
<thead>
<tr>
<th width="20%">userid</th>
<th width="20%">password</th>
<th width="20%">time</th>
<th width="10%">selected</th>
<th width="10%">Delete</th>
</tr>
</thead>
<tbody>
</tbody>
</table>


2) on server side,



@RequestMapping(value = "/users2", produces = "application/json")
public @ResponseBody
String showUser(@RequestParam int iDisplayStart,
            @RequestParam int iDisplayLength, @RequestParam int sEcho) {
String method="showUser";
info(method,"para0---"+iDisplayStart);
info(method,"para1---"+iDisplayLength);
info(method,"para2---"+sEcho);
DataTablesTO<Account> dt = new DataTablesTO<Account>();

List<Account> accts = accountService.getAccounts(iDisplayStart,iDisplayLength);
List<Account> accts2 = accountService.getAccounts();
dt.setAaData(accts);  // this is the dataset reponse to client
dt.setiTotalDisplayRecords(accts2.size());  // // the total data in db for datatables to calculate page no. and position
dt.setiTotalRecords(accts2.size());   // the total data in db for datatables to calculate page no.
dt.setsEcho(sEcho);

return toJson(dt);
}


private String toJson(DataTablesTO<?> dt){
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(dt);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}

need jackson jar files to support json conversion,

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;


public class DataTablesTO<T> implements java.io.Serializable{

private static final long serialVersionUID = -8220588043068200705L;
private List<T> aaData;
private int sEcho;
private Integer iTotalRecords;
private Integer iTotalDisplayRecords;
...... getter and setter.......
}

3) hibernate query


public List<Account> getAccounts(int currPosition, int pageSize) {

return sessionFactory.getCurrentSession().createQuery("from Account").setMaxResults(pageSize).setFirstResult(currPosition).list();
}


current position which means the first row to be shown on the page in the table.

4) actual result on page









5) this is the request data when call ajax


  1. sEcho:
    1
  2. iColumns:
    5
  3. sColumns:
  4. iDisplayStart:
    0
  5. iDisplayLength:
    10
  6. mDataProp_0:
    userid
  7. mDataProp_1:
    password
  8. mDataProp_2:
    timeStamp
  9. mDataProp_3:
    checked
  10. mDataProp_4:
  11. sSearch:
  12. bRegex:
    false
  13. sSearch_0:
  14. bRegex_0:
    false
  15. bSearchable_0:
    true
  16. sSearch_1:
  17. bRegex_1:
    false
  18. bSearchable_1:
    true
  19. sSearch_2:
  20. bRegex_2:
    false
  21. bSearchable_2:
    true
  22. sSearch_3:
  23. bRegex_3:
    false
  24. bSearchable_3:
    true
  25. sSearch_4:
  26. bRegex_4:
    false
  27. bSearchable_4:
    true
  28. iSortCol_0:
    0
  29. sSortDir_0:
    asc
  30. iSortingCols:
    1
  31. bSortable_0:
    true
  32. bSortable_1:
    true
  33. bSortable_2:
    true
  34. bSortable_3:
    true
  35. bSortable_4:
    true

6) right now, the datatables does not support order by column, if click the second column to order by it,let's check the request data.

  1. sEcho:
    7
  2. iColumns:
    5
  3. sColumns:
  4. iDisplayStart:
    0
  5. iDisplayLength:
    10
  6. mDataProp_0:
    userid
  7. mDataProp_1:
    password
  8. mDataProp_2:
    timeStamp
  9. mDataProp_3:
    checked
  10. mDataProp_4:
  11. sSearch:
  12. bRegex:
    false
  13. sSearch_0:
  14. bRegex_0:
    false
  15. bSearchable_0:
    true
  16. sSearch_1:
  17. bRegex_1:
    false
  18. bSearchable_1:
    true
  19. sSearch_2:
  20. bRegex_2:
    false
  21. bSearchable_2:
    true
  22. sSearch_3:
  23. bRegex_3:
    false
  24. bSearchable_3:
    true
  25. sSearch_4:
  26. bRegex_4:
    false
  27. bSearchable_4:
    true
  28. iSortCol_0:
    1 // means sorted by the second column
  29. sSortDir_0:
    asc // means order by asc, if click again, it will change to desc
  30. iSortingCols:
    1
  31. bSortable_0:
    true
  32. bSortable_1:
    true
  33. bSortable_2:
    true
  34. bSortable_3:
    true
  35. bSortable_4:
    true


so, we also need to change the hql as follows

from Account order by ${iSortCol_0}+1 ${sSortDir_0}








19 comments:

  1. Thank you for good post. Can you please post code as well.

    ReplyDelete
  2. i am working on spring, hibernate, datatables integration, so my database contains lots of records so while accessing it staking time to load, so what i thought is like get 10 pages...if i click on next then the request should go to controller and get the remaining 10 pages... i stuck up here... plz help me.......

    My table is like 3 tabs each tab contains one table...

    ReplyDelete
    Replies
    1. yes, what the post describe is to resolve your issues, pls take note

      public List getAccounts(int currPosition, int pageSize)

      this is specially for pagination.

      How to pass pagination info from jDataTables to servlet, pls take note this bean,

      public class DataTablesTO implements java.io.Serializable{

      private static final long serialVersionUID = -8220588043068200705L;
      private List aaData;
      private int sEcho;
      private Integer iTotalRecords;
      private Integer iTotalDisplayRecords;
      ...... getter and setter.......
      }

      Delete
  3. I am trying to call my Spring MVC controller from a JSP and getting following error on browser
    "The request sent by the client was syntactically incorrect ()"
    please help me.
    Thanks in advance.

    ReplyDelete
    Replies
    1. Do not have enough info, can you refer to this post

      http://forum.springsource.org/showthread.php?98200-Spring-The-request-sent-by-the-client-was-syntactically-incorrect

      Delete
  4. Hi, I have integrated Spring, Hibernate and DataTables in several projects. I have written a howto specific for Spring Roo but it can be easily applied to a normal Spring MVC app. There is also a link to the whole project in github.
    http://www.pabloguerrero.org/cgblog/2/15/DataTables-server-side-processing-integration-with-Spring-Roo-and-Hibernate
    Hope it helps somebody

    ReplyDelete
  5. Hi,
    Can you please post the source code of this tutorial ?
    Thanks

    ReplyDelete
  6. Hi Wang Xiang's
    it is good tutorial , I want to get source code of you this example ,
    can you put your code to every can get it ?
    thanks

    ReplyDelete
  7. hi ,can you post the example with all source code means js,css (with downloaded option) with an spring and hibernate with jquery pagination data table I want to call ajax with every page request,means 10 record fetch from db with select 10 and with next . plz help me

    ReplyDelete
  8. While running this app - Required int parameter 'iDisplayStart' is not present

    ReplyDelete
  9. Thanks a lot , it worked as described , have had few minor issues but after reading the whole article i fixed the issues.

    note : to fix the above program , just add sEcho : 1 , iDisplayStart : 0 parameters along with provided parameters as below .

    "bProcesing" : true,
    "bServerSide" : true,
    "bLenthChange" : false,
    "iDisplayLength" : 10,
    "iDisplayStart": 0,
    "sEcho":1,
    "sAjaxSource" : "users2.do",

    ReplyDelete
    Replies
    1. i am not able to search records. can you help me?

      Delete
  10. i am not able to search the data. can you please help me?

    ReplyDelete
  11. I found that the json data getting from page is string type, String showUser() -> DataTablesTO showUser()

    ReplyDelete
  12. This comment has been removed by the author.

    ReplyDelete