Wednesday, October 30, 2013

ExtJS, Spring MVC 3 and Hibernate 3.5: CRUD DataGrid Example

09.03.2010
 | 56876 views | 
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:
1.// The new DataWriter component.
2.var writer = new Ext.data.JsonWriter({
3.encode: true,
4.writeAllFields: true
5.});
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:
01.var Contact = Ext.data.Record.create([
02.{name: 'id'},
03.{
04.name: 'name',
05.type: 'string'
06.}, {
07.name: 'phone',
08.type: 'string'
09.}, {
10.name: 'email',
11.type: 'string'
12.}]);
Now you need to setup a proxy like this one:
1.var proxy = new Ext.data.HttpProxy({
2.api: {
3.read : 'contact/view.action',
4.create : 'contact/create.action',
5.update: 'contact/update.action',
6.destroy: 'contact/delete.action'
7.}
8.});
FYI, this is how my reader looks like:
1.var reader = new Ext.data.JsonReader({
2.totalProperty: 'total',
3.successProperty: 'success',
4.idProperty: 'id',
5.root: 'data',
6.messageProperty: 'message'  // <-- code="" messageproperty="" meta-data="" new="">
7.},
8.Contact);
The Writer and the proxy (and the reader) can be hooked to the store like this:
01.// Typical Store collecting the Proxy, Reader and Writer together.
02.var store = new Ext.data.Store({
03.id: 'user',
04.proxy: proxy,
05.reader: reader,
06.writer: writer,  // <-- a="" as="" code="" datawriter="" into="" just="" plug="" reader="" store="" the="" would="" you="">
07.autoSave: false // <-- code="" create="" delay="" executing="" false="" update="" would="">
08.//destroy requests until specifically told to do so with some [save] buton.
09.});
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:
1.
2.<link rel="stylesheet" type="text/css" href="/extjs-crud-grid/ext-3.1.1/examples/ux/css/rowEditorCustom.css" />
3.<link rel="stylesheet" type="text/css" href="/extjs-crud-grid/ext-3.1.1/examples/shared/examples.css" />
4.<link rel="stylesheet" type="text/css" href="/extjs-crud-grid/ext-3.1.1/examples/ux/css/RowEditor.css" />
5. 
6.
7.<script src="/extjs-crud-grid/ext-3.1.1/examples/ux/RowEditor.js"></script>
Add the plugin on you grid declaration:
01.var editor = new Ext.ux.grid.RowEditor({
02.saveText: 'Update'
03.});
04. 
05.// create grid
06.var grid = new Ext.grid.GridPanel({
07.store: store,
08.columns: [
09.{header: "NAME",
10.width: 170,
11.sortable: true,
12.dataIndex: 'name',
13.editor: {
14.xtype: 'textfield',
15.allowBlank: false
16.}},
17.{header: "PHONE #",
18.width: 150,
19.sortable: true,
20.dataIndex: 'phone',
21.editor: {
22.xtype: 'textfield',
23.allowBlank: false
24.}},
25.{header: "EMAIL",
26.width: 150,
27.sortable: true,
28.dataIndex: 'email',
29.editor: {
30.xtype: 'textfield',
31.allowBlank: false
32.}})}
33.],
34.plugins: [editor],
35.title: 'My Contacts',
36.height: 300,
37.width:610,
38.frame:true,
39.tbar: [{
40.iconCls: 'icon-user-add',
41.text: 'Add Contact',
42.handler: function(){
43.var e = new Contact({
44.name: 'New Guy',
45.phone: '(000) 000-0000',
46.email: 'new@loianetest.com'
47.});
48.editor.stopEditing();
49.store.insert(0, e);
50.grid.getView().refresh();
51.grid.getSelectionModel().selectRow(0);
52.editor.startEditing(0);
53.}
54.},{
55.iconCls: 'icon-user-delete',
56.text: 'Remove Contact',
57.handler: function(){
58.editor.stopEditing();
59.var s = grid.getSelectionModel().getSelections();
60.for(var i = 0, r; r = s[i]; i++){
61.store.remove(r);
62.}
63.}
64.},{
65.iconCls: 'icon-user-save',
66.text: 'Save All Modifications',
67.handler: function(){
68.store.save();
69.}
70.}]
71.});

Java code

