logo
  • Home
  • Acerca
  • Autores
  • Faq
  • Rede
  Twitter   Feed-me! RSS!

Paginação com Datagrid

Colocado por Edgard Davidson na(s) categoria(s): Flex, Glassfish, Hibernate, Java, JAX-WS, web services em 08 23rd, 2009 | Sem comentários

Olá!

Quando trabalhamos com aplicações centrada em banco de dados podemos ter algumas dificuldades quando a quantidade de registros nas tabelas começam a crescer. Já vi várias aplicações que trabalham bem desde que não possua muitos registros para serem retornados do banco de dados. Isso normalmente é devido a uma análise não muito cuidadosa. O resultado disso é DataGrids, List, ComboBox que tem que receber centenas ou milhares de registros o que com o passar do tempo, quanto mais registros são inseridos no banco de dados, mais lenta fica a aplicação.

Paginação_DataGrid

Paginação com DataGrid

Quando desenvolvemos aplicações que rodarão na internet isso passa a ser um agravante ainda maior. Pensando nisso várias aplicações desenvolvidas para a Web já foram construídas pensando nesse tipo de agravante.  Contundo, já é comum você entrar em um site que tem um grid como resultado de uma busca e esse resultado ser paginado em várias páginas. O próprio Google é um exemplo disto. Pense bem, se o resultado da busca foi um milhão de registros, para que tenho que mostrar tudo de um vez para o meu usuário, ele não vai dar conta de ver mesmo, então eu pagino.

Bom isso é muito bonito, muito legal e você já deve estar convencido, mas e aí, como fazer isso em Flex? Os componentes que vem como padrão no  Flex Builder não implementam esse tipo de recurso nativamente. Então pensando nisso criei este post com o objetivo demonstrar a utilização de paginação em Datagrid no Flex. Será demonstrado um como paginar dados de uma tabela simples utilizando do lado do servidor Java + Web services com JAX-WS + Hibernate +  Glassfish, desenvolvido no NetBeans 6.5.1. Para facilitar as coisar utilizei o banco de dados “sample” que já vem no NetBeans.

Bom, os detalhes de Java, JAX-WS, webservices, SOAP, WSDL, Hiberante vou deixar para outro post. Neste vou mostrar a paginação. Outro dia estava procurando algum exemplo de como fazer essa paginação, então encontrei o blog do Eduardo Kraus onde tinha um exemplo de Paginação de resultados em DataGrig que quase me atendeu para o que eu precisava. Essencialmente, eu aproveitei a função de Timer que ele implementou e a idéia é claro.

Então vamos lá.
Primeiramente será apresentado as classes Java do lado do servidor. A classe Customer abaixo é um POJO  gerado automaticamente pela ferramenta de engenharia reversa para Hibernate contida no NetBeans. A classe Customer reflete a tabela Customer do banco de dados Sample também presente como exemplo no NetBean 6.5.1.  Então, como a classe Customer é uma classe de entidade, ou seja, é uma classe que será persistida em banco de dados, ele tem os mesmos atributos da sua tabela associada e seus respectivos métodos getters e setters.

package entidade;
// Generated 23/08/2009 17:52:56 by Hibernate Tools 3.2.1.GA

/**
 * Customer generated by hbm2java
 */
public class Customer  implements java.io.Serializable {
    private static final long serialVersionUID = 6638932814548400382L;

     private int customerId;
     private char discountCode;
     private String zip;
     private String name;
     private String addressline1;
     private String addressline2;
     private String city;
     private String state;
     private String phone;
     private String fax;
     private String email;
     private Integer creditLimit;

    public Customer() {
    }

    public Customer(int customerId, char discountCode, String zip) {
        this.customerId = customerId;
        this.discountCode = discountCode;
        this.zip = zip;
    }
    public Customer(int customerId, char discountCode, String zip, String name, String addressline1, String addressline2, String city, String state, String phone, String fax, String email, Integer creditLimit) {
       this.customerId = customerId;
       this.discountCode = discountCode;
       this.zip = zip;
       this.name = name;
       this.addressline1 = addressline1;
       this.addressline2 = addressline2;
       this.city = city;
       this.state = state;
       this.phone = phone;
       this.fax = fax;
       this.email = email;
       this.creditLimit = creditLimit;
    }

    public int getCustomerId() {
        return this.customerId;
    }

    public void setCustomerId(int customerId) {
        this.customerId = customerId;
    }
    public char getDiscountCode() {
        return this.discountCode;
    }

    public void setDiscountCode(char discountCode) {
        this.discountCode = discountCode;
    }
    public String getZip() {
        return this.zip;
    }

    public void setZip(String zip) {
        this.zip = zip;
    }
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public String getAddressline1() {
        return this.addressline1;
    }

