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<Object> retorno = (List<Object>) repository.find(filter, start, limit); dto.setResults(retorno); return dto; }
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.
Posted in Ajax, DWR, Ext, Frameworks, Java, JavaScript, JEE, JSON, Model 3, RIA, web2.0 ~ 5 Comments

