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:
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()
throws
Exception {
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(
@RequestParam
Object 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(
@RequestParam
Object 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(
@RequestParam
Object 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!
5 comments:
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
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.
informative post This Site navigate to this web-site this article he said Get More Info
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
o9i09h4l75 o9d86q5f69 d9u99h1u92 x3d99t0t45 v0j99o7x51 h2j17z0i22
Post a Comment