    public void setAddressline1(String addressline1) {
        this.addressline1 = addressline1;
    }
    public String getAddressline2() {
        return this.addressline2;
    }

    public void setAddressline2(String addressline2) {
        this.addressline2 = addressline2;
    }
    public String getCity() {
        return this.city;
    }

    public void setCity(String city) {
        this.city = city;
    }
    public String getState() {
        return this.state;
    }

    public void setState(String state) {
        this.state = state;
    }
    public String getPhone() {
        return this.phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getFax() {
        return this.fax;
    }

    public void setFax(String fax) {
        this.fax = fax;
    }
    public String getEmail() {
        return this.email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
    public Integer getCreditLimit() {
        return this.creditLimit;
    }

    public void setCreditLimit(Integer creditLimit) {
        this.creditLimit = creditLimit;
    }
}

Em seguida está o código da classe de controle ControleCustomer. Classes de controle são responsáveis por implementar as regras de negócio da aplicação e também implementando o padrão Facade ou Fachada. Como essa é um exemplo muito simples, não havia nenhuma regra a implementar. Então Segue o código.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package controle;

import entidade.Customer;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebService;
import persistencia.GenericDAO;
import persistencia.GenericException;

/**
 *
 * @author Edgard Davidson
 */
@WebService()
public class ControleCustomer {
    private GenericDAO dao = new GenericDAO();

    /**
     * Função que retorna uma lista contendo os objetos que enquadrarem nos
     * critérios de filtragem.
     *
     * @param campo nome do campo do banco de dados que será feito a filtro
     * @param pesquisa o termo de pesquisa que será feito no campo selecionado
     * @param indice é o índice do primeiro registro que deverá ser retornado
     * @param maximo quantidade máxima de registror que serão retornados
     * @return retorna uma lista de customer. Essa lista será serializado em XML pelo JAX-WS
     * @throws persistencia.GenericException tratamento genérico de erro
     */
    @WebMethod
    @SuppressWarnings({"unchecked"})
    public List obterObjetosCustomer(String campo, String pesquisa, int indice, int maximo) throws GenericException {
        Customer customer = new Customer();
        return  dao.loadObjects(campo, pesquisa, customer, indice, maximo);
    }

    /**
     * Função que retorna a quantidade de objetos que enquadrarem nos
     * critérios de filtragem.
     *
     * @param campo nome do campo do banco de dados que será feito a filtro
     * @param pesquisa o termo de pesquisa que será feito no campo selecionado
     * @return a quantidade de objetos encontrados
     * @throws persistencia.GenericException tratamento genérico de erro
     */
    @WebMethod
    public long obterQuantidadeObjetosCustomer(String campo, String pesquisa) throws GenericException {
        Customer customer = new Customer();
        return dao.getCountObjects(campo, pesquisa, customer);
    }
}

Note que a classe ControleCustomer possui anotações como @WebMethod e @WebService. Essa classe será disponibilizada por meio de uma WSDL para ser acessado por qualquer outra aplicação cliente.

Existe também uma classe Chamada GenericDao responsável em fazer a comunicação com o framework hibernate. Essa classe implementa as funções que vão de fato recuperar os registros do banco de dados. Então para que você não precise de fazer um select * e voltar um milhão de registros, foi utilizado o Criteria do hibernate para filtrar a quantidade de registro que você deseja retornar. Utilizei também o CreateQuery para saber quantos registros na função getCountObjects. Se você observar depois nos códigos em Flex,  a aplicação irá chamar o método getCountObjects para saber quantos objetos serão retornados, só depois eu chamo o método loadObjects. Bom quando eu implementei isto eu tinha outras opções para chegar mesmo lugar. Se você tiver uma idéia mais interessante comente aí, será bem vindo!

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package persistencia;

import java.util.List;
import org.hibernate.*;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

/**
 *
 * @author Edgard Davidson
 */
public class GenericDAO {

    private Session session = null;

    public GenericDAO() {
       //  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
    }

    private void createSession(){
       //this.session = HibernateUtil.getSessionFactory().getCurrentSession();
        this.session = HibernateUtil.getSessionFactory().openSession();
    }

     public List loadObjects(String campo, String pesquisa, Object obj, int firstResult, int maxResult) throws GenericException {

        createSession();
        Transaction tx = session.beginTransaction();

        try {
            Criteria criteria = this.session.createCriteria(obj.getClass());
            criteria.add( Restrictions.like(campo.toLowerCase(), pesquisa, MatchMode.START) );

            criteria.setFirstResult(firstResult);
            criteria.setMaxResults(maxResult);

            return criteria.list();
        } catch (HibernateException ex) {
            if ((session != null) && tx.isActive()) {
                tx.rollback();
            }

            throw new GenericException("Ocorreu um erro de pesquisa" + " na classe " + obj.getClass().getSimpleName() + " com a seguinte mensagem de erro:" + ex.getMessage());
        } finally {
            if ((session != null) && session.isOpen()) {
             // tx.commit();
            }
        }
    }

    public long getCountObjects(String campo, String pesquisa, Object obj) throws GenericException{

        createSession();
        Transaction tx = session.beginTransaction();
        try {
            if (campo == null) {
                campo = "";
            }
            if (pesquisa == null) {
                pesquisa = "";
            }

            String sql = "select count(*) from " + obj.getClass().getName() + " where " + campo + " like '" + pesquisa + "%'";
            Long  count =  (Long) session.createQuery(sql).uniqueResult();
            if (count != null) {
                return count.longValue();
            }
            else {
                return 0;
            }
        } catch (HibernateException ex) {
            if ((session != null) && tx.isActive()) {
                tx.rollback();
            }
            throw new GenericException("Ocorreu um erro de pesquisa" + " na classe " + obj.getClass().getClass().getSimpleName() + " com a seguinte mensagem de erro:" + ex.getMessage());
        } finally {
            if ((session != null) && session.isOpen()) {
             // tx.commit();
            }
        }
    }
}

Bem,  existem outros detalhes como os arquivos xml para configuração do Hibernate, a classe HibernateUtil que irá criar a sessão com o banco,  mas isso vou empacotar para você fazer download no final do texto.  Caso tenha dúvida,  comente esse post que respondo!!

Agora vamos passar para o lado do Cliente, neste caso, implementado em Flex. A primeira coisa a se fazer e saber o endereço do seu WSDL. No meu caso o endereço é http://localhost:8080/appServidor/ControleCustomerService?WSDL. A aplicação precisará do endereço do WSDL do webservices  para saber quais métodos foram publicados, quais objetos serão trafegados etc. Para mais detalhes sobre o funcionamento de SOAP, WSDL e webservices vá ao google folgado(a).

Então, já que eu sei o meu endereço do WDSL eu já importei a classe Customer.  Aquela mesmo que está logo acima em Java. Só que agora ela já está em ActionScript.  O próprio Flex Builder tem uma opção para gerar essa classe automaticamente para você. Data->Import Web Service (WSDL).

/**
 * Customer.as
 * This file was auto-generated from WSDL by the Apache Axis2 generator modified by Adobe
 * Any change made to this file will be overwritten when the code is re-generated.
 */

package entidade{
    import mx.utils.ObjectProxy;
    import flash.utils.ByteArray;
    import mx.rpc.soap.types.*;
    /**
     * Wrapper class for a operation required type
     */

    public class Customer
    {
        /**
         * Constructor, initializes the type class
         */
public function Customer() {}

                   public var addressline1:String;
                   public var addressline2:String;
                   public var city:String;
                   public var creditLimit:Number;
                   public var customerId:Number;
                   public var discountCode:Number;
                   public var email:String;
                   public var fax:String;
                   public var name:String;
                   public var phone:String;
                   public var state:String;
                   public var zip:String;
           	}
      	 }

Em seguida segue o código da aplicação principal.




	
		 0)
					var temp1:int=this.indice + 1;
				var temp2:int=this.indice + this.maximo;
				if (temp2 > this.qtdeObjetos)
					temp2=this.qtdeObjetos;
				lbPag.text=temp1.toString() + " - " + temp2.toString() + " de " + this.qtdeObjetos.toString();
			}

			private function onResultObterObjetosCustomer(event:ResultEvent):void
			{
				var acTemp:ArrayCollection=new ArrayCollection();
				var i:int;
				acTemp=event.result as ArrayCollection;
				AC.removeAll();
				var customer:Customer;

				if (event.result != null)
				{
					if (acTemp == null)
					{
						this.controleBotoesPaginacao(1);
						customer=new Customer();
						customer.customerId=event.result.customerId;
						customer.name=event.result.name;
						customer.city=event.result.city;
						customer.state=event.result.state;
						customer.zip=event.result.zip;
						AC.addItem(customer);
					}

					if (acTemp != null)
					{
						this.controleBotoesPaginacao(acTemp.length);
						for (i=0; i < acTemp.length; i++)
						{

							customer=new Customer();
							customer.customerId=acTemp.getItemAt(i).customerId;
							customer.name=acTemp.getItemAt(i).name;
							customer.city=acTemp.getItemAt(i).city;
							customer.state=acTemp.getItemAt(i).state;
							customer.zip=acTemp.getItemAt(i).zip;
							AC.addItem(customer);
						}
					}
				}
				else
					this.controleBotoesPaginacao(0);
			}

			private function onResultObterQuantidadeObjetosCustomer(event:ResultEvent):void
			{
				this.qtdeObjetos=event.result as int;
				srv.obterObjetosCustomer(comboBoxFiltro.selectedItem, campoBusca.text, indice, maximo, '');
			}

			private function onFault(event:FaultEvent):void
			{
				if (event.fault.rootCause == null)
					Alert.show("MOTIVO:\n" + event.fault.faultString + " \n\nDESCRIÇÃO:\n" + event.fault.faultDetail, "ERRO: " + event.fault.faultCode);
				else
					Alert.show("MOTIVO:\n" + event.fault.message + " \n\nDESCRIÇÃO:\n" + event.fault.faultDetail, "ERRO: " + event.fault.faultCode);
			}

			private function inicio_Click():void
			{
				this.indice=0;
				this.maximo=nsMaximo.value;
				obterObjetosCustomer_Click();
			}

			private function retroceder_Click():void
			{
				if ((this.indice - nsMaximo.value) <= 0)
					this.indice=0;
				else
					this.indice=this.indice - nsMaximo.value;
				this.maximo=nsMaximo.value;
				obterObjetosCustomer_Click();
			}

			private function avancar_Click():void
			{
				this.indice=this.indice + nsMaximo.value;
				this.maximo=nsMaximo.value;
				obterObjetosCustomer_Click();
			}

			private function fim_Click():void
			{
				this.indice=this.qtdeObjetos - nsMaximo.value;
				this.maximo=nsMaximo.value;
				obterObjetosCustomer_Click();
			}
		]]>
	

	
		
		
		
		
	

	
		
			
				
					
					
					
					
					
				
			
			
				
				
				
				
				
				
				
				
			
			
				
					Name
					Cyte
					State
					Zip
				
			
			
			
		
	


