Simple Guide to Use DataTable with Spring Boot – Example With Source Code
In this article, you will learn how to use Datatable with Sprint Boot for Serverside processing with example. Complete Source Code and supporting SQL is provided on GitHub to download.
If you have worked on web development projects that deal with thousands of records getting displayed on the page then you must have worked with or heard of Datatables. It is a JQuery plugin that is highly flexible and adds interactive controls to any HTML table.
These tables serve a great purpose when it comes to displaying huge information in tabular form. When you have a task to work with huge data it’s not advised to pull all the data to client side first and then use datatables to display.
Use DataTable with Spring Boot:
In this scenario, we need to do the processing at the server side and send only relevant records back for display. In this article, we will see an example of this functionality. You will get a wrapper around this functionality so the integration becomes easy.
Software used for this example
- Java 1.8
- Spring Boot 1.5.1.RELEASE
- JQuery
- DataTable 1.10.12
- MySQL
- Eclipse IDE
When we use server-side option of datatable we need to prepare data as per the datatable specification and send it in JSON format. In this example you will find many such wrapper classes that will help us to prepare pagination, sorting, filtering data.
Project Structure
When we specify data for any column on datatable we need to specify the data, name, searchable, etc. fields. The below class holds all that data and we also have a method that processes HTTP request object and prepares the specification for each of the columns.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
/** * */ package com.opencodez.domain.pagination; import javax.servlet.http.HttpServletRequest; /** * The Class DataTableColumnSpecs. * * @author pavan.solapure */ public class DataTableColumnSpecs { /** The index. */ private int index; /** The data. */ private String data; /** The name. */ private String name; /** The searchable. */ private boolean searchable; /** The orderable. */ private boolean orderable; /** The search. */ private String search; /** The regex. */ private boolean regex; /** The sort dir. */ private String sortDir; /** * Instantiates a new data table column specs. * * @param request the request * @param i the i */ public DataTableColumnSpecs(HttpServletRequest request, int i) { this.setIndex(i); prepareColumnSpecs(request, i); } /** * Prepare column specs. * * @param request the request * @param i the i */ private void prepareColumnSpecs(HttpServletRequest request, int i) { this.setData(request.getParameter("columns["+ i +"][data]")); this.setName(request.getParameter("columns["+ i +"][name]")); this.setOrderable(Boolean.valueOf(request.getParameter("columns["+ i +"][orderable]"))); this.setRegex(Boolean.valueOf(request.getParameter("columns["+ i +"][search][regex]"))); this.setSearch(request.getParameter("columns["+ i +"][search][value]")); this.setSearchable(Boolean.valueOf(request.getParameter("columns["+ i +"][searchable]"))); int sortableCol = Integer.parseInt(request.getParameter("order[0][column]")); String sortDir = request.getParameter("order[0][dir]"); if(i == sortableCol) { this.setSortDir(sortDir); } } } |
After this, we have another main class that holds data for complete datatable interaction including draw, search, start, end of data. It will also hold the list of the above specification class for each column.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
/** * */ package com.opencodez.domain.pagination; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import com.opencodez.util.AppUtil; /** * The Class DataTableRequest. * * @author pavan.solapure */ public class DataTableRequest<T> { /** The unique id. */ private String uniqueId; /** The draw. */ private String draw; /** The start. */ private Integer start; /** The length. */ private Integer length; /** The search. */ private String search; /** The regex. */ private boolean regex; /** The columns. */ private List<DataTableColumnSpecs> columns; /** The order. */ private DataTableColumnSpecs order; /** The is global search. */ private boolean isGlobalSearch; /** * Instantiates a new data table request. * * @param request the request */ public DataTableRequest(HttpServletRequest request) { prepareDataTableRequest(request); } /** * Prepare data table request. * * @param request the request */ private void prepareDataTableRequest(HttpServletRequest request) { Enumeration<String> parameterNames = request.getParameterNames(); if(parameterNames.hasMoreElements()) { this.setStart(Integer.parseInt(request.getParameter(PaginationCriteria.PAGE_NO))); this.setLength(Integer.parseInt(request.getParameter(PaginationCriteria.PAGE_SIZE))); this.setUniqueId(request.getParameter("_")); this.setDraw(request.getParameter(PaginationCriteria.DRAW)); this.setSearch(request.getParameter("search[value]")); this.setRegex(Boolean.valueOf(request.getParameter("search[regex]"))); int sortableCol = Integer.parseInt(request.getParameter("order[0][column]")); List<DataTableColumnSpecs> columns = new ArrayList<DataTableColumnSpecs>(); if(!AppUtil.isObjectEmpty(this.getSearch())) { this.setGlobalSearch(true); } maxParamsToCheck = getNumberOfColumns(request); for(int i=0; i < maxParamsToCheck; i++) { if(null != request.getParameter("columns["+ i +"][data]") && !"null".equalsIgnoreCase(request.getParameter("columns["+ i +"][data]")) && !AppUtil.isObjectEmpty(request.getParameter("columns["+ i +"][data]"))) { DataTableColumnSpecs colSpec = new DataTableColumnSpecs(request, i); if(i == sortableCol) { this.setOrder(colSpec); } columns.add(colSpec); if(!AppUtil.isObjectEmpty(colSpec.getSearch())) { this.setGlobalSearch(false); } } } if(!AppUtil.isObjectEmpty(columns)) { this.setColumns(columns); } } } private int getNumberOfColumns(HttpServletRequest request) { Pattern p = Pattern.compile("columns\\[[0-9]+\\]\\[data\\]"); @SuppressWarnings("rawtypes") Enumeration params = request.getParameterNames(); List<String> lstOfParams = new ArrayList<String>(); while(params.hasMoreElements()){ String paramName = (String)params.nextElement(); Matcher m = p.matcher(paramName); if(m.matches()) { lstOfParams.add(paramName); } } return lstOfParams.size(); } /** * Gets the pagination request. * * @return the pagination request */ public PaginationCriteria getPaginationRequest() { PaginationCriteria pagination = new PaginationCriteria(); pagination.setPageNumber(this.getStart()); pagination.setPageSize(this.getLength()); SortBy sortBy = null; if(!AppUtil.isObjectEmpty(this.getOrder())) { sortBy = new SortBy(); sortBy.addSort(this.getOrder().getData(), SortOrder.fromValue(this.getOrder().getSortDir())); } FilterBy filterBy = new FilterBy(); filterBy.setGlobalSearch(this.isGlobalSearch()); for(DataTableColumnSpecs colSpec : this.getColumns()) { if(colSpec.isSearchable()) { if(!AppUtil.isObjectEmpty(this.getSearch()) || !AppUtil.isObjectEmpty(colSpec.getSearch())) { filterBy.addFilter(colSpec.getData(), (this.isGlobalSearch()) ? this.getSearch() : colSpec.getSearch()); } } } pagination.setSortBy(sortBy); pagination.setFilterBy(filterBy); return pagination; } /** The max params to check. */ private int maxParamsToCheck = 0; } |
You can see that constructor is calling another method that will process the HTTP request and prepare a complete datatable request. At the same time it has methods to prepare supporting information required for sorting, filtering and pagination is prepared.
The Controller
As this is a web project, we will add a controller that will display our data. We are using the Thymeleaf along with Spring Boot to server our web content.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
/** * */ package com.opencodez.controllers; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.google.gson.Gson; import com.opencodez.domain.User; import com.opencodez.domain.pagination.DataTableRequest; import com.opencodez.domain.pagination.DataTableResults; import com.opencodez.domain.pagination.PaginationCriteria; import com.opencodez.repo.UserRepository; import com.opencodez.util.AppUtil; /** * @author pavan.solapure * */ @Controller public class BaseController { @Autowired private UserRepository userRepo; /** The entity manager. */ @PersistenceContext private EntityManager entityManager; @RequestMapping(value="/users", method=RequestMethod.GET) public String listUsers(Model model) { return "users"; } @RequestMapping(value="/users/paginated", method=RequestMethod.GET) @ResponseBody public String listUsersPaginated(HttpServletRequest request, HttpServletResponse response, Model model) { DataTableRequest<User> dataTableInRQ = new DataTableRequest<User>(request); PaginationCriteria pagination = dataTableInRQ.getPaginationRequest(); String baseQuery = "SELECT id as id, name as name, salary as salary, (SELECT COUNT(1) FROM USER) AS totalrecords FROM USER"; String paginatedQuery = AppUtil.buildPaginatedQuery(baseQuery, pagination); System.out.println(paginatedQuery); Query query = entityManager.createNativeQuery(paginatedQuery, User.class); @SuppressWarnings("unchecked") List<User> userList = query.getResultList(); DataTableResults<User> dataTableResult = new DataTableResults<User>(); dataTableResult.setDraw(dataTableInRQ.getDraw()); dataTableResult.setListOfDataObjects(userList); if (!AppUtil.isObjectEmpty(userList)) { dataTableResult.setRecordsTotal(userList.get(0).getTotalRecords() .toString()); if (dataTableInRQ.getPaginationRequest().isFilterByEmpty()) { dataTableResult.setRecordsFiltered(userList.get(0).getTotalRecords() .toString()); } else { dataTableResult.setRecordsFiltered(Integer.toString(userList.size())); } } return new Gson().toJson(dataTableResult); } } |
In the above you can see when a request comes to this controller, datatable request, and pagination criteria that we need to pass to our data layer is prepared. After that using the pagination criteria which may contain sorting, filtering information a query is prepared and sent to execution for data. Below are both the queries base query and the one which gets prepared using the pagination information.
1 2 3 4 5 6 7 8 9 |
--Base Query SELECT id as id, name as name, salary as salary, (SELECT COUNT(1) FROM USER) AS totalrecords FROM USER --Query after adding pagination information SELECT FILTERED_ORDERD_RESULTS.* FROM (SELECT BASEINFO.* FROM ( SELECT id as id, name as name, salary as salary, (SELECT COUNT(1) FROM USER) AS totalrecords FROM USER ) BASEINFO ORDER BY id ASC ) FILTERED_ORDERD_RESULTS LIMIT 0, 5 |
Once results are back, datatable results are prepared which will have information about total records, filtered records, and actual data. This information is then converted to JSON and passed back to the client. Below is our User model, the data that get fetched and passed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/** * */ package com.opencodez.domain; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; /** * @author pavan.solapure * */ @Entity public class User { @Id private Long id; private String name; private String salary; @Column(name="totalrecords", updatable=false, insertable=false) private Integer totalRecords; } |
The View
Now we will see how we have our HTML and JavaScript put together. In HTML we need to put below js and CSS files in order to use datatable functionality
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Home</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" media="screen" /> <link th:href="@{../css/starter-template.css}" rel="stylesheet" media="screen" /> <link th:href="@{../css/datatables.min.css}" rel="stylesheet" media="screen" /> <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <script type="text/javascript" th:src="@{js/admin.js}"></script> <script type="text/javascript" th:src="@{../js/datatables.min.js}"></script> <script type="text/javascript" th:src="@{../js/fnSetFilteringEnterPress.js}"></script> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Datatable Demo</a> </div> </div> </nav> <div class="container"> <div class="starter-template"> <div class="table-responsive"> <table id="paginatedTable" class="table table-striped"> <thead> <tr> <th>Id</th> <th>Name</th> <th>Salary</th> </tr> </thead> </table> </div> </div> </div><!-- /.container --> </body> </html> |
And after we will initialize the datatable as shown below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$( document ).ready(function() { $('#paginatedTable').DataTable( { "processing": true, "serverSide": true, "pageLength": 5, "ajax": { "url": "/users/paginated", "data": function ( data ) { //process data before sent to server. }}, "columns": [ { "data": "id", "name" : "ID", "title" : "ID" }, { "data": "name", "name" : "Name" , "title" : "Name"}, { "data": "salary", "name" : "Salary" , "title" : "Salary"} ] }); $('#paginatedTable').dataTable().fnSetFilteringEnterPress(); }); |
Demo of Datatable
We are done with the code and config. Let’s see it working.
Default Rendering
Update:
Many people asked and trying to work this example with the Oracle database. I have added Oracle specific code to the same project. As this project is not equipped to connect to two database at the same time, I had to comment MySQL properties to connect with Oracle. (I know its pain, but I had to do it as I wanted to keep the focus of this article on Datatable and Oracle Integration.)
Change properties file to point to your Oracle database.
1 2 3 4 |
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe spring.datasource.username=pavans spring.datasource.password=****** spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver |
Refer file datatable.user.sql that is available in the source repository to create the table and sample data.
I have added couple of views and controllers to separea Oracle and MySQL flow.
The main change is how paginated query is built for Oracle.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public static String buildPaginatedQueryForOracle(String baseQuery, PaginationCriteria paginationCriteria) { StringBuilder sb = new StringBuilder("SELECT * FROM (SELECT FILTERED_ORDERED_RESULTS.*, COUNT(1) OVER() total_records, ROWNUM AS RN FROM (SELECT BASEINFO.* FROM ( #BASE_QUERY# ) BASEINFO ) FILTERED_ORDERED_RESULTS #WHERE_CLAUSE# #ORDER_CLASUE# ) WHERE RN > (#PAGE_NUMBER# * #PAGE_SIZE#) AND RN <= (#PAGE_NUMBER# + 1) * #PAGE_SIZE# "); String finalQuery = null; //Datatable start is set to 0, 5, 10 ..etc (5 is page size) //For oracle paginated query we need page start from 1,2,3 int pageNo = paginationCriteria.getPageNumber() / paginationCriteria.getPageSize(); paginationCriteria.setPageNumber(pageNo); if(!AppUtil.isObjectEmpty(paginationCriteria)) { finalQuery = sb.toString().replaceAll("#BASE_QUERY#", baseQuery) .replaceAll("#WHERE_CLAUSE#", ((AppUtil.isObjectEmpty(paginationCriteria.getFilterByClause())) ? "" : " WHERE ") + paginationCriteria.getFilterByClause()) .replaceAll("#ORDER_CLASUE#", paginationCriteria.getOrderByClause()) .replaceAll("#PAGE_NUMBER#", paginationCriteria.getPageNumber().toString()) .replaceAll("#PAGE_SIZE#", paginationCriteria.getPageSize().toString()); } return (null == finalQuery) ? baseQuery : finalQuery; } |
The above function takes pagination criteria into account and prepares the query for Oracle. You can not use the limit clause directly in Oracle, you have to rely on ROWNUM to limit the results. In this function, we calculate the page number and size and accordingly set them in the query.
I have done some minor changes to the domain object. You can refer them in source code.
Conclusion
I hope this example of datatable with Spring Boot will help you. You can download the source code and supporting SQL from our GitHub
hello i use a mysql database i use datatable all field value ok but date value return a object how to solve it?
like data : updatedAt
but return a object, in database updatedAt datatype is LocalDateTime
Great article, how can we put active link on the ID column of the data table ?
Thank you so much for this article and the code on github really helped. Appreciate your hard work.:)
Hello Pavan, Please Reply Fast
what is data in below? What is name , ID , titlle and ID in below ?
{ “data”: “id”, “name” : “ID”, “title” : “ID” },
{ “data”: “name”, “name” : “Name” , “title” : “Name”},
{ “data”: “salary”, “name” : “Salary” , “title” : “Salary”}
]
});
Null pointer exception in DataTableRequest.java in line :
for(DataTableColumnSpecs colSpec : this.getColumns()) {
if(colSpec.isSearchable()) {
if(!AppUtil.isObjectEmpty(this.getSearch()) || !AppUtil.isObjectEmpty(colSpec.getSearch())) {
filterBy.addFilter(colSpec.getData(), (this.isGlobalSearch()) ? this.getSearch() : colSpec.getSearch());
}
}
}
how do i fixed it? i used psql
hi, thanks for your tutorials,
i have one question
how to process data before sent to server that request filled and recocnize datatablerequest. please give me a sample of how to processing data for sending to server in ajax data.
thank you
I was trying to receive DataTableInput in controller, but I am unable to do that. Then I found this tutorial.
It’s really good,
Thanks
Glad you found it useful.
Hi!
Great tutorial, you saved me tons of working hours!
Glad you found it useful !
Keep Visiting ! Keep Learning !
Thank you for this tutorial.
I am running it in mysql and it works correctly.
Great!
SQL injection: Blind SQL Injection
Payload Boolean: columns[0][search][value]=%’ AND 1977=1977 AND ‘%’=’
How can I fix?
This has helped me alot in my project. Are you planning to update the code to match the latest version of Datatable as of now?
Thanks Sumit, Good to hear that the example was useful to you. If I update the code for any other database, I will surely let you know.
Just found an issue when searching for any value: if the resultset exceeds the max number of records per page, you will always just see the first page.
This is caused by line 79 of BaseController:
dataTableResult.setRecordsFiltered(Integer.toString(userList.size()));
The value returned by userList.size() is limited in SQL to the max number of records per page, so you’ll always get 1 page to view.
To solve this, I modified the base query adding a windowed count (with no partition) in order to count the number of filtered records, like this:
“SELECT FILTERED_ORDERD_RESULTS.* FROM (SELECT BASEINFO.*, COUNT(1) OVER () AS filtered_records FROM ( #BASE_QUERY# ) BASEINFO #WHERE_CLAUSE# ) FILTERED_ORDERD_RESULTS #ORDER_CLASUE# LIMIT #PAGE_NUMBER#, #PAGE_SIZE#”
Added the filtered_records property to my model object and then changed line 79 like this:
dataTableResult.setRecordsFiltered(modelList.get(0).getFilteredRecords().toString())
Worked for me!
Bye
Simon
Thanks, Simon for pointing this out.
I will try and change the code from our GIT.
This post is so usefult thank you.
By the way, I’m using MariaDB version 10.3.7 and it seems to ignore the ORDER BY clause in the inner select:
https://mariadb.com/kb/en/library/why-is-order-by-in-a-from-subquery-ignored/
Someone suggest putting a LIMIT 18446744073709551615 to the inner odered select to force it to get materialized, but this has performance issues.
However I tried taking out the ORDER BY clause in the outer FILTERED_ORDERD_RESULTS select and it seems to work.
SELECT FILTERED_ORDERD_RESULTS.* FROM (
SELECT BASEINFO.* FROM ( …) BASEINFO WHERE …
) FILTERED_ORDERD_RESULTS ORDER BY field1 ASC LIMIT 15, 5
Do you think it could be a good solution or am I wrong?
Thanks a lot!
Hi Simon, Glad you found it useful.
In the example, the query was built around MySQL. If the changes you did work correctly on MariaDB then that is good.
Hi Pavan,
I’m having a problem when do a searching on date column. Can you suggest a solution to this problem?
How can we integrate pipelining function in this project?
Hi,
I received an NullPointerExcention error at this point.
PaginationCriteria pagination = dataTableInRQ.getPaginationRequest();
and I think around this line = /*for(DataTableColumnSpecs colSpec : this.getColumns()) { */
Can you help me on this?
Hello
Are you running the code as is or you have added any customization as per your need?
I only took some of your code and try to run it on my existing program. Most of your code I copy from github and maybe some of it I took from this page. Would it be a problem if I did like that?
One more thing, help me understand this.
For the first time I display a datatable : request is null isnt it?
DataTableRequest dataTableInRQ = new DataTableRequest(request);
@Pavan,
It was my mistake, I tried to access the json using url and not by using datatable ajax. That’s why request is null. I’ve found the solution for my problems and I want to thank you for this great article. Thank you
Thanks Fidzrin, I am glad you found this useful.
One more thing, how do I make my custom Sort By Clause?
Right now it is based on my object Id, I want to change into something else, where can I do that sir?
hi fidzrin,i face the same problem.. can you tell me what is wrong, i test access json using url but it return null pointer exception
Great example. Is it possible to adjust search function it to work with table (model class) that have foreign key?
As its server-side sorting and filtering, you can prepare your query with as many tables as you may need.
Hi pavan ,
May I know how does the datatable know that these many results are there intially .
Hi Pavan,
I am using Oracle SQL.. i am getting SQL Command not properly ended.
Hi Prasad. Are you logging the final query some where? Can you check there is semicolon at the end of query?
Hi Pavan,
This is the query
SELECT FILTERED_ORDERD_RESULTS.* FROM (SELECT BASEINFO.* FROM ( SELECT txnid as txnid, amount as amount, (SELECT COUNT(1) FROM EmpDeatils) AS totalRecords FROM EmpDeatils ) BASEINFO ORDER BY txnid ASC ) FILTERED_ORDERD_RESULTS LIMIT 0, 5
and getting below error
WARN o.h.e.jdbc.spi.SqlExceptionHelper – SQL Error: 933, SQLState: 42000
ERROR o.h.e.jdbc.spi.SqlExceptionHelper – ORA-00933: SQL command not properly ended..
But in mysql same query working but in sql not working.
Kumar,
You can not use LIMIT 0, 5 in oracle. Thats MYSQL style. you need to re-build your query logic to use rownum for limiting the results.
Limit automatically setting in Code level na..So how can i change? is it possible?
Hi Kumar,
if you check the example is based on MySQL. You need to adapt the code for Oracle. Check AppUtil.java and in that method – buildPaginatedQuery
In this method, I am building a pagination query.
You may need to revisit and change this code to give you Oracle specific query.
Hi Pavan,
Just used ROWNUM replace of LIMIT. But Same error getting.
Please provide exact query for oracle
I have added code for Oracle as well. Request you to refer the Update section and latest code.
Hope this helps.
Hi Pavan,
my logic Changed to rownum.. but getting different types of errors.
For those wondering how to do it in Oracle:
ORDER BY field DESC OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
This would get 10 elements starting in the 20. Cheers
Hi Guillermo,
I have added code for Oracle as well. Request you to refer the Update section and latest code.
Hope this helps.
Hi i am getting below error,
java.lang.ClassNotFoundException: org.springframework.security.core.context.SecurityContextHolder
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_121]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_121]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_121]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_121]
at org.thymeleaf.extras.springsecurity4.auth.AuthUtils.getAuthenticationObject(AuthUtils.java:95) ~[thymeleaf-extras-springsecurity4-2.1.2.RELEASE.jar:2.1.2.RELEASE]
at org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect.getAdditionalExpressionObjects(SpringSecurityDialect.java:117) ~[thymeleaf-extras-springsecurity4-2.1.2.RELEASE.jar:2.1.2.RELEASE]
at org.thymeleaf.context.AbstractDialectAwareProcessingContext.computeExpressionObjects(AbstractDialectAwareProcessingContext.java:113) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.thymeleaf.context.AbstractProcessingContext.getExpressionObjects(AbstractProcessingContext.java:132) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.thymeleaf.spring4.expression.SpelVariableExpressionEvaluator.computeExpressionObjects(SpelVariableExpressionEvaluator.java:197) ~[thymeleaf-spring4-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.thymeleaf.spring4.expression.SpelVariableExpressionEvaluator.evaluate(SpelVariableExpressionEvaluator.java:115) ~[thymeleaf-spring4-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.thymeleaf.standard.expression.VariableExpression.executeVariable(VariableExpression.java:154) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:59) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:103) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:133) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:120) ~[thymeleaf-2.1.4.RELEASE.jar:2.1.4.RELEASE]
Hi Prasad,
Did you manage to solve this? Are you using the code from Github?
Hi Pavan,
I am trying to display “date” column in UI but i getting below error
DataTables warning: table id=paginatedTable – Requested unknown parameter ‘date’ for row 0, column 3. For more information about this error, please see http://datatables.net/tn/4
In my pojo class date column datatype is Date.
Hi Kumar,
Can you recheck your data mapping with Javascipt tabel column mapping. This kind of error generally pops up when a column does not get data from backend.
Where is “FILTERED_ORDERD_RESULTS” and BASEINFO Gotten from. I am confused
Hello friend, how can i put, edit and delete column ?
Hi Wallace,
You need to add corresponding columns in your html and the java script file where you are configuring or have defined the data table settings.
In our example: I would add column to users.html and corresponding settings will be changed in admin.js.
Once added you may have to add your business specific logic to control it.
Thanks
Pavan
Is there a pattern we could use so as to make this example more generic ?
I mean, now that the proof of concept is OK, I would like to use this solution for almost 40 controllers. That makes a lot of code duplication and forces to handle many servlet and servlet-mapping declaration in web.xml.
Pavan, would you have suggestions on how to achieve this ?
Best regards, Antoine
Hi Antoine,
With this POC, I tried to generalize
But I will try to give it some thought and see if I can come up with something.
In meantime, if you have improvised the POC, please share so others can also take benefit.
simple good
Hello, this is a great tutorial. Though I get a problem with search. I get only 1 page whatever I look for. Is there a way to fix this ?
Hi Antoine,
Did you check the query that gets formed in the background? Does that query returns results?
That was linked to Oracle DB commands. Had to revamp the way the query is formed.
I have added code for Oracle as well. Request you to refer the Update section and latest code.
Hope this helps.
org.postgresql.util.PSQLException: ERROR: LIMIT #,# syntax is not supported
Hint: Use separate LIMIT and OFFSET clauses.
Position: 324
postgresql: LIMIT 5 OFFSET 0 equivalent to LIMIT 0,5
another possibility is to use dandelion
only need to modify gradle or maven config to use thymeleaf 3… instead of 2…
Thanks, Marc. I will see if I can try this framework.
It’s simply great !!
Thanks, Vinodh.
Hi Pavan,
I have 5,00,000 records table.. i am trying to fetch all records at a time with search based… if it is possible or any performance related issue is there?
Hi Prasad,
Are you planning to show them at once? I hope not.
From database perspective, it may not affect performance if its simple select from table. But sending those records to client side and managing there would be costly.
I would suggest to only fetch thoses many which you want to show on the page.
Thanks
Pavan
Hi Pavan,
I have search option from front-end page with from date and to date. I am trying to get data between these two dates so that resulted data maximum one lack above. So what is the best way for me. Please suggest me.
When I executed this code it ask me to provide username and password to access any of the app url. Can you let me know that username and password.
Hi Sandeep, The code doesn’t have any security configuration. Are you trying to run the code as is from Git or you created a new project? Can you check if you accidentally added any security model?
please send me source code [email protected]
Hi Ajinkya,
You can find it in our GitHub repository – https://github.com/pavansolapure/opencodez-samples/tree/master/spring-boot-datatable
Hi-
I might be missing something here, but I don’t see the PaginationCriteria class defined anywhere, but it’s used in a few places in the code and listed in the file tree at the top. Can you explain where we would get this class?
Thanks.
Hi Mahedi,
If you are referring the code from GIT then you will find the class in /spring-boot-datatable/src/main/java/com/opencodez/domain/pagination/
Hi Pavan
Can you help me to write the pagination query generation for mssql server. Because it is not allowing order by inside views
Thanks, it helped me a lot but it has an error if you use underscore on your database column.
I’ve just resolved using @SerializedName(“database_fieldname”) on my Entity object. Hope it helps somebody else.
Thanks Frank. I am glad you found it useful.
hi,Can you explain how itself taking asc order?if i want to change orderby then what can i do sir?Kindly explain order
Hi Rizwana,
The data table when renders set lots of information in http request. The order by is also set in http request.
When we are preparing the pagination request we read all these variables from request and prepare column and table specification.
While preparing column specs we read order[0][dir] from request and set to that column. As we can have sorting on one column at a time this will be set as an order for table and inturn used while preparing the Pagination criteria. Check function – getPaginationRequest() in DataTableRequest.java.
Thank you so much.I got your point.And also Thanks a lot for sharing useful knowledge to us 🙂
one err query a table manytone
you help me
please mail me the details pavan.solapure at gmail.com
I resolved my problem before I had to sql custom in AppUtil.java “SELECT FILTERED_ORDERD_RESULTS. * FROM (SELECT BASEINFO. FROM FROM # (# BASE_QUERY #) BASEINFO # WHERE_CLAUSE ## ORDER_CLASUE #) FILTERED_ORDERD_RESULTS LIMIT # PAGE_NUMBER #, # PAGE_SIZE # = “SELECT BASEINFO. * FROM (# BASE_QUERY #) BASEINFO # WHERE_CLAUSE ## ORDER_CLASUE # LIMIT # PAGE_NUMBER #, # PAGE_SIZE #. Now, it’s perfect thank you much
i have the same problem..i use postgre.. can you help me?
Hi TrinhNguyen,
Are You using SQL?
Hi
thanks for this tutorial, Can you please write tutorial for spring mvc REST hibernate jquery datatable crud tutorial.
Sorry, i understan now. Delete my coments.
Can’t understand the magic about the “totalRecords” attr…
Can you explain where is setted? How does that works?
Thanks