Note: An updated version of this tutorial is now accessible at Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide
What is jqGrid?
jqGrid is an Ajax-enabled JavaScript control that provides solutions for representing and manipulating tabular data on the web. Since the grid is a client-side solution loading data dynamically through Ajax callbacks, it can be integrated with any server-side technology, including PHP, ASP, Java Servlets, JSP, ColdFusion, and Perl.Here's a screenshot of what we will be doing:
jqGrid uses a jQuery Java Script Library and is written as plugin for that package.
Source: http://www.trirand.com/jqgridwiki/doku.php
Our application is a simple CRUD system for managing a list of users. The presentation layer uses a jqGrid to display the data which is built on top of the JQuery, a great JavaScript framework. The business layer is composed of simple Spring beans annotated with @Controller and @Service. Our data is provided by an in-memory dummy list of users. Switching to a real data provider, like a database, should be easy enough. Notice in this tutorial I strive
to stick with simple POJO development. This makes the application easy to comprehend as well to debug. Comments are provided within the code to facilitate in the comprehension of this material.
Let's start by defining our domain.
Our domain is quite simple. It only contains a single object. We have a User class with three fields: id, firstName, lastName
package org.krams.tutorial.domain; /** * A simple POJO to represent our user domain * */ public class User { private Long id; private String firstName; private String lastName; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }Now we define our service layer.
The service handles the business logic of our application. It's provides CRUD operations for the User object, like adding, editing, deleting, and retrieving all users. Following good OOP practice we declare an interface first:
Our service implementation is a simple class annotated with the @Service to make it service, and @Transactional to make it transactional as well. Our service manipulates an in-memory array of users. Then init() method is the one responsible for initializing our dummy users.
Here's the service implementation:
/** * */ package org.krams.tutorial.service; import java.util.ArrayList; import java.util.List; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.krams.tutorial.domain.User; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * Handles CRUD services for users * */ @Service("userService") @Transactional public class UserService implements IUserService { private ListLet's move on to the controllers.dummyUsersList = new ArrayList (); protected static Logger logger = Logger.getLogger("service"); public UserService() { // Initialize our in-memory list of users init(); } public List getAll() { logger.debug("Retrieving all users"); return dummyUsersList; } public User get( String id ) { logger.debug("Retrieving an existing user"); return dummyUsersList.get( Integer.valueOf(id) ); } public Boolean add( User user ) { logger.debug("Adding a new user"); try { // Assign a new id user.setId( Long.valueOf(dummyUsersList.size()) ); dummyUsersList.add(user); return true; } catch (Exception e) { return false; } } public Boolean delete( User user ) { logger.debug("Deleting an existing user"); try { // Retrieve id to delete Long id = Long.valueOf( user.getId().toString() ); // Loop array for ( User dummyUser: dummyUsersList) { if ( dummyUser.getId().compareTo(id) == 0 ) { dummyUsersList.remove(dummyUser); break; } } return true; } catch (Exception e) { return false; } } public Boolean edit( User user ) { logger.debug("Editing an existing user"); try { // Retrieve id to edit Long id = Long.valueOf( user.getId().toString() ); // Loop array for ( User dummyUser: dummyUsersList) { if ( dummyUser.getId().compareTo(id) == 0 ) { dummyUser.setFirstName( user.getFirstName()); dummyUser.setLastName( user.getLastName()); break; } } return true; } catch (Exception e) { return false; } } private void init() { // Populate our in-memory, dummy list of users // Normally, the data should come from your DAOs or your persitence layer logger.debug("Init in-memory users"); User user = new User(); user.setId(Long.valueOf("1")); user.setFirstName("John"); user.setLastName("Smith"); dummyUsersList.add(user); user = new User(); user.setId(Long.valueOf("2")); user.setFirstName("Jane"); user.setLastName("Adams"); dummyUsersList.add(user); user = new User(); user.setId(Long.valueOf("3")); user.setFirstName("Jeff"); user.setLastName("Mayer"); dummyUsersList.add(user); } }
In this application we declare two controllers:
1. MediatorController
2. UserController
The purpose of the MediatorController is to handle and show the JSP page that contains the jqGrid itself. The JSP page is mapped to the URI template /main/users. To access the JSP page, you type the root path of your web application then followed by /main/users
Notice our controllers are simple classes annotated with @Controller and @RequestMapping. Same with the @Service annotation, this class becomes a Spring Controller that's capable to handle URI-template-based requests.
Here's the MediatorController:
package org.krams.tutorial.controller; import org.apache.log4j.Logger; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * Handles CRUD requests for users * */ @Controller @RequestMapping("/main") public class MediatorController { protected static Logger logger = Logger.getLogger("controller"); /** * Retrieves the JSP page that contains our JqGrid */ @RequestMapping(value = "/users", method = RequestMethod.GET) public String getUsersPage() { logger.debug("Received request to show users page"); // This will resolve to /WEB-INF/jsp/users.jsp page return "users"; } }On the other hand the UserController does not display any JSP page. It's job is to handle JSON request from the jqGrid and respond with JSON as well. The UserController receives the CRUD operations which it delegates to the UserService. When the UserService is done processing, the UserController responds back to the jqGrid.
Here's the UserController:
/** * */ package org.krams.tutorial.controller; import java.util.List; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.krams.tutorial.domain.User; import org.krams.tutorial.json.CustomGenericResponse; import org.krams.tutorial.json.CustomUserResponse; import org.krams.tutorial.service.IUserService; import org.springframework.stereotype.Controller; 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; /** * Handles CRUD requests for users * */ @Controller @RequestMapping("/crud") public class UserController { protected static Logger logger = Logger.getLogger("controller"); @Resource(name="userService") private IUserService userService; /** * The default method when a request to /users is made. * This essentially retrieves all users, which are wrapped inside a CustomUserResponse object. * The object is automatically converted to JSON when returning back the response. * The @ResponseBody is responsible for this behavior. */ @RequestMapping(method = RequestMethod.GET) public @ResponseBody CustomUserResponse getAll( ) { logger.debug("Received request to get all users"); // Retrieve all users from the service ListThe UserController has four mappings:users = userService.getAll(); // Initialize our custom user response wrapper CustomUserResponse response = new CustomUserResponse(); // Assign the result from the service to this response response.setRows(users); // Assign the total number of records found. This is used for paging response.setRecords( String.valueOf(users.size()) ); // Since our service is just a simple service for teaching purposes // We didn't really do any paging. But normally your DAOs or your persistence layer should support this // Assign a dummy page response.setPage( "1" ); // Same. Assign a dummy total pages response.setTotal( "10" ); // Return the response // Spring will automatically convert our CustomUserResponse as JSON object. // This is triggered by the @ResponseBody annotation. // It knows this because the JqGrid has set the headers to accept JSON format when it made a request // Spring by default uses Jackson to convert the object to JSON return response; } /** * Edit the current user. */ @RequestMapping(value = "/edit", method = RequestMethod.POST) public @ResponseBody CustomGenericResponse edit( @RequestParam("id") String id, @RequestParam("firstName") String firstName, @RequestParam("lastName") String lastName ) { logger.debug("Received request to edit user"); // Construct our user object // Assign the values from the parameters User user = new User(); user.setId( Long.valueOf(id) ); user.setFirstName(firstName); user.setLastName(lastName); // Do custom validation here or in your service // Call service to edit Boolean success = userService.edit(user); // Check if successful if ( success == true ) { // Success. Return a custom response CustomGenericResponse response = new CustomGenericResponse(); response.setSuccess(true); response.setMessage("Action successful!"); return response; } else { // A failure. Return a custom response as well CustomGenericResponse response = new CustomGenericResponse(); response.setSuccess(false); response.setMessage("Action failure!"); return response; } } /** * Add a new user */ @RequestMapping(value = "/add", method = RequestMethod.POST) public @ResponseBody CustomGenericResponse add( @RequestParam("firstName") String firstName, @RequestParam("lastName") String lastName ) { logger.debug("Received request to add a new user"); // Construct our new user object. Take note the id is not required. // Assign the values from the parameters User user = new User(); user.setFirstName(firstName); user.setLastName(lastName); // Do custom validation here or in your service // Call service to add Boolean success = userService.add(user); // Check if successful if ( success == true ) { // Success. Return a custom response CustomGenericResponse response = new CustomGenericResponse(); response.setSuccess(true); response.setMessage("Action successful!"); return response; } else { // A failure. Return a custom response as well CustomGenericResponse response = new CustomGenericResponse(); response.setSuccess(false); response.setMessage("Action failure!"); return response; } } /** * Delete an existing user */ @RequestMapping(value = "/delete", method = RequestMethod.POST) public @ResponseBody CustomGenericResponse delete( @RequestParam("id") String id ) { logger.debug("Received request to delete an existing user"); // Construct our user object. We just need the id for deletion. // Assign the values from the parameters User user = new User(); user.setId( Long.valueOf(id) ); // Do custom validation here or in your service // Call service to add Boolean success = userService.delete(user); // Check if successful if ( success == true ) { // Success. Return a custom response CustomGenericResponse response = new CustomGenericResponse(); response.setSuccess(true); response.setMessage("Action successful!"); return response; } else { // A failure. Return a custom response as well CustomGenericResponse response = new CustomGenericResponse(); response.setSuccess(false); response.setMessage("Action failure!"); return response; } } }
/crud/add /crud/edit /crud/delete /crud
To make an add request, a jqGrid should call the /crud/add URI template. To make an edit request, call the /crud/edit URI template. And so forth.
When you call a get request from the Spring Controller, here's the exact JSON data that's being transported:
You can easily retrieve this data by calling directly the JSON controller via a third-party tool. I use RESTClient by WizTools to verify the response. Here's a screenshot of the tool:
You can download the tool at RESTClient
The UserController has two types of response:
1. CustomGenericResponse
2. CustomUserResponse
These responses are custom POJO classes that I created. The idea of these classes is to contain JSON object within a Java class. It's easier to manipulate a Java object than a JSON object inside Java. The conversion from JSON to Java is done automatically by Spring! It uses Jackson to do the conversion.
Here's the CustomGenericResponse:
The CustomUserResponse is a wrapper containing an array of users, along with some extra data used by a jqGrid, like paging, total records, and alike. The reasoning for the structure of this class is dictated by the standard parameters that a jqGrid expects. Check the following jqGrid doc jqGrid JSON format
Here's CustomUserResponse:
Let's move on to the JSP page.
The JSP page contains the jqGrid. I added custom buttons on the grid itself. The jqGrid declaration below has some extra features that we will not be using for this tutorial. I put them here anyway just in case I write another tutorial utilizing these extra features.
Here's a screenshot of these custom buttons:
On the body of the JSP, we declare the following:
users.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" media="screen" href="/spring-jqgrid-integration/resources/css/jquery/ui-lightness/jquery-ui-1.8.6.custom.css" /> <link rel="stylesheet" type="text/css" media="screen" href="/spring-jqgrid-integration/resources/css/jqgrid/ui.jqgrid.css" /> <script type="text/javascript" src="/spring-jqgrid-integration/resources/js/jquery/jquery-1.4.4.min.js"></script> <script type="text/javascript"> var jq = jQuery.noConflict(); </script> <script type="text/javascript" src="/spring-jqgrid-integration/resources/js/jquery/jquery-ui-1.8.6.custom.min.js"></script> <script type="text/javascript" src="/spring-jqgrid-integration/resources/js/jqgrid/grid.locale-en.js" ></script> <script type="text/javascript" src="/spring-jqgrid-integration/resources/js/jqgrid/jquery.jqGrid.min.js"></script> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>JqGrid - Spring 3 MVC Integration Tutorial</title> </head> <body > <script type="text/javascript"> jq(function() { jq("#grid").jqGrid({ url:'/spring-jqgrid-integration/krams/crud', datatype: 'json', mtype: 'GET', colNames:['Id', 'First Name', 'Last Name'], colModel:[ {name:'id',index:'id', width:55,editable:false,editoptions:{readonly:true,size:10},hidden:true}, {name:'firstName',index:'lastName', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}}, {name:'lastName',index:'firstName', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}} ], postData: { }, rowNum:20, rowList:[20,40,60], height: 200, autowidth: true, rownumbers: true, pager: '#pager', sortname: 'id', viewrecords: true, sortorder: "asc", caption:"Users", emptyrecords: "Empty records", loadonce: false, loadComplete: function() { }, jsonReader : { root: "rows", page: "page", total: "total", records: "records", repeatitems: false, cell: "cell", id: "id" } }); jq("#grid").jqGrid('navGrid','#pager', {edit:false,add:false,del:false,search:true}, { }, { }, { }, { sopt:['eq', 'ne', 'lt', 'gt', 'cn', 'bw', 'ew'], closeOnEscape: true, multipleSearch: true, closeAfterSearch: true } ); jq("#grid").navButtonAdd('#pager', { caption:"Add", buttonicon:"ui-icon-plus", onClickButton: addRow, position: "last", title:"", cursor: "pointer" } ); jq("#grid").navButtonAdd('#pager', { caption:"Edit", buttonicon:"ui-icon-pencil", onClickButton: editRow, position: "last", title:"", cursor: "pointer" } ); jq("#grid").navButtonAdd('#pager', { caption:"Delete", buttonicon:"ui-icon-trash", onClickButton: deleteRow, position: "last", title:"", cursor: "pointer" } ); jq("#btnFilter").click(function(){ jq("#grid").jqGrid('searchGrid', {multipleSearch: false, sopt:['eq']} ); }); // Toolbar Search jq("#grid").jqGrid('filterToolbar',{stringResult: true,searchOnEnter : true, defaultSearch:"cn"}); }); </script> <script type="text/javascript"> function addRow() { // Get the currently selected row jq("#grid").jqGrid('editGridRow','new', { url: "/spring-jqgrid-integration/krams/crud/add", editData: { }, recreateForm: true, beforeShowForm: function(form) { }, closeAfterAdd: true, reloadAfterSubmit:false, afterSubmit : function(response, postdata) { var result = eval('(' + response.responseText + ')'); var errors = ""; if (result.success == false) { for (var i = 0; i < result.message.length; i++) { errors += result.message[i] + "<br/>"; } } else { jq("#dialog").text('Entry has been added successfully'); jq("#dialog").dialog( { title: 'Success', modal: true, buttons: {"Ok": function() { jq(this).dialog("close");} } }); } // only used for adding new records var new_id = null; return [result.success, errors, new_id]; } }); } function editRow() { // Get the currently selected row var row = jq("#grid").jqGrid('getGridParam','selrow'); if( row != null ) jq("#grid").jqGrid('editGridRow',row, { url: "/spring-jqgrid-integration/krams/crud/edit", editData: { }, recreateForm: true, beforeShowForm: function(form) { }, closeAfterEdit: true, reloadAfterSubmit:false, afterSubmit : function(response, postdata) { var result = eval('(' + response.responseText + ')'); var errors = ""; if (result.success == false) { for (var i = 0; i < result.message.length; i++) { errors += result.message[i] + "<br/>"; } } else { jq("#dialog").text('Entry has been edited successfully'); jq("#dialog").dialog( { title: 'Success', modal: true, buttons: {"Ok": function() { jq(this).dialog("close");} } }); } return [result.success, errors, null]; } }); else jq( "#dialogSelectRow" ).dialog(); } function deleteRow() { // Get the currently selected row var row = jq("#grid").jqGrid('getGridParam','selrow'); // A pop-up dialog will appear to confirm the selected action if( row != null ) jq("#grid").jqGrid( 'delGridRow', row, { url: '/spring-jqgrid-integration/krams/crud/delete', recreateForm: true, beforeShowForm: function(form) { //change title jq(".delmsg").replaceWith('<span style="white-space: pre;">' + 'Delete selected record?' + '</span>'); //hide arrows jq('#pData').hide(); jq('#nData').hide(); }, reloadAfterSubmit:false, closeAfterDelete: true, afterSubmit : function(response, postdata) { var result = eval('(' + response.responseText + ')'); var errors = ""; if (result.success == false) { for (var i = 0; i < result.message.length; i++) { errors += result.message[i] + "<br/>"; } } else { jq("#dialog").text('Entry has been deleted successfully'); jq("#dialog").dialog( { title: 'Success', modal: true, buttons: {"Ok": function() { jq(this).dialog("close");} } }); } // only used for adding new records var new_id = null; return [result.success, errors, new_id]; } }); else jq( "#dialogSelectRow" ).dialog(); } </script> <p>JqGrid - Spring 3 MVC Integration Tutorial</p> <div id="jqgrid"> <table id="grid"></table> <div id="pager"></div> </div> <div id="dialog" title="Feature not supported" style="display:none"> <p>That feature is not supported.</p> </div> <div id="dialogSelectRow" title="Warning" style="display:none"> <p>Please select row</p> </div> </body> </html>
For the Javascript functions, addRow, editRow, deleteRow, each declares a custom URL. For example, the deleteRow declares the following URL:
This URL corresponds the controller delete URI template: /crud/delete.
Another important setting you must look at is the jsonReader we declared inside the jqGrid:
jsonReader : { root: "rows", page: "page", total: "total", records: "records", repeatitems: false, cell: "cell", id: "id" }It turns out all you need to declare among those properties is the repeatitems: false. You can remove the root, page, total, records, cell, and id. The application will still run. I believe jqGrid has an internal naming convention that it expects. By default if your JSON data has the following format:
Then it's following convention. Try changing the rows to something like arbirtrary, i.e mydog. Your grid will not show any data.
If that's the case, make sure you set the root property in your jsonReader like the following:
jsonReader : { root: "mydog", repeatitems: false }Another important setting you must be wary of is the colModel names.
Our jqGrid expects the following colModel names:
colModel:[ {name:'id', ...} {name:'firstName', ...}, {name:'lastName, ...} ],These names must exactly match the properties you're passing in your JSON data. It's case sensitive! FIRSTNAME and firstName are not the same names!
Thanks to Oleg for pointing these nuances. He's the guy I consider expert when it comes to jqGrid. He's an active guy in www.stackoverflow.com. Ask a jqGrid question there and he'll more than likely answer it.
Of course, you need to add the JQuery and jqGrid library on the head section of your JSP. Otherwise, you won't see any grids. Make sure the path is correct.
I need to point one critical JQuery configuration, however. If you notice on standard JQuery examples, most use the $, but in this tutorial you don't see that sign! Instead you see the jq. The jq and $ are equivalent. To force JQuery to use a different identifier, declare the following on the head section of your JSP:
Let's return to Spring.
Typical with any Spring application, we must declare a few required beans in the xml configuration.
applicationContext.xml
spring-servlet.xml
web.xml
Take note of the URL pattern. When accessing any pages in our MVC application, the host name must be appended withspring org.springframework.web.servlet.DispatcherServlet 1 spring /krams/* org.springframework.web.context.ContextLoaderListener
/krams
Run the Application
To run the application, please use the following URL:http://localhost:8080/spring-jqgrid-integration/krams/main/users
Some reminders.
1. Download the Jackson library and put it in your classpath.
2. Download the JQuery framework and put it in your resources folder
3. Download the jqGrid plugin .
4. You may need to customize the URLs declared in the JSP
The best way to learn further is to try the actual application.
Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/jqgrid-spring3mvc-integration-tutorial/
You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run
You can download the project as a Maven build. Look for the spring-jqgrid-integration.zip in the Download sections.
Share the joy:
|
Subscribe by reader Subscribe by email Share
Thanks so much posting such a detailed tutorial! It is really useful. Just a note that the code pasted for Custom User Response class is CustomGenericResponse. Can you please post the CustomUserResonse class instead?
ReplyDelete@JP, thanks for pointing that out. I've updated the tutorial with the correct CustomUserResponse. Just to point out, if you look at the CustomUserResponse rows fields you can easily change the type using Generics.
ReplyDeleteI'm glad you liked the tutorial. This is my way of thanking the open-source community for helping me as well in just about everything.
Thanks! Chris
ReplyDeleteI've just uploaded a Maven version of the project. Enjoy
ReplyDeleteyou can process data to insert hibernate by extending this tutorial.
ReplyDelete@Anonymous, yes, you can use Hibernate to access your data.
ReplyDeletei am getting the oddest error......that googling didnt resolve:
ReplyDeleteserver side:
[DEBUG] [http-8080-exec-9 01:29:29] (AbstractHandlerExceptionResolver.java:resolveException:132) Resolving exception from handler [org.krams.tutorial.controller.UserController@9c176c]: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
[DEBUG] [http-8080-exec-9 01:29:29] (AbstractHandlerExceptionResolver.java:resolveException:132) Resolving exception from handler [org.krams.tutorial.controller.UserController@9c176c]: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
[DEBUG] [http-8080-exec-9 01:29:29] (AbstractHandlerExceptionResolver.java:resolveException:132) Resolving exception from handler [org.krams.tutorial.controller.UserController@9c176c]: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
[DEBUG] [http-8080-exec-9 01:29:29] (DispatcherServlet.java:doDispatch:824) Null ModelAndView returned to DispatcherServlet with name 'spring': assuming HandlerAdapter completed request handling
[DEBUG] [http-8080-exec-9 01:29:29] (FrameworkServlet.java:processRequest:674) Successfully completed request
client side (with the help of wiztools): The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers
headers being set
accept:json
ok, figured it out:
ReplyDeletehad to add:
and the jackson-all.jar
hmm....bean stuff didnt add....
ReplyDeletei added a message adapter like this this thread:
http://forum.springsource.org/showthread.php?t=89618
@Eric, you don't really need to add the adapter as long as you have the tag. That tag declares the same AnnotationMethodHandlerAdapter. I assume you're using the latest Spring 3.0.5 jars?
ReplyDeleteThe tag I was referring to mvc:annotation-driven
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteThank you very much krams..this help me alot..i got some deployment issues when i used your maven version. but i was able to plug this grid to a working spring mvc 3 sample..anyhow my grid won't sort when i click on the col name. and also it wnt get filtered when i type some letters in the toolbar search box ( jst above the column header ) can you please give me some advice?
ReplyDelete@Sam, yes that's right. The grid won't sort and filter. That's because I purposely didn't enable that feature in the tutorial to stay within the scope of the tutorial. Maybe it's time for me to write a FULL jqGrid tutorial. To make the filtering work, you will need to retrieve the values as request parameters and you'll have to convert them to your database's language.
ReplyDeleteappreciate your effort krams..I went through JQgrid wiki and saw the parameter called 'soratable'. i set it to true but still it wnt sort.am new to this JQgrid thing and spring 3.after saw your cutting edge tutorials i loved to play with those..full jqgrid tutorial will be really helpful krams..Thanks again for your great effort and time..
ReplyDeletedoesn't work for me.
ReplyDeletefirst to make it work on tomcat i had to put all sort of jars on the classpath and when trying to run the project a 404 error page is shown.
doesn't work, when i'm trying to run users.jps, it returns the 404 page. (link: http://hostname/spring-jqgrid-integration/krams/users).
ReplyDeleteThe User Controller work when i lunch http://hostname/spring-jqgrid-integration/krams/crud it returns the user list as json.
Thanks
Hi krams, i have also tried to run the mvn project, but when i happen to access,spring-jqgrid-integration/krams/users it gives me 404 error. it has not yet worked for me. where could the problem be?
ReplyDeletethanks
gbro
I just tried with Maven and Tomcat by running "mvn tomcat:run", and it works. The URL I used is http://localhost:8080/spring-jqgrid-integration/krams/main/users
ReplyDeleteThanks for the feedback krams. This tutorial can be very useful for me...could you please add configuration tips step by step ?
ReplyDeletedon't I need to change the jdbc properties file ?
build a particular database...
thanks a lot
If you need an actual database, all you'll need is change the Service layer so-that instead of doing an in-memory manipulation of data, you delegate to your database. Remember jqGrid is only for the presentation layer. If you need help on configuring, MVC and JDBC check my tutorial: Spring 3 MVC - JDBC Integration Tutorial or Spring MVC 3, Hibernate Annotations, MySQL Integration Tutorial (See the Tutorials section)
ReplyDeleteAlso, have you looked at my tutorial: Spring 3: Dynamic MVC using jqGrid and MongoDB (See the Tutorials section)? This uses a NoSQL database. But the principle still applies for JDBC. I know I owe my readers a full jqGrid, JDBC tutorial :)
ReplyDeleteHello krams, great tutorial finally, but I have problems deploying my .war, I'm trying to deploy this to jboss server, I get this error while starting it "org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userService' is defined: not found in JNDI environment" , maybe you had this experience before?
ReplyDelete@c0mrade, you would do better if you ask this in the Spring forums (in the Web thread). I know there are some issues with JBoss, but I just can't remember the solution
ReplyDelete[DEBUG] [http-8080-1 11:12:45] (FrameworkServlet.java:processRequest:671) Could not complete request
ReplyDeletejavax.servlet.ServletException: Circular view path [users]: would dispatch back to the current handler URL [/spring-jqgrid-integration/krams/main/users] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
Running tomcat 6.032/J2SE 6.023. As others have noted, the json url's are fine.
Thanks for the tute, btw. Good stuff.
Seems like a viewResolver issue. InternalResourceViewResolver is forwarding/redirecting to "/spring-jqgrid-integration/krams/main/users" instead of "/WEB-INF/jsp/users.jsp".
ReplyDeleteIf I hardcode "forward:/WEB-INF/jsp/users.jsp" it works fine.
I see this (not sure if related):
[DEBUG] [main 01:15:17] (AbstractAutowireCapableBeanFactory.java:createBean:458) Finished creating instance of bean 'org.springframework.web.servlet.view.InternalResourceViewResolver'
[DEBUG] [main 01:15:17] (DispatcherServlet.java:initViewResolvers:584) No ViewResolvers found in servlet 'spring': using default
Still investigating.
More logs (in context):
ReplyDelete[DEBUG] [http-8080-1 01:15:25] (AbstractAutowireCapableBeanFactory.java:invokeInitMethods:1461) Invoking afterPropertiesSet() on bean with name 'users'
[DEBUG] [http-8080-1 01:15:25] (DispatcherServlet.java:render:1045) Rendering view [org.springframework.web.servlet.view.JstlView: name 'users'; URL [users]] in DispatcherServlet with name 'spring'
[DEBUG] [http-8080-1 01:15:25] (FrameworkServlet.java:processRequest:671) Could not complete request
javax.servlet.ServletException: Circular view path [users]: would dispatch back to the current handler URL [/spring-jqgrid-integration/krams/main/users] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
added viewNames property to the viewResolver and set the list value as "users"
ReplyDeleteworks fine now.
This comment has been removed by the author.
ReplyDeleteHi all, what do i need to implement a dyanamic dropdpwn list. i want to pull data from the database and allow a user to select a category that is in my db.
ReplyDeleteI am also tryn to figure out how to show the value of an id. i.e. i pull data that has a referenced field so to show the user the value i use itemClass.classname and there i have the class name displayed other than the id. Saving becames a problem coz i get an error 400. I would love to save the id again not the name.
OK. successfully implemented the drop down using dataUrl and buildselect.
ReplyDeleteAnyone with an example for a dynamic drop down in which i select a country and it loads the second drop down with cities then cities fires a dropdown with its states. Will be so greatful for your help.
Thanks buddy!!!! I was looking exactly for this to start my internal project perfect maven rocks no issue while executing it...
ReplyDeleteThanks once again.... keep up the good work....
hi,
ReplyDeleteI am trying this code in our spring roo based project.
this code is note working ..
Please advise me as per as soon....
hi, may i know how to convert @ResponseBody Spring 3 to Spring 2 ?
ReplyDeleteHi Krams,
ReplyDeleteThanks for this post.
I got the code working for me. I have a quick question here. Why a "blank row" appearing on the top of the grid. Is this a default nature of jqgrid. How can we stop showing the blank row in the page.
Thanks.
@Prasad, are you referring to the blank row where you can enter text? If that's the one, that's the toolbar search feature of jQgrid. You can disable it. But if you want to use it, you need to provide an implementation on your Controller to handle the search filters
ReplyDeleteWhat should I include in pom and manifest to use jackson 1.9 in osgi? in springsource repo i fiund only 1.4.3
ReplyDeletereally good one.M going to try this out
ReplyDeletehey kram,
ReplyDeletei am a newbie to jqgrid and finding difficulty to integrate with a JDBC instead of in memory DB,
Can u help??
problem
#1 - how to provide pagination info to spring??
#2 - i am using mybatis for mapping will there be any changes??
Thanks in advance..!
Awaiting reply.
Hi,
ReplyDeletehow can i remove the first empty rows can you Please help me
how can we remove the first row
ReplyDeleteGreat tutorial, thanks.
ReplyDeleteHaving bit of a weird problem. Got it working with JDBC(MySQL DB). All fine except...
The Add/Edit/Delete buttons and the first empty row not showing up on the grid.
Other than DB changes , haven't changed any of the front-end - any idea what could be wrong??
Cheers
Scratch that - must have inadvertently done something to mess up the js. Grid all working now.
ReplyDeleteThanks for the tut!!
Somebody work with jqGrid and TILES ? i don't know how can i do it :(
ReplyDeleteHi,
ReplyDeleteGreat tutorial, thanks.
I've got a probleme. The grid isn't load. I haven't any error message with IE9 and Chrome. With FireFox this error is written
NetworkError: 406 Inacceptable - http://localhost:8080/englishAnnotation/do/crud?_search=false&nd=1327010598446&rows=20&page=1&sidx=id&sord=asc
the url is good. In the eclipse console, I see logger trace for :
23:03:17 [DEBUG] (MediatorController.java:getUsersPage:17) Recieved request to show users page
23:03:18 [DEBUG] (Usercontroller.java:getAll:26) Recieve request to get all users
23:03:18 [DEBUG] (UserService.java:getAll:21) Retrieve all Users
Do you have any idea ?
Thanks
I found the problem. It was because I miss to put jackson-mapper-asl-1.9.3.jar, jackson-core-asl-1.9.3.jar in the classpath
Deletehi, i get my data as json on the page but my grid is not being displayed what could be wrong ?? please HELP !!!
ReplyDelete@Anonymous, I suggest you use Chrome and enable the Developer Tools; then check the Console output for errors. Also, check your web server's logs, i.e Tomcat. It's either you got the grid setup wrong or your Controller mapping is wrong, but since you can get the data, I would put my two cents on the grid setup (your HTML/JSP page)
ReplyDeleteHi Krams, Thanks for this nice work here.
ReplyDeleteI tried this on eclipse(3.7 indigo with jdk1.7) by importing as an existing maven project then I tried run tomcat 7 .
But tomcat is stoping here :INFO: Initializing Spring root WebApplicationContext.
It looks like the web.xml is not there but I checked it is there.
Any suggestion please.
Best Regards.
@Anonymous, can you try instead importing this more updated tutorial: http://krams915.blogspot.com/2012/01/spring-mvc-31-jqgrid-and-spring-data_1887.html
ReplyDeleteHi Krams,
ReplyDeleteI tried to run the above code in this site, but the below error is occured in local browser, so kindly help me
HTTP Status 404 -
type Status report
message
description The requested resource () is not available.
Apache Tomcat/5.5.31
I am not using , Manually deploying the code in Tomcat.
I am not using maven,Manually deploying the code in Tomcat.
ReplyDelete@Kraj, you have to check the logs in your Tomcat log directory and extract the exact error message. Preferrably, you provide the complete stacktrace. You can copy and paste the error at http://pastebin.com/. Then post the link here so we can further investigate.
ReplyDeleteThanks for this tutorial. I'm curious, though, what rules govern the passing of data from the cellEdit functions in jqGrid to the Spring container?
ReplyDeleteMore specifically, is the "rule" to basically define a @RequestParam for each value on your colModel? The jqGrid documents state:
"What is posted to the server?
When the data is posted to the server we construct object {} that contain:
the name:value pair where the name is the name of the input element represented in the cell
additionally we add a pair id:rowid where the rowid is the id of the row
if the returned data from beforeSubmitCell event is not empty we extend this data with the posted data."
To me, this suggests more than just individual string objects are coming back from jqGrid. Your example above defines @RequestParam for each column model and apparently that works.
In my code, I'm getting an Error 400 when I sent the jqGrid data to my Controller. Clearly I'm doing something wrong...
@Learning, if you have the extra time, I suggest you read a more updated version of this guide at http://krams915.blogspot.com/2012/01/spring-mvc-31-jqgrid-and-spring-data_1887.html
ReplyDeletejqGrid has its own rules for passing data, but you can modify the data that is passed. You will have to read the JavaScript source of jqGrid to know the internal details. But there are hooks that allow you to pass extra parameters.
For Spring, the basic rule is you just match the field names from jqGrid to your Spring DTO. The best way to check which fields are passed is to use your browser's developer tools, ie Firebug.
Hi Krams, thank you for this tutorial, I am learning Spring MVC, I like your tutorial, I imported this project to eclipse, run it, it's working, but only add link is working, But all the others (edit, delete, find) are not working.
ReplyDeleteThanks, your help is appreciated.
Hi Krams, How to implement simple pagination with your example. I have read your other blog where you've explained JQpagination with help of JpaRepository page. But my application we are using complex sql and using JDBCTemplate for executing SQLs. So, i am not sure how to implement simple pagination with this. Any information on this will be helpful for me.
ReplyDeleteThanks,
Karthick
For the life of me, I couldn't pass this error,
ReplyDeletelooks like a bug in Spring data, I am sure you have passed it, can you share,
I am using jdk 1.7, and maven 3.03, on 64 bit machine.
I understand the error, but if it works for every one I must have missed something.
error: name clash: save(Iterable(? extends T#1)) in JpaRepository and (S)save(Iterable(S)) in CrudRepository have the same erasure, yet neither overrides the other
David,
DeleteIn the POM use:
1.1.1.RELEASE instead of:
1.1.0.RC1
The released version fixes the type erasure bug.
Alberto Acevedo
Thank you for such a great article, you saved my day.
ReplyDeleteYou should also check the more updated article "Spring MVC 3.1, jqGrid, and Spring Data JPA Integration Guide" http://krams915.blogspot.com/2012/01/spring-mvc-31-jqgrid-and-spring-data_1887.html
DeleteIt works, but it appears to be a bug in Javascript. Once a number of items are created, then one is deleted and another one is created, it stops working correctly.
ReplyDeleteCan this be fixed? I'd like to use this somple version without JPA.
Thanks
Mark Serrano, thanks! mabuhay ka! ^_^
ReplyDeleteHi Krams,
ReplyDeleteNavigation part is not working for me. What I've to do to activate tht to push record on next page if it's > 10 or 20..
it is not displayed to the gris , it is only showing row of data . what did i miss. i need herl
ReplyDeleteHello Krams
ReplyDeleteWhat is license type for your tutorials?
I am going to develop example in Spring framework for our jQuery Widget and your jqGrid tutorial is very close to what I need. So I want to refit it for our needs.
Our core product is commercial, but our demos are released under jQuery license:
Sergey Nikolayev
They don't have any official license. Use it anyway you want it. You can mention my name or not (it wouldn't matter). You can use it for commercial or personal use. No hidden costs :-)
Deleteonly the Json String values are displayed ({"records":"2","total":"10","rows" ....) what did i miss?
ReplyDeleteDid you use the sample project or are you trying to implement the feature for a new project?
DeleteHey I am new to jqgrid and i have a problem that i'm not able to get data from the dummylist, i'm hitting the url as "http://localhost:7001/integration-spring-jqgrid/krams/main/users". In Fire Bug it is showing NullPointerException, here's the stack trace
ReplyDeletejava.lang.NullPointerException
at org.krams.tutorial.controller.UserController.getAll(UserController.java:46)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:592)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:550)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:743)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:857)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:283)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:176)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3272)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2019)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:1925)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1394)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:181)
Everything is at it is as given in your tutorial. Please help
Hi,
ReplyDeleteI have 2 independent jqgrids on a jsp page, boths have a checkbox to only choose one row.
the code of each one is on a independent div but when i click into a row on the 2º grid it selects the same one havin on the first grid having the same index, but when i check directly in the checkbox this doesn't happen, any suggestion for resolving this. thx to yo for responding.
HI Krams, In the above example how to send json object using jquery in Users.jsp to spring mvc controller while ADD, UPDATE and DELETE operations.
ReplyDeleteCould you please send this example
Krams you give so many examples why dont you use pagination in your own site for this comments part?
ReplyDeleteHi Krams, thank you for this tutorial, I am learning Spring MVC, I like your tutorial, I imported this project to eclipse, run it, it's working, but only add link is working, But all the others (edit, delete, find) are not working.
ReplyDeletePlease any help is appreciated.
The tutorial you posted here was awesome!
ReplyDeleteI wish you can post other tutorial out here for some novice spring developers to promote themselves up to professional.
May God bless you and your precious share..
Hi Krams i have a question: When we load data using /CRUD and it got error, so how could we though the message to View layer get it. I mean using @ResponseBody so i can't add error message to Model to View get it to display
ReplyDeletePlease any help is appreciated.
Hello,
ReplyDeleteThank you for your articles!
It's very nice example of spring and jquery data table for me.
And good job.
Great review!
ReplyDeleteHTTP status 406
ReplyDelete"The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers."
Sorry it is resolved
ReplyDeleteJust need to add this line on my controller
@RequestMapping(method = RequestMethod.GET,headers = {"Accept=text/xml, application/json"})
Hi Krams - I wonder how added values are getting shown into the UI without storing into DB ?
ReplyDeleteI have read your blog its very attractive and impressive. I like it your blog.
ReplyDeleteSpring online training Spring online training Spring Hibernate online training Spring Hibernate online training Java online training
spring training in chennai spring hibernate training in chennai
Thanks for sharing this valuable information.
ReplyDeletejava projects in chennai
dotnet projects in chennai
mba projects in chennai
be projects in chennai
ns2 projects in chennai
ReplyDeletevery nice and informative blog
dot net training in chennai
java training in chennai
Hi, author, nice post. thanks. you need to remove the last comment on December 14, 1016 at 3:04 am.
ReplyDeleteTranslation of some links, all are kind of same:
link: Company for cleaning apartments in Riad city.
link: Cleaning Houses in Riad City
link: Best company of cleaning in Riad city.
all are like that
You should write a source in your artcles.
ReplyDeleteBest BCA Colleges in Noida
is this sample still up-to-date/practical as per latest technology?
ReplyDeleteGood Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
ReplyDeletecore java training in Electronic City
Hibernate Training in electronic city
spring training in electronic city
java j2ee training in electronic city
Thanks for the informative article About Android. This is one of the best resources I have found in quite some time. Nicely written and great info. I really cannot thank you enough for sharing.
ReplyDeleteJava training in chennai | Java training in annanagar | Java training in omr | Java training in porur | Java training in tambaram | Java training in velachery
Effective blog with a lot of information. I just Shared you the link below for Courses .They really provide good level of training and Placement,I just Had Spring Classes in this institute,Just Check This Link You can get it more information about the Spring course.
ReplyDeleteJava training in chennai | Java training in annanagar | Java training in omr | Java training in porur | Java training in tambaram | Java training in velachery
We have seen many blog but this the great one, Thanks for provide great informatic and looking beautiful blog, really nice required information & the things i never imagined and i would like to request, wright more blog and blog post like that for us. Thanks you once agian
ReplyDeletebirth certificate in delhi
birth certificate in noida
birth certificate in ghaziabad
birth certificate in gurgaon
correction in birth certificate
marriage registration in delhi
marriage certificate delhi
how to change name in 10th marksheet
marriage registration in ghaziabad
marriage registration in gurgaon
Aivivu chuyên vé máy bay, tham khảo
ReplyDeletesăn vé máy bay giá rẻ đi Mỹ
vé máy bay từ mỹ về việt nam mùa dịch
vé máy bay từ tpHCM đi Los Angeles
khi nào có chuyến bay từ canada về việt nam
Hey there
ReplyDeleteThanks for sharing this wonderful post, Keep on updating more like this
Software Development company
Mobile app development company
Best web development company
Great post. keep sharing such a worthy information.
ReplyDeleteافضل سهم استثماري يوزع ارباح على المساهمين هو ما يبحث عنه معظم المستثمرين
ReplyDeletepalm angels clothing
ReplyDeleteyeezy outlet
supreme
curry shoes
goyard bag
supreme outlet
nike sb dunk low
golden goose sneakers
golden goose sale
kd shoes
I love the podcasts available on this site.
ReplyDelete