Espero que seja útil, apesar de uma ou outra gambiarra…

O lado servidor poderá ser baixado em  appServidor

O lado cliente poderá ser baixado em appCliente

Obs: Para diminuir o tamanho do arquivo para o código do servidor, eu retirei as libs. Mas para você compilar precisará delas: 

antlr-2.7.6.jar
asm.jar
asm-attrs.jar
cglib-2.1.3.jar
commons-collections-2.1.1.jar
commons-logging-1.1.jar
derbyclient.jar
dom4j-1.6.1.jar
ehcache-1.2.3.jar
hibernate3.jar
hibernate-annotations.jar
hibernate-commons-annotations.jar
hibernate-entitymanager.jar
hibernate-tools.jar
javassist.jar
jdbc2_0-stdext.jar
jta.jar

Paginação de resultados em DataGrig



Veja o post original no blog do autor aqui!  

Edgard Davidson

Escrito por Edgard Davidson @ http://edgarddavidson.com
Saiba mais sobre o autor na sua pagina de perfil
Outros posts do autor:
» Conformidade com o Produto vs. Conformidade com o Processo
» Flex Mania
» Prototipagem: Balsamiq Mockups + Napkee

Deixe um comentário



Spam Protection by WP-SpamFree

ACERCA

O que é o RedeRIA ?

