Informática -> Spring + ExtJS - Grid CRUD

ExtJS e Spring Framework: Exemplo de um CRUD Grid

Este tutorial demonstra como implementar um CRUD Grid (Create, Read, Update, Delete) usando ExtJS e Spring Framework

O que geralmente queremos fazer com os dados

  • Create (Criar) – (Insert)
  • Read (Ler/Visualizar) – (Select)
  • Update (Atualizar) – (Update)
  • Delete (Deletar) – (Delete)

Até a versão 3.0 do ExtJS, podíamos apenas LER dados utilizando o componente dataGrid. Se você quisesse fazer um update, insert ou delete, você tinha que codificar funções específicas para essas ações no lado ExtJS. Com a versão 3.0 (e versões mais recentes) do ExtJS, a biblioteca javascript introduziu o ext.data.writer, e você não tem todo aquele trabalho de criar as funções específicas, pode utilizar o Writer para ter um CRUD Grid.

Mas o que é preciso para ter todas as funcionalidades funcionando apenas com o uso desse writer?

No exemplo desse tutorial, estou usando JSON como formato de dados para troca de informações entre brwoser e servidor.

Primeiro, é preciso criar um Ext.data.JsonWriter:

1// The new DataWriter component.
2 var writer = new Ext.data.JsonWriter({
3 encode: true,
4 writeAllFields: false
5 });

Onde writeAllFields significa que queremos enviar todos os campos do registro para o banco de dados. identifies that we want to write all the fields from the record to the database. Se você tem uma estrutura de dados um pouco complicada ou o usuário irá fazer muitas iterações de update, é melhor deixar setado como false.

Por exemplo, Essa é a declaração da minha estrutura de dados no ExtJS:

01var 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}, {
13 name: 'birthday',
14 type: 'date',
15 dateFormat: 'm/d/Y'
16}]);

Se eu apenas atualizar o nome do contato, a aplicação irá apenas enviar o nome do contato e a id do mesmo para o servidor dizendo que foi atualizado (se o campo writeallfields estiver como false). Se tiver setado como true, irá enviar todos os campos, e o trabalho para descobrir o que sofreu alteração ficará para o server.

Agora, é necessário configurar o proxy, como esse:

1var 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});

E só para constar, é assim que meu reader se parece:

1var reader = new Ext.data.JsonReader({
2 totalProperty: 'total',
3 successProperty: 'success',
4 idProperty: 'id',
5 root: 'data',
6 messageProperty: 'message' // <-- New "messageProperty" meta-data
7},
8Contact);

O próximo passo é juntat tudo (writer, proxy e reader) no objeto store:

1// Typical Store collecting the Proxy, Reader and Writer together.
2 var store = new Ext.data.Store({
3 id: 'user',
4 proxy: proxy,
5 reader: reader,
6 writer: writer, // <-- plug a DataWriter into the store just as you would a Reader
7 autoSave: false // <-- false would delay executing create, update, destroy requests until specifically told to do so with some [save] buton.
8 });

O autosave significa que deseja salvar as alterações automaticamente no servidor (não precisa de um botão salvar na tela, assim que o usuário atualizar, deleter ou criar um novo dado, será enviado automaticamente para o servidor). Para este exemplo, implementei um botão salvar, assim, qualquer registro ou dado que for adicionado ou alterado terá uma marcação vermelha (no canto superior esquerdo da célula), assim quando o evento (ou botão) salvar for disparado, serão enviados para o servidor os dados que sofreram alteração (marcados com o flag vermelho). Você pode fazer múltiplos updates e enviar todos para o servidor em apenas uma vez (Observe como isso foi tratado no código da classe de serviço no código fonte desse projeto).

E para deixar a vida ainda mais fácil (afinal, pra isso que usamos bibliotecas como ExtJS :D ), vamos usar o plugin RowEditor, que permite a edição dos dados de forma muito simples. Tudo o que precisa fazer para usar esse plugin é primeiro adicionar os arquivos necessários na sua página HTML (ou JSP, ou outra extensão!):

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>

E adicionar o plugin na declaração do grid:

