Post

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:

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]
// The new DataWriter component.
var writer = new Ext.data.JsonWriter({
encode: true,
writeAllFields: false
});
[/code]

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:

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]
var Contact = Ext.data.Record.create([
{name: 'id'},
{
name: 'name',
type: 'string'
}, {
name: 'phone',
type: 'string'
}, {
name: 'email',
type: 'string'
}, {
name: 'birthday',
type: 'date',
dateFormat: 'm/d/Y'
}]);
[/code]

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:

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]
var proxy = new Ext.data.HttpProxy({
api: {
read : 'contact/view.action',
create : 'contact/create.action',
update: 'contact/update.action',
destroy: 'contact/delete.action'
}
});
[/code]

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

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]
var reader = new Ext.data.JsonReader({
totalProperty: 'total',
successProperty: 'success',
idProperty: 'id',
root: 'data',
messageProperty: 'message'// <-- New "messageProperty" meta-data
},
Contact);
[/code]

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

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]
// 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.
});
[/code]

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!):

[code lang="html" firstline="1" toolbar="true" collapse="false" wraplines="false"]
<!-- 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>
[/code]

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

[code lang="js" firstline="1" toolbar="true" collapse="false" wraplines="false"]
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
}},
{header: "BIRTHDAY",
width: 100,
sortable: true,
dataIndex: 'birthday',
renderer: Ext.util.Format.dateRenderer('m/d/Y'),
editor: new Ext.form.DateField ({
allowBlank: false,
format: 'm/d/Y',
maxValue: (new Date())
})}
],
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',
birthday: '01/01/2000'
});
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();
}
}]
});
[/code]

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

[code lang="java" firstline="1" toolbar="true" collapse="false" wraplines="false"]
package com.loiane.web;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;

import com.loiane.model.Contact;
import com.loiane.service.ContactService;

public class ContactController extends MultiActionController{

private ContactService contactService;

public ModelAndView view(HttpServletRequest request,
HttpServletResponse response) throws Exception {

try{

List<Contact> contacts = contactService.getContactList();

return getModelMap(contacts);

} catch (Exception e) {

return getModelMapError("Error trying to retrieve contacts.");
}
}

public ModelAndView create(HttpServletRequest request,
HttpServletResponse response) throws Exception {

try{

Object data = request.getParameter("data");

List<Contact> contacts = contactService.create(data);

return getModelMap(contacts);

} catch (Exception e) {

return getModelMapError("Error trying to create contact.");
}
}

public ModelAndView update(HttpServletRequest request,
HttpServletResponse response) throws Exception {
try{

Object data = request.getParameter("data");

List<Contact> contacts = contactService.update(data);

return getModelMap(contacts);

} catch (Exception e) {

return getModelMapError("Error trying to update contact.");
}
}

public ModelAndView delete(HttpServletRequest request,
HttpServletResponse response) throws Exception {

try{

String data = request.getParameter("data");

contactService.delete(data);

Map<String,Object> modelMap = new HashMap<String,Object>(3);
modelMap.put("success", true);

return new ModelAndView("jsonView", modelMap);

} catch (Exception e) {

return getModelMapError("Error trying to delete contact.");
}
}

/**
* Generates modelMap to return in the modelAndView
* @param contacts
* @return
*/
private ModelAndView getModelMap(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 new ModelAndView("jsonView", modelMap);
}

/**
* Generates modelMap to return in the modelAndView in case
* of exception
* @param msg message
* @return
*/
private ModelAndView getModelMapError(String msg){

Map<String,Object> modelMap = new HashMap<String,Object>(2);
modelMap.put("message", msg);
modelMap.put("success", false);

return new ModelAndView("jsonView",modelMap);
}

/**
* Spring use - DI
* @param dadoService
*/
public void setContactService(ContactService contactService) {
this.contactService = contactService;
}

}
[/code]

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.

Bons códigos!

This post is licensed under CC BY 4.0 by the author.
This site uses cookies. Please choose whether to accept analytics cookies. Privacy Policy