ExtJS, Spring MVC 3 and Hibernate 3.5: CRUD DataGrid Example
This tutorial will walk through how to implement a CRUD (Create, Read, Update, Delete) DataGrid using ExtJS, Spring MVC 3 and Hibernate 3.5.
What do we usually want to do with data?
- Create (Insert)
- Read / Retrieve (Select)
- Update (Update)
- Delete / Destroy (Delete)
Until ExtJS 3.0 we only could READ data using a dataGrid. If you wanted to update, insert or delete, you had to do some code to make these actions work. Now ExtJS 3.0 (and newest versions) introduces the ext.data.writer, and you do not need all that work to have a CRUD Grid.
So… What do I need to add in my code to make all these things working together?
In this example, I’m going to use JSON as data format exchange between the browser and the server.
ExtJS Code
First, you need an Ext.data.JsonWriter:
// The new DataWriter component.
var writer = new Ext.data.JsonWriter({
encode: true,
writeAllFields: true
});
Where writeAllFields identifies that we want to write all the fields from the record to the database. If you have a fancy ORM then maybe you can set this to false. In this example, I’m using Hibernate, and we have saveOrUpate method – in this case, we need all fields to updated the object in database, so we have to ser writeAllFields to true. This is my record type declaration:
var Contact = Ext.data.Record.create([
{name: 'id'},
{
name: 'name',
type: 'string'
}, {
name: 'phone',
type: 'string'
}, {
name: 'email',
type: 'string'
}]);
Now you need to setup a proxy like this one:
var proxy = new Ext.data.HttpProxy({
api: {
read : 'contact/view.action',
create : 'contact/create.action',
update: 'contact/update.action',
destroy: 'contact/delete.action'
}
});
FYI, this is how my reader looks like:
var reader = new Ext.data.JsonReader({
totalProperty: 'total',
successProperty: 'success',
idProperty: 'id',
root: 'data',
messageProperty: 'message' // <-- New "messageProperty" meta-data
},
Contact);
The Writer and the proxy (and the reader) can be hooked to the store like this:
// Typical Store collecting the Proxy, Reader and Writer together.
var store = new Ext.data.Store({
id: 'user',
proxy: proxy,
reader: reader,
writer: writer, // <-- plug a DataWriter into the store just as you would a Reader
autoSave: false // <-- false would delay executing create, update, destroy requests until specifically told to do so with some [save] buton.
});
Where autosave identifies if you want the data in automatically saving mode (you do not need a save button, the app will send the actions automatically to the server). In this case, I implemented a save button, so every record with new or updated value will have a red mark on the cell left up corner). When the user alters a value in the grid, then a “save” event occurs (if autosave is true). Upon the “save” event the grid determines which cells has been altered. When we have an altered cell, then the corresponding record is sent to the server with the ‘root’ from the reader around it. E.g if we read with root “data”, then we send back with root “data”. We can have several records being sent at once. When updating to the server (e.g multiple edits). And to make you life even easier, let’s use the RowEditor plugin, so you can easily edit or add new records. All you have to do is to add the css and js files in your page:
<!-- Row Editor plugin css --> <link rel="stylesheet" type="text/css" href="/extjs-crud-grid/ext-3.1.1/examples/ux/css/rowEditorCustom.css" /> <link rel="stylesheet" type="text/css" href="/extjs-crud-grid/ext-3.1.1/examples/shared/examples.css" /> <link rel="stylesheet" type="text/css" href="/extjs-crud-grid/ext-3.1.1/examples/ux/css/RowEditor.css" /> <!-- Row Editor plugin js --> <script src="/extjs-crud-grid/ext-3.1.1/examples/ux/RowEditor.js"></script>
Add the plugin on you grid declaration:
var editor = new Ext.ux.grid.RowEditor({
saveText: 'Update'
});
// create grid
var grid = new Ext.grid.GridPanel({
store: store,
columns: [
{header: "NAME",
width: 170,
sortable: true,
dataIndex: 'name',
editor: {
xtype: 'textfield',
allowBlank: false
}},
{header: "PHONE #",
width: 150,
sortable: true,
dataIndex: 'phone',
editor: {
xtype: 'textfield',
allowBlank: false
}},
{header: "EMAIL",
width: 150,
sortable: true,
dataIndex: 'email',
editor: {
xtype: 'textfield',
allowBlank: false
}})}
],
plugins: [editor],
title: 'My Contacts',
height: 300,
width:610,
frame:true,
tbar: [{
iconCls: 'icon-user-add',
text: 'Add Contact',
handler: function(){
var e = new Contact({
name: 'New Guy',
phone: '(000) 000-0000',
email: 'new@loianetest.com'
});
editor.stopEditing();
store.insert(0, e);
grid.getView().refresh();
grid.getSelectionModel().selectRow(0);
editor.startEditing(0);
}
},{
iconCls: 'icon-user-delete',
text: 'Remove Contact',
handler: function(){
editor.stopEditing();
var s = grid.getSelectionModel().getSelections();
for(var i = 0, r; r = s[i]; i++){
store.remove(r);
}
}
},{
iconCls: 'icon-user-save',
text: 'Save All Modifications',
handler: function(){
store.save();
}
}]
});
Java code
Finally, you need some server side code.
Controller:
package com.loiane.web;
@Controller
public class ContactController {
private ContactService contactService;
@RequestMapping(value="/contact/view.action")
public @ResponseBody Map<String,? extends Object> view() throws Exception {
try{
List<Contact> contacts = contactService.getContactList();
return getMap(contacts);
} catch (Exception e) {
return getModelMapError("Error retrieving Contacts from database.");
}
}
@RequestMapping(value="/contact/create.action")
public @ResponseBody Map<String,? extends Object> create(@RequestParam Object data) throws Exception {
try{
List<Contact> contacts = contactService.create(data);
return getMap(contacts);
} catch (Exception e) {
return getModelMapError("Error trying to create contact.");
}
}
@RequestMapping(value="/contact/update.action")
public @ResponseBody Map<String,? extends Object> update(@RequestParam Object data) throws Exception {
try{
List<Contact> contacts = contactService.update(data);
return getMap(contacts);
} catch (Exception e) {
return getModelMapError("Error trying to update contact.");
}
}
@RequestMapping(value="/contact/delete.action")
public @ResponseBody Map<String,? extends Object> delete(@RequestParam Object data) throws Exception {
try{
contactService.delete(data);
Map<String,Object> modelMap = new HashMap<String,Object>(3);
modelMap.put("success", true);
return modelMap;
} catch (Exception e) {
return getModelMapError("Error trying to delete contact.");
}
}
private Map<String,Object> getMap(List<Contact> contacts){
Map<String,Object> modelMap = new HashMap<String,Object>(3);
modelMap.put("total", contacts.size());
modelMap.put("data", contacts);
modelMap.put("success", true);
return modelMap;
}
private Map<String,Object> getModelMapError(String msg){
Map<String,Object> modelMap = new HashMap<String,Object>(2);
modelMap.put("message", msg);
modelMap.put("success", false);
return modelMap;
}
@Autowired
public void setContactService(ContactService contactService) {
this.contactService = contactService;
}
}
Some observations:
In Spring 3, we can get the objects from requests directly in the method parameters using @RequestParam. I don’t know why, but it did not work with ExtJS. I had to leave as an Object and to the JSON-Object parser myself. That is why I’m using a Util class – to parser the object from request into my POJO class. If you know how I can replace Object parameter from controller methods, please, leave a comment, because I’d really like to know that!
Service Class:
package com.loiane.service;
@Service
public class ContactService {
private ContactDAO contactDAO;
private Util util;
@Transactional(readOnly=true)
public List<Contact> getContactList(){
return contactDAO.getContacts();
}
@Transactional
public List<Contact> create(Object data){
List<Contact> newContacts = new ArrayList<Contact>();
List<Contact> list = util.getContactsFromRequest(data);
for (Contact contact : list){
newContacts.add(contactDAO.saveContact(contact));
}
return newContacts;
}
@Transactional
public List<Contact> update(Object data){
List<Contact> returnContacts = new ArrayList<Contact>();
List<Contact> updatedContacts = util.getContactsFromRequest(data);
for (Contact contact : updatedContacts){
returnContacts.add(contactDAO.saveContact(contact));
}
return returnContacts;
}
@Transactional
public void delete(Object data){
//it is an array - have to cast to array object
if (data.toString().indexOf('[') > -1){
List<Integer> deleteContacts = util.getListIdFromJSON(data);
for (Integer id : deleteContacts){
contactDAO.deleteContact(id);
}
} else { //it is only one object - cast to object/bean
Integer id = Integer.parseInt(data.toString());
contactDAO.deleteContact(id);
}
}
@Autowired
public void setContactDAO(ContactDAO contactDAO) {
this.contactDAO = contactDAO;
}
@Autowired
public void setUtil(Util util) {
this.util = util;
}
}
Contact Calss – POJO:
package com.loiane.model;
@JsonAutoDetect
@Entity
@Table(name="CONTACT")
public class Contact {
private int id;
private String name;
private String phone;
private String email;
@Id
@GeneratedValue
@Column(name="CONTACT_ID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(name="CONTACT_NAME", nullable=false)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name="CONTACT_PHONE", nullable=false)
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Column(name="CONTACT_EMAIL", nullable=false)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
DAO Class:
package com.loiane.dao;
@Repository
public class ContactDAO implements IContactDAO{
private HibernateTemplate hibernateTemplate;
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
hibernateTemplate = new HibernateTemplate(sessionFactory);
}
@SuppressWarnings("unchecked")
@Override
public List<Contact> getContacts() {
return hibernateTemplate.find("from Contact");
}
@Override
public void deleteContact(int id){
Object record = hibernateTemplate.load(Contact.class, id);
hibernateTemplate.delete(record);
}
@Override
public Contact saveContact(Contact contact){
hibernateTemplate.saveOrUpdate(contact);
return contact;
}
}
Util Class:
package com.loiane.util;
@Component
public class Util {
public List<Contact> getContactsFromRequest(Object data){
List<Contact> list;
//it is an array - have to cast to array object
if (data.toString().indexOf('[') > -1){
list = getListContactsFromJSON(data);
} else { //it is only one object - cast to object/bean
Contact contact = getContactFromJSON(data);
list = new ArrayList<Contact>();
list.add(contact);
}
return list;
}
private Contact getContactFromJSON(Object data){
JSONObject jsonObject = JSONObject.fromObject(data);
Contact newContact = (Contact) JSONObject.toBean(jsonObject, Contact.class);
return newContact;
}
)
private List<Contact> getListContactsFromJSON(Object data){
JSONArray jsonArray = JSONArray.fromObject(data);
List<Contact> newContacts = (List<Contact>) JSONArray.toCollection(jsonArray,Contact.class);
return newContacts;
}
public List<Integer> getListIdFromJSON(Object data){
JSONArray jsonArray = JSONArray.fromObject(data);
List<Integer> idContacts = (List<Integer>) JSONArray.toCollection(jsonArray,Integer.class);
return idContacts;
}
}
If you want to see all the code (complete project will all the necessary files to run this app), download it from my GitHub repository: http://github.com/loiane/extjs-crud-grid-spring-hibernate
This was a requested post. I’ve got a lot of comments from my previous CRUD Grid example and some emails. I made some adjustments to current code, but the idea is still the same. I hope I was able answer all the questions.
Happy coding!
Comments (54)
Links to this Post
- ExtJS and Spring MVC Framework: CRUD DataGrid Example | Loiane Groner | September 2, 2010
- extjstutorial.org | May 4, 2011
- JavaPins | January 8, 2012









