Nesse artigo eu pretendo trabalhar dois conceitos principais de uso do Extjs, extensão/customização de componentes e acesso a dados server-side com base em experiência recente em um projeto que desenvolvemos. Esse projeto em questão é um ERP que tinha a necessidade de manter a usabilidade similar a sua versão antiga, feita em Delphi, para o desktop.
Para suprir essa necessidade de usabilidade tivemos que adotar alguns conceitos, como ser totalmente stateless e modificar a arquitetura MVC2 para o MVC3. No server-side trabalhamos com um domain model baseado em Hibernate, Spring e Facades e Services com DWR. Nada de frameworks MVC2, não nos preocupamos com renderização e sim com a API. No lado cliente usamos Extjs com algumas modificações que fiz para integrar de forma suave com o DWR.
Primeiro precisamos entender como o Extjs trabalha com herança. Basicamente há um método no objeto Ext que faz esse trabalho de extensão dos componentes, funciona da seguinte maneira:
//Formato:
var NovoComponente = Ext.extend(velhoComponente, {
/* metodos e propriedades que serão reescritas */
});
//Exemplo:
var MilfontGridPanel = Ext.extend(Ext.grid.GridPanel, {
//novo construtor
constructor: function(config) {
// Seu preprocessamento vai aqui
MilfontGridPanel.superclass.constructor.apply(this, arguments);
// Seu pos-processamento vai aqui
},
NovoMethod: function() {
// algum novo método que você queira criar para o novo componente
}
});
Para esse projeto, criei um Ext.data.DataProxy (como visto no artigo passado) especialista para o DWR, criativamente denominado DWRProxy. A idéia é modificar o comportamento de buscar os dados para usar um Creator do DWR.
Definimos primeiro o objeto e suas propriedades necessárias:
Ext.ux.data.DWRProxy = function(dwr_facade, dwr_filter, dwr_errorHandler){
Ext.ux.data.DWRProxy.superclass.constructor.call(this);
/* Propriedade que receberá a classe Java configurada como Creator */
this.data = dwr_facade;
/*
* Propriedade que receberá uma classe java configurada como converter
* que servirá como filtro de busca
*/
this.dwr_filter = dwr_filter;
/**
*
* Propriedade para fazer paginação, indica que deve cachear a consulta de
* total de elementos o controlador [fachada] deve implementar a logica de
* negocios adequada, quando for false consulta o total, quando for true
* consulta apenas a listagem e repete o total
*/
this.dwr_total_cache = false;
this.dwr_errorHandler = dwr_errorHandler;
};
Após isso extendemos do Ext.data.DataProxy :
Ext.extend(Ext.ux.data.DWRProxy, Ext.data.DataProxy, {
/**
* Método Load do Ext.data.DataProxy overrided
*/
load : function(params, reader, callback, scope, arg) {
/**
* Escopo "this" mapeado para a variável "s" porque dentro do callback do
* DWR o escopo "this" não pertence ao objeto Ext.ux.data.DWRProxy.
*/
var s = this;
params = params || {};
if(params.cache != undefined) {
this.dwr_total_cache = params.cache;
}
if(params.filter != undefined) {
this.dwr_filter = params.filter;
}
var result;
try {
this.data(this.dwr_filter, params.start, params.limit, this.dwr_total_cache, {
callback:function(response) {
//aqui passamos o retorno do DWR
// que chamei de response, para o extjs
result = reader.readRecords(response);
callback.call(scope, result, arg, true);
},
errorHandler:function(a, e) {
scope.fireEvent("loadexception", s, arg, null, e);
s.dwr_errorHandler(a);
},
timeout:100000
});
this.dwr_total_cache = true;
} catch(e) {
this.fireEvent("loadexception", this, arg, null, e);
callback.call(scope, null, arg, false);
return;
}
}
});
A fachada DWR é uma classe comum, segue um exemplo de uso com Hibernate:
//classe para satisfazer o transporte para o Extjs
public final class DataTransferObject {
private int total;
private List extends Object> results;
//sets e gets
}
public class AjaxFacade {
//injeta um repositorio, whatever
private Repository repository = null;
public DataTransferObject find(Object filter, int start, int limit, boolean cache, HttpSession session) {
DataTransferObject dto = new DataTransferObject();
//verifica se o Proxy está passando true
// indicando que está paginando
if (cache) {
Integer total = (Integer) session.getAttribute("totalObject");
dto.setTotal(total);
} else {
session.removeAttribute("totalObject");
Integer total = repository.count(filter);
dto.setTotal(total);
session.setAttribute("totalObject", total);
}
List
Para o Grid visto no artigo passado, basta instanciar assim no javscript:
var store = new Ext.data.Store({
proxy: new Ext.ux.data.DWRProxy(
AjaxFacade.find,
{$dwrClassName:"Project"},
errorHandler
),
reader: new Ext.data.JsonReader({
root: 'results',totalProperty: 'total',id: 'id'
},
['id', 'name', 'manager.name', 'manager.address.country']
)
});
Para entender o {$dwrClassName:”Project”} visite esse post.
Dessa forma o DWR se torna um proxy para todos os componentes do Extjs.
Código fonte da modificação do javascript eu coloquei aqui no github e uma aplicação demo aqui. No próximo vou integrar o DWR com o Rails, aguardem que sai logo… ou não.
Typically chemist’s shop can sale to you with discreet treatments for various soundness problems. There are numerous of safe online pharmacies that will deliver medications to your address. There are divers medicines for each afflictions. Learn more about “viagra manufacturer coupon“. Maybe “viagra discount coupons” is a highly complicated question. Matters, like “coupons for viagra“, are connected numerous types of health problems. If you need to take recipe medications, ask your pharmacist to check your testosterone levels before. Sometimes the treatment options may include erectile malfunction remedies or a suction device that helps get an erection. Keep in mind web-site which is ready to sell erectile dysfunction drugs like Viagra without a prescription is fraudulent. When you purchase from an unknown web-site, you run the risk of getting counterfeit remedies.
Ótimo tutorial!
Valeu
Muito bom o artigo!
Só não vi a real necessidade de utilizar o “cache” em session para evitar uma nova requisição ao banco [count(*)], principalmente quando você caminha para algo stateless.
Acho que utilizar a session no código está atuado como “glue code”. Eu, particularmente, não o utilizaria. Principalmente se eu estivesse com o cache level 2 do Hibernate ligado, pois ele sim deveria se preocupar com isso, e não você.
Enfim, excelente post.
@Rafael Ponte, nesse projeto específico o cache não pode ser usado por motivos que não tenho permissão de expor aqui mas você deve imaginar já que conhece o projeto.
Mas fica a excelente dica para quem puder usar o cache do Hibernate ou outra tecnologia como Ibatis [que nem sei se tem cache de segundo nível].
Sobre a session eu estou resolvendo com o Spring [intercepta e faz o trabalho sujo], mas para não complicar e o pessoal entender de forma fácil eu fiz assim no exemplo.
Christiano,
Antes de mais, parabéns pelo artigo.
Tenho andado à procura de como fazer um proxy em ExtJS e este é o artigo que encontrei mais semelhante daquilo que pretendo.
O que queria era apenas ser eu a definir como fazer o put e get de informação numa página web mas sem usar XML ou JSON, uma vez que a página usa uma especificação própria e é necessário parsing.
Eu estava a pensar fazer as funções de parsing em JavaScript e delegar o put e get nessas funções. Será que me podes dar uma ideia de como será este proxy?
Obrigado
Pingback: Transparência inédita na saúde pública - Milfont Consulting