Dev (Back & Front)ARTIGO

Criando um componente de paginação – Parte 02

Salve, salve, pessoal!

Depois de um enorme jejum, estou de volta, e com a segunda parte do componente de paginação. A demora foi por conta de excesso de trabalho, uns projetos que tomaram grande parte do meu tempo. Obrigado pelos emails pedindo essa segunda parte, e aqui está ela!

Na primeira
parte do artigo
, desenvolvemos um componente de paginação extremamente
estático, que apenas simulava uma paginação, ou seja, recebia uma lista
completa do server-side e ficava, então, dividindo a lista na memória.
Todos sabemos que isso é realmente inviável em grandes aplicações, pois
imagine se receber uma lista com mais de mil registros, com certeza o
server-side ou o client iria lançar algum erro.

Nesta situação, temos de fazer com que o server-side tenha toda a
responsabilidade de paginar e retornar apenas os dados que informamos no
filtro, é isso que irei abordar nesta segunda parte do artigo.

Requisitos:

  • Ter Flex/Flash Builder ou outra IDE
  • Ter SDK 3 ou superior
  • Conhecimento em ActionScript e Mxml
  • MySQL Instalado e conhecimento básico
  • Jdk 5 ou superior
  • Nível de dificuldade: 8.0

Passo 1:

Iremos criar um projeto Java e suas configurações básicas para se
conectar com o Flex, não irei demonstrar isso passo a passo, já que esse
tema já foi abordado em um artigo anterior.

Passo 2:

Com o projeto criado e configurado, iremos criar as seguintes classes
de configuração e conexão com o banco de dados MySQL. A única responsabilidade desta classe é de abrir e fechar uma conexão
com o banco de dados.