Hi Loiane,
this is a very good and clean post.
I think it could be even better if you tried it in a more RESTful manner. And it is very close (code-wise) to what you have already. Just a few annotations to change and setup the store properly.
To get the object into the controller without using your Util class you need the @RequestBody annotation. Then if you have Jackson configured as a message converter and client set header Content-Type as ‘application/json’ to the request, Spring does the job automatically.
Check this post http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
Regards,
Aggelos
@ Aggelos
I tried to implement RESTful grid once, but because of that issue, I did not work. I’m going to try again.
Thanks for the answer!
To map the JSON that you submit to a method parameter on your @Controller, you need to be using @RequestBody, not @RequestParam, and you need the Jackson library in your app. That will cause the body of the request to be marshalled via a MappingJacksonHttpMessageConverter.
See this blog entry from SpringSource which contains an example.
http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
@AndyC
Thanks for the answer!
I cannot download the Example.
Please help!!!
@Abhaya
If you already installed Git, just run this command:
git clone git://github.com/loiane/extjs-crud-grid-spring-hibernate.git
@Loiane
Hi, very nice blog with many useful information. Thanx for tutorials!
Hi Loiane, gr8 tutorial, although there are some things which did not understand like where from which part of the code in crud-grid.js does the code create.action gets called? i.e after store.save() how does it reach create.action?
Secondly the modelMap returned from the controller where does it go to in the crud-grid.js
Thanks in advance & Regards
Mudassar Hakim
Hola Loiane, yo recien comienzo con Extjs y me parece estupendo, gracias por el aporte de este tutorial, espero poder hacerte algunas consultas mas adelante, gracias.
Uno de los mejores ejemplos que he visto te agradezco es lo que buscaba .
Gracias !
I’d like to pass some data from extjs to controllers view() method. When I change view method definition to :
public @ResponseBody Map view(@RequestParam Object data)
extjs shows error. Is it possible to pass some parameters (and read them) to the view method ?
@mrs
yes, but you have to use @requestbody instead of @requestparam.
I still did not find out why we get error with requestparam.
@Loiane
I think I had the same problem with @RequestBody when I tried to use the restful api of both spring and extjs’ store.
Ext’s JsonWriter by default posts data to the request’s body like this:
data={property: value, property2: etc}
Where ‘data’ is what you set as root in the extjs’ configuration. But Jackson (and Spring) try to unmarshal the object from the body in plain json like this:
{property: value, property2: etc}
So (I didn’t find any other way and) I created a PlainJsonWriter extending JsonWriter’s render method to send only the json… and everyone is happy now!
Regards,
Aggelos
great post. i also wanna share a spoon-fed tutorial on Hibernate integration to spring mvc 3.0 for newbies like me
http://www.adobocode.com/spring/adding-crud-capability-to-spring-mvc
hope this helps.
Thank for tutorials……
@Aggelos, @Loiane
use Writer and just set root to ” that will plain the requestBody to {..} instead of data={…}.
Excellent article! Really clear! I agreed with a RESTfull example would help even more! Keep the good work!
This is awesome!
I am having trouble with hibernate for implementing a crud grid where the table has foreign keys using the same frameworks as the example. Any advice?
nice article.
@elmasse: Can you pls explain me more how to do this with @Requestbody annotation?
Thanks
Janaka
İ ‘ve some problems that are firstly i dont connect my extjs project with mysql.And i dont know how to do ıt.
second,i wanna use java codes( by hibernate) sql and extjs.i connect java-mysql but i dont link extjs how to do ıt???
thx alot..
Great work Loiane. I have a question.
I modified writeAllFields to false. So that it should update modified field. I changed contact name. But it throws following error, “Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.loiane.model.Contact.email”. Why does it check email?
Please let me know how to fix it.
how are u writing the Ext JS code in eclipse. I found it difficult as I have to remember all the attributes, there is not auto help (like when you type the Ctrl+space normally it used to give the list of attributes or methods in eclipse). I dont find this for ext js (plugin for eclipse).
I tried with Sptket plugin for eclipse but it doesnt solve the problem, i still have to remember all the attributes and methods,
is anyone successful in this ??
I use Sptket plugin for eclipse. And I keep the documentation opened in a browser as well.
Very helpful! Thanks for taking the time to write and publish this.
Hi Loiane,
this example is very userful to me, i want this code to study,but i can’t find it on internet. Can you send it to my email? taoo_hades@hotmail.com.
thank you !
Hi Hades, you can download it from the github repository. On the right up corner, there is a download button.
Hi Hades, you can click on the download button and download the code. Thanks!
HI LoINA YOUR BLOG IS SO SUPER PLS UPDATE THE EXAMPLE FOR FUTURE
hi superb your blog pleas Update it for intrest
Thanks Loiane…..very great job
Hello Loiane, Great post there. I tried downloading the code to run on JBOSS 5.1GA and cant seem to get it to start i get all sorts of errors related to hibernate.properties and mapping errors although i changed the Tomcat7 dependencies to JBOSS 5. any ideas what i need to do to make it run ?
thanks.
Hi paul,
Are you trying to deploy it with a war file or from an IDE?
Noob here.Very nice job but i have a problem.When i run the project on server i get the error message ERROR org.hibernate.util.JDBCExceptionReporter – Access denied for user ‘root’@'localhost’ (using password: YES). The problem is that i execute the sql file but i cant make any changes to the database from the grid.So i think is a Tomcat problem.Any idea?
Hi panls,
Can you pls post your hibernate configuration file?
You opened my noobish fuckin eyes.Had to open db-config.xml in a text editor and type my root password.Thnx Loiane Greetings from Greece.
Hi Loiane!!! Thank you very much!!!
But, there are some things which did not understand like @mudassar…
I would greatly appreciate someone answer this:
“which part of the code in crud-grid.js does the code create.action gets called? i.e after store.save() how does it reach create.action?Secondly the modelMap returned from the controller where does it go to in the crud-grid.js”
Thanks, really!!
Hi CarlosL,
This is done internally by ExtJS, so I cannot indicate to you where in the code this is happening.
Take a look at the Store class documentation and try to understand how it works.
I can also indicate two link from my blog where I try to explain some of these concepts:
http://loianegroner.com/2009/12/getting-started-with-extjs-datagrid/
http://loianegroner.com/2010/03/extjs-and-spring-mvc-framework-crud-datagrid-example/
Thanks!
Very good example! Do you have any plans in doing this same example using Extjs 4?
I am new to Extjs and I am looking into using version 4. Thank you.
Hi Nick,
Yes, I am going to port my examples to ExtJS 4 when I have some time.
Thanks!
super post!!!
Hello @Loiane, thank you very much, really!But one doubt me, I’ve been watching the web page says @AndyC and don’t understand … ie, just change the @requestparam for @requestbody? and how to remove the part where you call util.class?
if someone has done it, I would like to see how classes are modified.I’m new and i’m lost.
Thank you very much if someone has it!!!!
Super post!!!
Hello @Loiane, thank you very much, really!But one doubt me, I’ve been watching the web page says @AndyC and I don’t understand … ie, just change the @requestparam for @requestbody? and how to remove the part where you call util.class?
If someone has done it, I would like to see how classes are modified.I’m new and i’m lost.
Thank you very much if someone has it!!!!
Hi Chals,
I implemented a new example and removed the util class.
Please check it out: https://github.com/loiane/ext4-crud-mvc
Thanks!
Hii @loiane!!! Many thanks, really!
Loiane check the SyntaxHighlighter dont wroking good ..
Nice blog !
Hi @Loiane!! One question in the Ext JS 4 example tha you’ve post without using the Utils.class, why do you use the ContactWrapper class? When you create, delete or edit a contact could you use “@RequestBody Contact data” instead of “@RequestBody ContactWrapper data” ?? If I change it the program give me an error.
Anyway I would like to know why is necessary to use the ContactWrapper class in order to get the parameter without errors. Thanks in advance!!
Marckba
Hi marckba,
You can use a wrapper class instead of getting each parameter from the request.
I implemented an example demonstrating how to do it: https://github.com/loiane/ext4-crud-mvc
Thanks!
Yeah!! I’ve seen this example.
What I would like to know if there is any way to instead of using the ContactWrapper use the Contact object directly without using the wrapper.. In your example the code for create action will be like this:
public @ResponseBody Map create(@RequestBody Contact data) throws Exception {
try{
List contacts = contactService.create(data);
!!
return ExtJSReturn.mapOK(contacts);
} catch (Exception e) {; return ExtJSReturn.mapError(“Error trying to create contact.”); } }
The fact is that this does not work because jackson library doesn’t know who to parse it. Do you know which would be the solution? Or why I can’t use the Contact Bean directly? Because In the reader and writer of the store I’m indicating that the model is Contact.
Thanks in advance again
Nothing was showing and no error in the logs when I built and deployed the project
Hi lakes,
Did you follow all the steps? Did you execute the script into the db?
Thanks!
Thank you every much,that’s what I need!
Cool. But have a question. In project you does not have Hibernate mapping file… All work without him?
Hi Alex,
I am using annotations in the project, so you do not need to use xml mapping file.
Thanks