01var editor = new Ext.ux.grid.RowEditor({
02 saveText: 'Update'
03});
04
05// create grid
06var 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 {header: "BIRTHDAY",
34 width: 100,
35 sortable: true,
36 dataIndex: 'birthday',
37 renderer: Ext.util.Format.dateRenderer('m/d/Y'),
38 editor: new Ext.form.DateField ({
39 allowBlank: false,
40 format: 'm/d/Y',
41 maxValue: (new Date())
42 })}
43 ],
44 plugins: [editor],
45 title: 'My Contacts',
46 height: 300,
47 width:610,
48 frame:true,
49 tbar: [{
50 iconCls: 'icon-user-add',
51 text: 'Add Contact',
52 handler: function(){
53 var e = new Contact({
54 name: 'New Guy',
55 phone: '(000) 000-0000',
56 email: 'new@loianetest.com',
57 birthday: '01/01/2000'
58 });
59 editor.stopEditing();
60 store.insert(0, e);
61 grid.getView().refresh();
62 grid.getSelectionModel().selectRow(0);
63 editor.startEditing(0);
64 }
65 },{
66 iconCls: 'icon-user-delete',
67 text: 'Remove Contact',
68 handler: function(){
69 editor.stopEditing();
70 var s = grid.getSelectionModel().getSelections();
71 for(var i = 0, r; r = s[i]; i++){
72 store.remove(r);
73 }
74 }
75 },{
76 iconCls: 'icon-user-save',
77 text: 'Save All Modifications',
78 handler: function(){
79 store.save();
80 }
81 }]
82});

E Finalmente, precisamos de código no lado servidor. O Controller que implementei ficou assim:

001package com.loiane.web;
002
003import java.util.HashMap;
004import java.util.List;
005import java.util.Map;
006
007import javax.servlet.http.HttpServletRequest;
008import javax.servlet.http.HttpServletResponse;
009
010import org.springframework.web.servlet.ModelAndView;
011import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
012
013import com.loiane.model.Contact;
014import com.loiane.service.ContactService;
015
016public class ContactController extends MultiActionController {
017
018 private ContactService contactService;
019
020 public ModelAndView view(HttpServletRequest request,
021 HttpServletResponse response) throws Exception {
022
023 try{
024
025 List contacts = contactService.getContactList();
026
027 return getModelMap(contacts);
028
029 } catch (Exception e) {
030
031 return getModelMapError("Error trying to retrieve contacts.");
032 }
033 }
034
035 public ModelAndView create(HttpServletRequest request,
036 HttpServletResponse response) throws Exception {
037
038 try{
039
040 Object data = request.getParameter("data");
041
042 List contacts = contactService.create(data);
043
044 return getModelMap(contacts);
045
046 } catch (Exception e) {
047
048 return getModelMapError("Error trying to create contact.");
049 }
050 }
051
052 public ModelAndView update(HttpServletRequest request,
053 HttpServletResponse response) throws Exception {
054 try{
055
056 Object data = request.getParameter("data");
057
058 List contacts = contactService.update(data);
059
060 return getModelMap(contacts);
061
062 } catch (Exception e) {
063
064 return getModelMapError("Error trying to update contact.");
065 }
066 }
067
068 public ModelAndView delete(HttpServletRequest request,
069 HttpServletResponse response) throws Exception {
070
071 try{
072
073 String data = request.getParameter("data");
074
075 contactService.delete(data);
076
077 Map modelMap = new HashMap(3);
078 modelMap.put("success", true);
079
080 return new ModelAndView("jsonView", modelMap);
081
082 } catch (Exception e) {
083
084 return getModelMapError("Error trying to delete contact.");
085 }
086 }
087
088 /**
089 * Generates modelMap to return in the modelAndView
090 * @param contacts
091 * @return
092 */
093 private ModelAndView getModelMap(List contacts){
094
095 Map modelMap = new HashMap(3);
096 modelMap.put("total", contacts.size());
097 modelMap.put("data", contacts);
098 modelMap.put("success", true);
099
100 return new ModelAndView("jsonView", modelMap);
101 }
102
103 /**
104 * Generates modelMap to return in the modelAndView in case
105 * of exception
106 * @param msg message
107 * @return
108 */
109 private ModelAndView getModelMapError(String msg){
110
111 Map modelMap = new HashMap(2);
112 modelMap.put("message", msg);
113 modelMap.put("success", false);
114
115 return new ModelAndView("jsonView",modelMap);
116 }
117
118 /**
119 * Spring use - DI
120 * @param dadoService
121 */
122 public void setContactService(ContactService contactService) {
123 this.contactService = contactService;
124 }
125
126}

Se quiser visualizar o código inteiro dessa app de exemplo (ou fazer o donwload do código completo), visite o meu repositório do GitHub: http://github.com/loiane/extjs-crud-grid

Só mais uma observação: você pode usar o dataWriter para salvar as informações que foram arrastadas para o grid com o plugin DataDrop (Lembra do plugin?). Também incluí o plugin no projeto, caso deseje testar.

Fonte: http://www.loiane.com/2010/03/extjs-e-spring-framework-exemplo-de-um-crud-grid/