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 < _totalPorPagina; j++){<br />if(bpAtual.intervaloInicial<br /> + j < _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 > 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.
Abraço e até a próxima.