Finally, you need some server side code.
Controller:
01.package com.loiane.web;
02. 
03.@Controller
04.public class ContactController  {
05. 
06.private ContactService contactService;
07. 
08.@RequestMapping(value="/contact/view.action")
09.public @ResponseBody Mapextends Object> view() throwsException {
10. 
11.try{
12. 
13.List contacts = contactService.getContactList();
14. 
15.return getMap(contacts);
16. 
17.catch (Exception e) {
18. 
19.return getModelMapError("Error retrieving Contacts from database.");
20.}
21.}
22. 
23.@RequestMapping(value="/contact/create.action")
24.public @ResponseBody Mapextends Object> create(@RequestParamObject data) throws Exception {
25. 
26.try{
27. 
28.List contacts = contactService.create(data);
29. 
30.return getMap(contacts);
31. 
32.catch (Exception e) {
33. 
34.return getModelMapError("Error trying to create contact.");
35.}
36.}
37. 
38.@RequestMapping(value="/contact/update.action")
39.public @ResponseBody Mapextends Object> update(@RequestParamObject data) throws Exception {
40.try{
41. 
42.List contacts = contactService.update(data);
43. 
44.return getMap(contacts);
45. 
46.catch (Exception e) {
47. 
48.return getModelMapError("Error trying to update contact.");
49.}
50.}
51. 
52.@RequestMapping(value="/contact/delete.action")
53.public @ResponseBody Mapextends Object> delete(@RequestParamObject data) throws Exception {
54. 
55.try{
56. 
57.contactService.delete(data);
58. 
59.Map modelMap = new HashMap(3);
60.modelMap.put("success"true);
61. 
62.return modelMap;
63. 
64.catch (Exception e) {
65. 
66.return getModelMapError("Error trying to delete contact.");
67.}
68.}
69. 
70.private Map getMap(List contacts){
71. 
72.Map modelMap = new HashMap(3);
73.modelMap.put("total", contacts.size());
74.modelMap.put("data", contacts);
75.modelMap.put("success"true);
76. 
77.return modelMap;
78.}
79. 
80.private Map getModelMapError(String msg){
81. 
82.Map modelMap = new HashMap(2);
83.modelMap.put("message", msg);
84.modelMap.put("success"false);
85. 
86.return modelMap;
87.}
88. 
89.@Autowired
90.public void setContactService(ContactService contactService) {
91.this.contactService = contactService;
92.}
93. 
94.}


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:


01.package com.loiane.service;
02. 
03.@Service
04.public class ContactService {
05. 
06.private ContactDAO contactDAO;
07.private Util util;
08. 
09.@Transactional(readOnly=true)
10.public List getContactList(){
11. 
12.return contactDAO.getContacts();
13.}
14. 
15.@Transactional
16.public List create(Object data){
17. 
18.List newContacts = new ArrayList();
19. 
20.List list = util.getContactsFromRequest(data);
21. 
22.for (Contact contact : list){
23.newContacts.add(contactDAO.saveContact(contact));
24.}
25. 
26.return newContacts;
27.}
28. 
29.@Transactional
30.public List update(Object data){
31. 
32.List returnContacts = new ArrayList();
33. 
34.List updatedContacts = util.getContactsFromRequest(data);
35. 
36.for (Contact contact : updatedContacts){
37.returnContacts.add(contactDAO.saveContact(contact));
38.}
39. 
40.return returnContacts;
41.}
42. 
43.@Transactional
44.public void delete(Object data){
45. 
46.//it is an array - have to cast to array object
47.if (data.toString().indexOf('[') > -1){
48. 
49.List deleteContacts = util.getListIdFromJSON(data);
50. 
51.for (Integer id : deleteContacts){
52.contactDAO.deleteContact(id);
53.}
54. 
55.else //it is only one object - cast to object/bean
56. 
57.Integer id = Integer.parseInt(data.toString());
58. 
59.contactDAO.deleteContact(id);
60.}
61.}
62. 
63.@Autowired
64.public void setContactDAO(ContactDAO contactDAO) {
65.this.contactDAO = contactDAO;
66.}
67. 
68.@Autowired
69.public void setUtil(Util util) {
70.this.util = util;
71.}
72.}

Contact Class – POJO:

01.package com.loiane.model;
02. 
03.@JsonAutoDetect
04.@Entity
05.@Table(name="CONTACT")
06.public class Contact {
07. 
08.private int id;
09.private String name;
10.private String phone;
11.private String email;
12. 
13.@Id
14.@GeneratedValue
15.@Column(name="CONTACT_ID")
16.public int getId() {
17.return id;
18.}
19. 
20.public void setId(int id) {
21.this.id = id;
22.}
23. 
24.@Column(name="CONTACT_NAME", nullable=false)
25.public String getName() {
26.return name;
27.}
28. 
29.public void setName(String name) {
30.this.name = name;
31.}
32. 
33.@Column(name="CONTACT_PHONE", nullable=false)
34.public String getPhone() {
35.return phone;
36.}
37. 
38.public void setPhone(String phone) {
39.this.phone = phone;
40.}
41. 
42.@Column(name="CONTACT_EMAIL", nullable=false)
43.public String getEmail() {
44.return email;
45.}
46. 
47.public void setEmail(String email) {
48.this.email = email;
49.}
50.}

DAO Class:

01.package com.loiane.dao;
02. 
03.@Repository
04.public class ContactDAO implements IContactDAO{
05. 
06.private HibernateTemplate hibernateTemplate;
07. 
08.@Autowired
09.public void setSessionFactory(SessionFactory sessionFactory) {
10.hibernateTemplate = new HibernateTemplate(sessionFactory);
11.}
12. 
13.@SuppressWarnings("unchecked")
14.@Override
15.public List getContacts() {
16.return hibernateTemplate.find("from Contact");
17.}
18. 
19.@Override
20.public void deleteContact(int id){
21.Object record = hibernateTemplate.load(Contact.class, id);
22.hibernateTemplate.delete(record);
23.}
24. 
25.@Override
26.public Contact saveContact(Contact contact){
27.hibernateTemplate.saveOrUpdate(contact);
28.return contact;
29.}
30.}

Util Class:

01.package com.loiane.util;
02. 
03.@Component
04.public class Util {
05. 
06.public List getContactsFromRequest(Object data){
07. 
08.List list;
09. 
10.//it is an array - have to cast to array object
11.if (data.toString().indexOf('[') > -1){
12. 
13.list = getListContactsFromJSON(data);
14. 
15.else //it is only one object - cast to object/bean
16. 
17.Contact contact = getContactFromJSON(data);
18. 
19.list = new ArrayList();
20.list.add(contact);
21.}
22. 
23.return list;
24.}
25. 
26.private Contact getContactFromJSON(Object data){
27.JSONObject jsonObject = JSONObject.fromObject(data);
28.Contact newContact = (Contact) JSONObject.toBean(jsonObject, Contact.class);
29.return newContact;
30.}
31.)
32.private List getListContactsFromJSON(Object data){
33.JSONArray jsonArray = JSONArray.fromObject(data);
34.List newContacts = (List) JSONArray.toCollection(jsonArray,Contact.class);
35.return newContacts;
36.}
37. 
38.public List getListIdFromJSON(Object data){
39.JSONArray jsonArray = JSONArray.fromObject(data);
40.List idContacts = (List) JSONArray.toCollection(jsonArray,Integer.class);
41.return idContacts;
42.}
43.}
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!
Published at DZone with permission of Loiane Groner, author and DZone MVB.

5 comments:

raybanoutlet001 said...

fitflops sale
cheap air jordans
huarache shoes
nike huarache sale
cheap jordans
air jordan shoes
michael kors handbags
cheap jordans online
michael kors outlet
michael kors outlet
nike huarache
michael kors handbags,michael kors handbags clearance,michael kors clearance
nfl jerseys from china
true religion store
nmd adidas store
air jordan shoes
adidas yeezy boost
michael kors outlet online
http://www.outlettiffanyand.co
tiffany and co outlet
adidas stan smith
tiffany jewelry
http://www.oakleystoreonline.us.org
ugg outlet

jeje said...

Compte tenu de la récompense All-Star basket adidas zx flux pas cher cette année-là, la star du basket-ball était en route vers des choses plus grandes et meilleures. Dernièrement, au cours de l'entreprise de vêtements, il existe des possibilités illimitées à choisir. Les membres artificiels, les humanoïdes, les nombreux capteurs branchés sur le système, etc. Maintenir une mission claire (faisabilité d'une chaussure peu coûteuse), air jordan 1 pinnacle france un bon leadership, développer une bonne camaraderie entre les membres de l'équipe, sentir la responsabilité des résultats par tous les membres, assurer la croissance des membres autant comme équipe que dans leur vie personnelle. Tandis que la conception de asics nimbus homme solde ces sneakers est plus ou moins la même, vous découvrirez quelques détails qui sont utilisés pour distinguer les baskets Nike faux et réels. Des chemises de golf aux sacs d'entraînement, des chaussures de course au manteau d'hiver; Nike soutient fermement sa devise et continue à asics femme courir «FAIRE CE QUE C'EST.

saysse said...

informative post This Site navigate to this web-site this article he said Get More Info

phane said...

pop over here l8v66h0e58 replica louis vuitton bag replica goyard bags replica bags paypal fake hermes e5y47l4a66 replica bags nyc replica bags thailand site y6i64w1i92 replica bags blog

Unknown said...

o9i09h4l75 o9d86q5f69 d9u99h1u92 x3d99t0t45 v0j99o7x51 h2j17z0i22