package com.imaster;<br /> <br />import java.sql.Connection;<br />import java.sql.DriverManager;<br />import java.sql.ResultSet;<br />import java.sql.SQLException;<br />import java.sql.Statement;<br /> <br />/**<br /> * <br /> * @author Fabiel Prestes<br /> *<br /> */<br />public class ConnectionManager {<br /> <br />	private static final String dburl = "jdbc:mysql://localhost:3306/imaster_paginacao"; <br />    private static final String dbdriver = "com.mysql.jdbc.Driver";<br />    private static final String usuario = "root";  <br />    private static final String senha = "root";<br /> <br /> <br />    public static Connection getConexao() throws Exception {<br />        try {<br />        	Connection conn = null;<br />            // carregamento do driver<br />            Class.forName(dbdriver);<br />            // Obtendo a conexao<br />            conn = DriverManager.getConnection(dburl, usuario, senha);<br />            System.out.println(" <<< Obtendo conexao >>>");<br />            return conn;<br /> <br />        } catch (ClassNotFoundException e) {<br />            String errorMsg = "Driver nao encontrado";<br />            throw new Excecoes(errorMsg, e);<br />        } catch (SQLException e) {<br />            String errorMsg = "Erro ao obter a conexao";<br />            throw new Excecoes(errorMsg, e);<br />        }<br />    }<br /> <br />    public static void closeAll(Connection conn) {<br />        try {<br />            if (conn != null) {<br />                conn.close();<br />            }<br />        } catch (Exception e) {<br />            String errorMsg = "Nao foi possivel fechar a conexao com o banco";<br />            Excecoes.print(e, errorMsg);<br />        }<br />    }<br /> <br />    public static void closeAll(Connection conn, Statement stmt) {<br />        try {<br />            if (stmt != null) {<br />                stmt.close();<br />            }<br />        } catch (Exception e) {<br />            String errorMsg = "Nao foi possivel fechar o Statement";<br />            Excecoes.print(e, errorMsg);<br />        }<br />        closeAll(conn);<br />    }<br /> <br />    public static void closeAll(Connection conn, Statement stmt, ResultSet rs) {<br />        try {<br />            if (rs != null) {<br />                rs.close();<br />            }<br />        } catch (Exception e) {<br />            String errorMsg = "Nao foi possivel fechar o Resultset";<br />            Excecoes.print(e, errorMsg);<br />        }<br />        closeAll(conn, stmt);<br />    }<br /> <br />}

Passo 3:

Iremos criar a classe AlunoDAO, que terá três métodos: um para
inserir alunos, um para listar os alunos e outro para contar o total
de alunos.

package com.imaster;<br /> <br />import java.sql.Connection;<br />import java.sql.ResultSet;<br />import java.sql.SQLException;<br />import java.sql.Statement;<br />import java.util.ArrayList;<br />import java.util.List;<br /> <br />/**<br /> * <br /> * @author Fabiel Prestes<br /> *<br /> */<br />public class AlunoDAO {<br /> <br />	private Connection conn = null;<br />	private Statement stmt = null;<br />	private ResultSet rs = null;<br /> <br />	public void salvar(Aluno aluno) throws Exception {<br />		try {<br />			// criando Conexao<br />			conn = ConnectionManager.getConexao();<br />			stmt = conn.createStatement();<br /> <br />			// comando sql<br />			String sql = "insert into aluno (nome, email) values ('"+aluno.getNome()+"', '"+aluno.getEmail()+"')";<br /> <br />			stmt.executeUpdate(sql);<br /> <br />			System.out.println(" <<< aluno inserido com sucesso >>>");<br />		} catch (SQLException e) {<br />			Excecoes.print(e,"Nao foi possivel salvar o aluno na base de dados.");<br />		} finally {<br />			// Finalizar o statement e a conexao usando a classe ConnectionManager<br />			ConnectionManager.closeAll(conn, stmt);<br />		}<br />	}<br /> <br />	public int getTotalAlunos() throws Exception {<br />		int totalAlunos = 0;<br /> <br />		try{<br />			// comando sql<br />			String sql = "SELECT COUNT(*) FROM aluno";<br /> <br />			// criando Conexao<br />			conn = ConnectionManager.getConexao();<br />			stmt = conn.createStatement();<br />			rs = stmt.executeQuery(sql);<br /> <br />			while(rs.next()){<br />				totalAlunos = rs.getInt(1);<br />			}<br />		} catch (SQLException e) {<br />			Excecoes.print(e,"Nao foi possivel recuperar o total de alunos na base de dados.");<br />		} finally {<br />			// Finalizar o statement e a conexao usando a classe ConnectionManager<br />			ConnectionManager.closeAll(conn, stmt);<br />		}<br />		return totalAlunos;<br />	}<br /> <br />	public List<Aluno> listarAlunos(int pagina, int totalRegistros) throws Exception {<br />		List<Aluno> alunos = new ArrayList<Aluno>();<br /> <br />		try{<br />			// comando sql<br />			String sql = "SELECT * FROM aluno LIMIT "+pagina+","+totalRegistros;<br /> <br />			// criando Conexao<br />			conn = ConnectionManager.getConexao();<br />			stmt = conn.createStatement();<br />			rs = stmt.executeQuery(sql);<br /> <br />			Aluno aluno = null;<br /> <br />			while(rs.next()){<br />				aluno = new Aluno();<br />				aluno.setId(rs.getInt("id"));<br />				aluno.setNome(rs.getString("nome"));<br />				aluno.setEmail(rs.getString("email"));<br /> <br />				alunos.add(aluno);<br />			}<br />		} catch (SQLException e) {<br />			Excecoes.print(e,"Nao foi possivel recuperar o total de alunos na base de dados.");<br />		} finally {<br />			// Finalizar o statement e a conexao usando a classe ConnectionManager<br />			ConnectionManager.closeAll(conn, stmt);<br />		}<br />		return alunos;<br />	}<br />}

Passo 4:

Com o DAO criado, precisamos de uma classe para acessar e chamar os
métodos e devolvê-los ao Client. Esta classe realmente simples apenas
recebe uma requisição do Flex e retorna o resultado da paginação.

package com.imaster;<br /><br />/**<br /> * <br /> * @author Fabiel Prestes<br /> *<br /> */<br />public class PaginacaoService {<br /><br />	private AlunoDAO alunoDAO;<br /><br />	public AlunoDAO getAlunoDAO(){<br />		if(alunoDAO == null){<br />			alunoDAO = new AlunoDAO();<br />		}<br />		return alunoDAO;<br />	}<br /><br />	public Paginacao listarDadosPaginados(int pagina, int totalRegistros) throws Exception {<br />		try {<br />			Paginacao paginacao = new Paginacao();<br />			paginacao.setTotalDados(getAlunoDAO().getTotalAlunos());<br />			paginacao.setListaDados(getAlunoDAO().listarAlunos(pagina, totalRegistros));<br />			return paginacao;<br />		} catch (Exception e) {<br />			throw e;<br />		}<br />	}<br /><br />	public static void main(String[] args) throws Exception {<br />		PaginacaoService ps = new PaginacaoService();<br />		System.out.println(ps.getAlunoDAO().getTotalAlunos());<br />//		ps.getAlunoDAO().salvar(new Aluno("Fabiel Prestes", "fabiel.prestes@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Joao Prestes Neto", "joao.prestes@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Dom Pedro I", "domI@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Dom Pedro II", "donII@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Luiz Inacio", "luiz@inacio.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Ana Carolina", "ana@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Ana Beatriz", "anabeatriz@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Antonio Carlos", "antonio@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Aline B. R.", "aline@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Cecilia Duarte", "cecilia@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Maria Isabel", "mariaisabel@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Carlos Renato", "carlosrenato@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Susana", "susana@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Monica", "monmica@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Cebolinha", "cebolinha@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Chico Bento", "chicobento@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Magali", "magali@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Anginho", "anginho@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Cascao", "cascao@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("zeca Urubu", "eca@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Pica Pau", "picapau@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("zé Carioca", "cariona@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Tio Patinhas", "tiopatinhas@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Xuxa", "xuxa@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Sheila", "sh@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Hebe Camargo", "hebe@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Jonas", "jonas@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Igor", "@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Magnum", "@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Princila", "@gmail.com"));<br />//		ps.getAlunoDAO().salvar(new Aluno("Maria Cecilia", "@gmail.com"));<br /><br /><br />	}<br />}

Passo 5:

Com a nossa classe de serviço pronta, precisamos criar um DTO/VO que
represente a paginação em si. Neste DTO teremos apenas duas
propriedades: totalDados e listaDados. O flex irá utilizar os dados
contidos neste DTO para montar toda a estrutura de paginação.

package com.imaster;<br /><br />import java.util.List;<br /><br />/**<br /> * <br /> * @author Fabiel Prestes<br /> *<br /> */<br />public class Paginacao {<br /><br />	private int totalDados;<br />	private List<? extends Object> listaDados;<br /><br />	public Paginacao(){<br /><br />	}<br /><br />	/**<br />	 * @return the totalDados<br />	 */<br />	public int getTotalDados() {<br />		return totalDados;<br />	}<br />	/**<br />	 * @param totalDados the totalDados to set<br />	 */<br />	public void setTotalDados(int totalDados) {<br />		this.totalDados = totalDados;<br />	}<br />	/**<br />	 * @return the listaDados<br />	 */<br />	public List<? extends Object> getListaDados() {<br />		return listaDados;<br />	}<br />	/**<br />	 * @param listaDados the listaDados to set<br />	 */<br />	public void setListaDados(List<? extends Object> listaDados) {<br />		this.listaDados = listaDados;<br />	}<br /><br /><br />}

Passo 6:

Seguem a classe Aluno, que é simplesmente um DTO/Bean, e a classe
Excecoes, que apenas realiza um tratamento nas Exceptions geradas.

package com.imaster;<br />public class Aluno {<br />    private Integer id;<br />    private String nome;<br />    private String email;<br /><br />    public Aluno(){<br />    }<br /><br />    public Aluno(String nome, String email){<br />        this.nome = nome;<br />        this.email = email;<br />    }<br /><br />    /**<br />     * @return the id<br />     */<br />    public Integer getId() {<br />        return id;<br />    }<br /><br />    /**<br />     * @param id the id to set<br />     */<br />    public void setId(Integer id) {<br />        this.id = id;<br />    }<br /><br />    /**<br />     * @return the nome<br />     */<br />    public String getNome() {<br />        return nome;<br />    }<br /><br />    /**<br />     * @param nome the nome to set<br />     */<br />    public void setNome(String nome) {<br />        this.nome = nome;<br />    }<br /><br />    /**<br />     * @return the email<br />     */<br />    public String getEmail() {<br />        return email;<br />    }<br /><br />    /**<br />     * @param email the email to set<br />     */<br />    public void setEmail(String email) {<br />        this.email = email;<br />    }<br />}
/**<br /> * <br /> */<br />package com.imaster;<br />/**<br /> * @author Fabiel<br /> *<br /> */<br />public class Excecoes extends Exception{<br />    private static final long serialVersionUID = 1L;<br /><br />    public Excecoes(String mensagem, Exception e) {<br />        super(mensagem, e);<br />    }<br /><br />    public Excecoes(String mensagem) {<br />        super(mensagem);<br />    }<br /><br />    public static void print(Exception e, String mensagem) {<br />        System.out.println("==============Exception===============");<br />        System.out.println(mensagem);<br />        System.out.println("PrintStackTrace: ");<br />        e.printStackTrace();<br />        System.out.println("============End Exception=============");<br />    }<br /><br />    public void print() {<br />        System.out.println("==============Exception===============");<br />        System.out.println(getMessage());<br />        System.out.println("PrintStackTrace: ");<br />        getCause().printStackTrace();<br />        System.out.println("============End Exception=============");<br />    }<br />}

Chegamos ao final da configuração do servidor, neste não irei me
apegar a nenhum design pattern e nem a bons modos de implentação, já que o
foco aqui é apenas mostrar como se faz para utilizar a paginação via
sql.

Agora no projeto Flex que foi criado na parte I não iremos alterar
muita coisa, iremos alterar apenas a classe Paginacao.as e criar uma
classe chamada PaginacaoVO.as, que é o espelho do nosso DTO
Paginacao.java.

Na classe paginação, inseri algumas anotations:

  • @Novo quando tive de criar métodos e variáveis
  • @Alterado quando apenas alterei um algoritimo de algum método
  • @Removido quando exlcui alguma variável ou método

Abaixo irei colocar alguns trechos que tive que modificar para a
segunda parte do artigo. Mais já adianto que apenas modifiquei
uma ou outra coisa.

/** @Novo */<br />private var <br />remotePaginacao:RemoteObject;
/* @Removido<br />[Bindable]<br />private var <br />_listaBaseAux:ArrayCollection; */
/** @Novo */<br />private var _atualizarBarraBotoes:Boolean = true;
/**<br />* @Alterado<br />*<br />*/<br />public function Paginacao() {<br />super();<br /> <br />remotePaginacao<br /> = new RemoteObject();<br />remotePaginacao.destination = destination;<br />remotePaginacao.addEventListener(FaultEvent.FAULT,<br /> function (event:FaultEvent):void{<br />Alert.show(event.toString());<br />});<br /> <br />this.addEventListener(FlexEvent.CREATION_COMPLETE,<br /> onCreate, false, 0, true);<br />}
/**<br />* @private<br />* @Novo<br />*<br />*/<br />private function <br />onCreate(evt:FlexEvent):void{<br />this.remotePaginacao.listarDadosPaginados(0,<br /> totalPorPagina);<br />}
/**<br />* @private<br />* @Novo<br />* @param evt<br />*<br />*/<br />private <br />function listarDadosPaginadosResult(evt:ResultEvent):void{<br />totalDados<br /> = PaginacaoVO(evt.result).totalDados;<br />listaBase = <br />PaginacaoVO(evt.result).listaDados;<br /> <br />if(_atualizarBarraBotoes){<br />configurarBotoesPagina();<br />}<br /> else {<br />this.listaAlvo.dataProvider = listaBase;<br />}<br />}
/**<br />* @Removido<br />*<br />*/<br />override public function <br />invalidateProperties():void{<br />super.invalidateProperties();<br /> <br />/*<br /> Inicializa a configuração da paginação */<br />configurarBotoesPagina();<br />}
/**<br />* @private<br />* @Alterado<br />* Fica escutando quando o <br />usuario trocou o total de interva de dados a ser amostrado na lista<br />*<br /> @param evt<br />*/<br />private function <br />trateTrocaIntervalo(evt:ListEvent):void{<br />totalPorPagina = <br />cbIntevalo.selectedItem.value;<br /> <br />/* INICIO: @Novo*/<br />_atualizarBarraBotoes<br /> = true;<br /> <br />this.remotePaginacao.listarDadosPaginados(0, <br />totalPorPagina);<br />/* FIM: @Novo*/<br />}
/**<br />* @private<br />* @Alterado<br />* Configura e renderiza os dados<br /> Base para ser amostrado na tela levendo-se em consideração<br />* o <br />intervalo passado.<br />* @param intervloIncial<br />*<br />*/<br />private <br />function configurarListaNaPagina(bpAtual:BotaoPagina):void{<br />/* <br />INICIO: @Removido<br />_listaBaseAux = new ArrayCollection();<br /> <br />//para<br /> cada Loop é copiado o objeto que se encontra no intervalo passado como <br />parametro<br /> <br />for(var j:int = 0; j &lt; _totalPorPagina; j++){<br />if(bpAtual.intervaloInicial<br /> + j &lt; _totalDados)<br />_listaBaseAux.addItem(_listaBase.getItemAt(bpAtual.intervaloInicial<br /> + j));<br />}<br />FIM: @Removido */<br /> <br />/* Configurando os botoes de <br />avançar e retornar */<br />if(bpAtual.pagina &gt; 1){<br />configBpPaginaAnterior();<br />}<br /> else {<br />configBpPaginaAnterior(false);<br />}<br /> <br />if(bpAtual.pagina<br /> == totalBotoes){<br />configBpProximaPagina(false);<br />} else {<br />configBpProximaPagina();<br />}<br /> <br />/*<br /> INICIO: @Removido<br />//Define o provider clonado e define na ListBase<br />this._listaAlvo.dataProvider<br /> = _listaBaseAux;<br />* FIM: @Removido */<br /> <br />/* INICIO: @Novo */<br />_atualizarBarraBotoes<br /> = false;<br />this.remotePaginacao.listarDadosPaginados((bpAtual.pagina -<br /> 1) * totalPorPagina, totalPorPagina);<br />/* FIM: @Novo */<br />}
/**<br />* @Alterado<br />* Define a lista que será utilizada para <br />exibir na paginacao<br />* @param value<br />*<br />*/<br />public function set <br />listaBase(value:ArrayCollection):void{<br />_listaBase = value;<br />/*<br />_listaBase<br /> = value;<br />if(_listaBase){<br />_totalDados = _listaBase.length;<br />}<br />*/<br />}

É isso aí, pessoal, todas as alterações que tive que fazer para que o
componente de paginação funcionasse junto ao server-side.

Estou disponibilizando o código fonte dos dois projetos para vocês
testarem.

Agora é só esperarem a terceira parte do tutorial, onde iremos
refinar o componente, aplicar filtros e ordenação dos dados.

Código Fonte

Abraço e até a próxima.

trabalha a desde 2005 em desenvolvimento e integração de sistemas WEB JEE. Começou a trabalhar com desenvolvimento de aplicações RIA Flex/Air em 2007. Atualmente é analista de sistemas pela JExperts, participa de fóruns e listas de discussões como Anddev, Adroid.org, GUJ, FlexDev, FloripaFlex e PortalAndroid.

Ver perfil