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 < _totalPorPagina; j++){
if(bpAtual.intervaloInicial
+ j < _totalDados)
_listaBaseAux.addItem(_listaBase.getItemAt(bpAtual.intervaloInicial
+ j));
}
FIM: @Removido */
/* Configurando os botoes de
avançar e retornar */
if(bpAtual.pagina > 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.
Abraço e até a próxima.