Devido a desvantagens de desempenho, como o alto consumo de recursos, ao utilizar o cursor do ResultSet para implementar paginação de dados, uma abordagem mais eficiente em desenvolvimento real é empregar o mecanismo de paginação nativo do banco de dados.
A seguir, apresentaremos um exemplo utilizando o mecanismo de paginação do banco de dados MySQL.
Primeiro, criamos a classe ItemProduto, responsável por encapsular as informações dos produtos. Esta clasce funciona como um JavaBean para representar objetos de produto.
package modelo;
import java.math.BigDecimal;
public class ItemProduto {
public static final int TAMANHO_PAGINA = 2; // Número de registros por página
private int idProduto; // Identificador
private String nomeProduto; // Nome
private BigDecimal precoProduto; // Preço
public int getIdProduto() {
return idProduto;
}
public void setIdProduto(int idProduto) {
this.idProduto = idProduto;
}
public String getNomeProduto() {
return nomeProduto;
}
public void setNomeProduto(String nomeProduto) {
this.nomeProduto = nomeProduto;
}
public BigDecimal getPrecoProduto() {
return precoProduto;
}
public void setPrecoProduto(BigDecimal precoProduto) {
this.precoProduto = precoProduto;
}
}
Na classe ItemProduto, encapsulamos as informações básicas do objeto produto. Além disso, definimos o tamanho da página para paginação.
A seguir, criamos a classe RepositorioProduto, responsável por operações de banco de dados relacionadas aos produtos. Esta classe representa a camada de acesso a dados (DAO) para informações de produto.
package repositorio;
import modelo.ItemProduto;
import util.ConexaoBD;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class RepositorioProduto {
/**
* Busca todos os produtos com paginação
*
* @param pagina Número da página
* @return Lista de produtos
*/
public List<ItemProduto> buscarTodosProdutos(int pagina) {
List<ItemProduto> listaProdutos = new ArrayList<>();
Connection conexao = null;
PreparedStatement stmt = null;
ResultSet rs = null;
// A cláusula LIMIT especifica o ponto de início e o número de registros
String sql = "SELECT id_produto, nome_produto, preco_produto FROM produto ORDER BY id_produto LIMIT ?,?";
try {
conexao = ConexaoBD.obterConexao();
stmt = conexao.prepareStatement(sql);
stmt.setInt(1, (pagina - 1) * ItemProduto.TAMANHO_PAGINA);
stmt.setInt(2, ItemProduto.TAMANHO_PAGINA);
rs = stmt.executeQuery();
while (rs.next()) {
ItemProduto produto = new ItemProduto();
produto.setIdProduto(rs.getInt("id_produto"));
produto.setNomeProduto(rs.getString("nome_produto"));
produto.setPrecoProduto(rs.getBigDecimal("preco_produto"));
listaProdutos.add(produto);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
ConexaoBD.fechar(rs, stmt, conexao);
}
return listaProdutos;
}
/**
* Conta o total de registros
*
* @return Contagem total de registros
*/
public int contarTodosProdutos() {
int total = 0;
Connection conexao = null;
PreparedStatement stmt = null;
ResultSet rs = null;
String sql = "SELECT COUNT(*) FROM produto";
try {
conexao = ConexaoBD.obterConexao();
stmt = conexao.prepareStatement(sql);
rs = stmt.executeQuery();
if (rs.next()) {
total = rs.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
ConexaoBD.fechar(rs, stmt, conexao);
}
return total;
}
}
O método buscarTodosProdutos(int pagina) busca produtos de uma página específica. O parâmetro pagina indica qual página recuperar. O método contarTodosProdutos() obtém o total de registros. Isso permite saber quantas páginas serão necessárias.
Uma limitação desse método é que, quendo novos registros são inseridos, alguns itens podem não ser exibidos em consultas subsequentes, o que requer otimização.
Criamos a classe ListagemProdutos, um Servlet que trata as requisições de paginação de produtos. O método doGet() processa as solicitações de paginação.
package controle;
import modelo.ItemProduto;
import repositorio.RepositorioProduto;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/ListagemProdutos")
public class ListagemProdutos extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
// Lógica para requisições POST
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int paginaAtual = 1; // Página atual
if (request.getParameter("pagina") != null) {
paginaAtual = Integer.parseInt(request.getParameter("pagina"));
}
RepositorioProduto repositorio = new RepositorioProduto();
List<ItemProduto> listaProdutos = repositorio.buscarTodosProdutos(paginaAtual);
request.setAttribute("listaProdutos", listaProdutos);
int totalPaginas; // Total de páginas
int totalRegistros = repositorio.contarTodosProdutos();
if (totalRegistros % ItemProduto.TAMANHO_PAGINA == 0) {
totalPaginas = totalRegistros / ItemProduto.TAMANHO_PAGINA;
} else {
totalPaginas = totalRegistros / ItemProduto.TAMANHO_PAGINA + 1;
}
StringBuilder barraNavegacao = new StringBuilder();
for (int i = 1; i <= totalPaginas; i++) {
if (i == paginaAtual) {
barraNavegacao.append("[").append(i).append("]");
} else {
barraNavegacao.append("<a href='ListagemProdutos?pagina=").append(i)
.append("'>").append(i).append("</a>");
}
}
barraNavegacao.append(" ");
request.setAttribute("barraNavegacao", barraNavegacao.toString());
request.getRequestDispatcher("exibir_produtos.jsp").forward(request, response);
}
}
A classe ListagemProdutos realiza duas tarefas principais: obter o resultado da consulta paginada e construir a barra de navegação. A consulta paginada é implementada chamando o método buscarTodosProdutos(pagina) da classe RepositorioProduto. A barra de navegação é construída concatenando strings HTML e, em seguida, usando o objeto HttpServletRequest, o request é encaminhado para a página exibir_produtos.jsp para exibição.
Criamos a página exibir_produtos.jsp, que utiliza expressões EL e APIs Java para exibir os resultados da consutla e a barra de navegação.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title>Lista de Produtos</title>
</head>
<body>
| Informações dos Produtos ------------------------ |
|:-:|
| ID | Nome do Produto | Preço |
<foreach items="${requestScope.listaProdutos}" var="produto"> | ${produto.idProduto} | ${produto.nomeProduto} | ${produto.precoProduto} |
</foreach>| <%=request.getAttribute("barraNavegacao")%> |
</body>
</html>
Finalmente, apresentamos a classe utilitária ConexaoBD que encapsula a conexão com o banco de dados JDBC:
package util;
/**
* Utilitário para conexão com banco de dados
*/
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ConexaoBD {
/**
* Obtém conexão com o banco
*
* @return Conexão
* @throws Exception Exceção
*/
public static Connection obterConexao() throws Exception {
// Nome do driver JDBC
String nomeDriver = "com.mysql.jdbc.Driver";
Class.forName(nomeDriver);
// URL do banco de dados
String urlBanco = "jdbc:mysql://servidor:3306/banco?useUnicode=true&characterEncoding=UTF-8";
// Usuário do banco
String usuario = "usuario";
// Senha do banco
String senha = "senha";
Connection conexao = DriverManager.getConnection(urlBanco, usuario, senha);
return conexao;
}
/**
* Fecha conexão
*
* @param stmt Statement
* @param conn Connection
* @throws Exception Exceção
*/
public static void fechar(Statement stmt, Connection conn) throws Exception {
if (stmt != null) {
stmt.close();
if (conn != null) {
conn.close();
}
}
}
/**
* Fecha conexão
*
* @param cstmt CallableStatement
* @param conn Connection
* @throws Exception Exceção
*/
public static void fechar(CallableStatement cstmt, Connection conn) throws Exception {
if (cstmt != null) {
cstmt.close();
if (conn != null) {
conn.close();
}
}
}
/**
* Fecha conexão
*
* @param pstmt PreparedStatement
* @param conn Connection
* @throws SQLException Exceção SQL
*/
public static void fechar(PreparedStatement pstmt, Connection conn) {
if (pstmt != null) {
try {
pstmt.close();
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* Método sobrecarregado para fechar conexão
*
* @param rs ResultSet
* @param pstmt PreparedStatement
* @param conn Connection
* @throws Exception Exceção
*/
public static void fechar(ResultSet rs, PreparedStatement pstmt, Connection conn) {
if (rs != null) {
try {
rs.close();
if (pstmt != null) {
pstmt.close();
if (conn != null) {
conn.close();
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}