O redeRIA não é nada mais que um agregador de feed's que disponibiliza o conteudo de varios blogs e autores ao redor do mundo RIA, actualmente agregamos mais de 2790 entradas vindas de 53 blogs especializados em ria’s, pelo que só fica a ganhar em assinar o feed ou seguir a comunidade no twitter.

Se acha que o seu blog ou um blog de um amigo é interessante e util para os leitores o redeRIA, faça a sua submissão aqui.

Feed: assine já
Twitter: siga-nos

GOOGLE

Votação


Deveria o RedeRia agregar conteúdo em inglês?
Ver Resultados

AUTORES


Eduardo KrausAlexandre TadashiBindableCognitiva SoluçõesDaniel LopesDaniel SchmitzDanielPedrinhaDClick TeamEbercomEdgard DavidsonElvis FernandesErko BrideeFabiel PrestesFábio Batista da SilvaFabio da SilvaFabriccio BernardesFelipe BorellaFlavia MoreiraGabriel VersalliniGabriela T. PerryIgor MusardoJanderson CardosoJoão AugustoJose Carlos FielKelps SousaLeonardo FrançaLucas MarçalLuis MessiasLuiz TarabalMario JuniorMário SantosMauro MartinsPablo SouzaPedro ClaudioreneRia BrazilriaPTRicardo CerqueiraRobson FernandesRodrigo Pereira FragaSaintBrSamuelFacchinelloSergio SouzaSilva DeveloperStefan HorochovecTech CaffeTecinforThiago BuenoVedVinícius SandimWillian ManoXAML Cast

PUBLICIDADE








Powered by Wordpress & msdevstudio.com