Back-End

22 abr, 2010

Criando um componente de paginação – Parte 02

Publicidade

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

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

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;

/**
*
* @author Fabiel Prestes
*
*/
public class PaginacaoService {

private AlunoDAO alunoDAO;

public AlunoDAO getAlunoDAO(){
if(alunoDAO == null){
alunoDAO = new AlunoDAO();
}
return alunoDAO;
}

public Paginacao listarDadosPaginados(int pagina, int totalRegistros) throws Exception {
try {
Paginacao paginacao = new Paginacao();
paginacao.setTotalDados(getAlunoDAO().getTotalAlunos());
paginacao.setListaDados(getAlunoDAO().listarAlunos(pagina, totalRegistros));
return paginacao;
} catch (Exception e) {
throw e;
}
}

public static void main(String[] args) throws Exception {
PaginacaoService ps = new PaginacaoService();
System.out.println(ps.getAlunoDAO().getTotalAlunos());
// ps.getAlunoDAO().salvar(new Aluno("Fabiel Prestes", "fabiel.prestes@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Joao Prestes Neto", "joao.prestes@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Dom Pedro I", "domI@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Dom Pedro II", "donII@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Luiz Inacio", "luiz@inacio.com"));
// ps.getAlunoDAO().salvar(new Aluno("Ana Carolina", "ana@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Ana Beatriz", "anabeatriz@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Antonio Carlos", "antonio@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Aline B. R.", "aline@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Cecilia Duarte", "cecilia@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Maria Isabel", "mariaisabel@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Carlos Renato", "carlosrenato@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Susana", "susana@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Monica", "monmica@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Cebolinha", "cebolinha@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Chico Bento", "chicobento@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Magali", "magali@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Anginho", "anginho@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Cascao", "cascao@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("zeca Urubu", "eca@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Pica Pau", "picapau@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("zé Carioca", "cariona@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Tio Patinhas", "tiopatinhas@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Xuxa", "xuxa@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Sheila", "sh@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Hebe Camargo", "hebe@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Jonas", "jonas@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Igor", "@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Magnum", "@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Princila", "@gmail.com"));
// ps.getAlunoDAO().salvar(new Aluno("Maria Cecilia", "@gmail.com"));


}
}

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;

import java.util.List;

/**
*
* @author Fabiel Prestes
*
*/
public class Paginacao {

private int totalDados;
private List<? extends Object> listaDados;

public Paginacao(){

}

/**
* @return the totalDados
*/
public int getTotalDados() {
return totalDados;
}
/**
* @param totalDados the totalDados to set
*/
public void setTotalDados(int totalDados) {
this.totalDados = totalDados;
}
/**
* @return the listaDados
*/
public List<? extends Object> getListaDados() {
return listaDados;
}
/**
* @param listaDados the listaDados to set
*/
public void setListaDados(List<? extends Object> listaDados) {
this.listaDados = listaDados;
}


}

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;
public class Aluno {
    private Integer id;
    private String nome;
    private String email;

    public Aluno(){
    }

    public Aluno(String nome, String email){
        this.nome = nome;
        this.email = email;
    }

    /**
     * @return the id
     */
    public Integer getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(Integer id) {
        this.id = id;
    }

    /**
     * @return the nome
     */
    public String getNome() {
        return nome;
    }

    /**
     * @param nome the nome to set
     */
    public void setNome(String nome) {
        this.nome = nome;
    }

    /**
     * @return the email
     */
    public String getEmail() {
        return email;
    }

    /**
     * @param email the email to set
     */
    public void setEmail(String email) {
        this.email = email;
    }
}
/**
 *
 */
package com.imaster;
/**
 * @author Fabiel
 *
 */
public class Excecoes extends Exception{
    private static final long serialVersionUID = 1L;

    public Excecoes(String mensagem, Exception e) {
        super(mensagem, e);
    }

    public Excecoes(String mensagem) {
        super(mensagem);
    }

    public static void print(Exception e, String mensagem) {
        System.out.println("==============Exception===============");
        System.out.println(mensagem);
        System.out.println("PrintStackTrace: ");
        e.printStackTrace();
        System.out.println("============End Exception=============");
    }

    public void print() {
        System.out.println("==============Exception===============");
        System.out.println(getMessage());
        System.out.println("PrintStackTrace: ");
        getCause().printStackTrace();
        System.out.println("============End Exception=============");
    }
}

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

É 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.