Paginação é um conceito ou melhor, uma técnica para dividir o conjunto de resultados em pequenos páginas para o usuário navegar através dele com facilidade. Paginação por definição, é um processo para dividir o conteúdo em páginas menores.

Antes do curso de Tecnologia da Informação, a paginação foi um processo totalmente manual e o layout de impressão era a única intenção. Mas a paginação atualmente é feita principalmente para aumentar a velocidade dos dados, ao buscar em um determinado site/software. Buscando todos os dados de uma só vez é um trabalho intensivo e lento de recursos, também o usuário que tem que ver toda a lista tem uma má experiência devido à quantidade de dados que ele tem para percorrer. Sites bem implementados sempre cuidam dessas questões e proporcionam uma experiência com o usuário mais amigável.

Paginação pode ser utilizada no lado do servidor e do lado do cliente.

A paginação do lado do servidor é usado quando:

  • É necessário um carregamento mais rápido da página inicial.
  • Lógica de negócios complexa é necessário.
  • Há grandes conjunto de dados.

Paginação do lado do cliente é usado quando:

  • O conjunto de dados é pequeno.
  • Carregamento da página subseqüente é mais rápido.
  • Suporte total para classificação e filtragem.

Caso se esteja paginando para fins dométicos então é aconselhável usar o mecanismo do lado do cliente. Mas se você está paginando para reduzir o tempo de carregamento inicial então do lado do servidor é a melhor escolha.

Paginação é dependente de framework. A API regular usada para paginar em uma página web pode não funcionar em uma aplicação Swing (desktop).

Formas de Paginação

Usando um ready-made paginação API

Este método é útil, bem como tem os seus próprios problemas. Em primeiro lugar a API readymade é mais fácil de encontrar e usar as funções embutidas para paginar os resultados. Tudo o que precisa ser feito é dar os detalhes da API do número de resultados e quantas páginas para exibir, etc. o código API é dada abaixo:


<pagination-tag:pager start="<%=start%>" range="<%=range%>" 
results="<%=results%>"/>

O número de resultados, a posição de início e o intervalo é tudo o que a API precisa para fazer seu trabalho e paginar o resultado. Isso requer o mínimo de trabalho do lado do desenvolvedor. O código de paginação está disponível a partir da biblioteca de tags.

O desenvolvedor precisa conhecer as funções da API e o resto é tratado pela própria API. Mas, embora essas APIs reduzam o tempo de desenvolvimento, eles não são tão flexíveis quanto pode ser necessário em alguns momentos.

Criando sua própria lógica de paginação

Existem duas maneiras principais de criar lógica de paginação. A primeira maneira é buscar todos os resultados e, em seguida, apresentá-los para o usuário a partir de um cache. A outra opção é buscar o resultado e escolher como e quando os usuários irão acessá-los. Este método é normalmente conhecido como greedy fetching (busca ganaciosa).

Greedy Fetching

Quando se usa greedy fetching um padrão chamado de ValueListHandler é particularmente muito útil. Este padrão pode ser reutilizado em várias consultas e pode ajudar o processo de paginação. Uma ilustração do diagrama da classe ValueListHandler é apresentado abaixo:

Diagrama de Classe
Figura 1. Diagrama de Classe

O Cliente utiliza uma ValueListHandler, que por sua vez chama um DAO para gerar um ValueList. Cada ValueList contem alguns objetos de valor. Cada vez que a solicitação do usuário para um conjunto de resultados a serem exibidos ao ValueListHandler é feita, uma sub classe de ValueList, os trata.

Como o ValueList armazena o resultado, a necessidade de ir para o banco de dados novamente para buscar o próximo conjunto de dados é eliminada quando o usuário solicitá-lo. Cada vez que o ValueListHandler fornece os resultados das páginas de resultados next/previous (seguinte/anterior).

Not-So-Greedy fetching

Vamos primeiro discutir o inconveniente do modelo acima referido greedy fetching, só então, podemos entender claramente a necessidade deste método. Imagine uma situação onde há um, 100 mil registros que correspondem a uma consulta particular.

Buscando no greedy fecthing, o usuário terá que esperar por muito tempo até que todos os registros são obtidos no cache do ValueListHandler. E além disso os valores tornam-se obsoletos, uma vez obtida. Ou seja, se os registros são atualizados uma vez que os registros são armazenados em cache, em seguida, os valores podem não refletir os resultados atualizados. Assim, se um aplicativo atualiza dados com freqüência, então o greedy fetching pode não ser a melhor solução para paginação. Para superar estes inconvenientes, o método Not-So-Greedy é recomendado. Neste método, apenas um número limitado de resultados são obtidos ao mesmo tempo. Por exemplo, um código do Oracle é mostrado:


select * 
from ( select /*+ FIRST_ROWS(n) */ a.*, ROWNUM rwnum 
   from ( user query, with order by )a 
   where ROWNUM <= :MAX_ROW_TO_FETCH ) 
where rwnum>= :MIN_ROW_TO_FETCH;
Listagem 1. Exemplo de código para exibição de consulta Oracle para buscar dados para paginação

<%@ page import="java.sql.PreparedStatement"%> 
<%@ page import="java.sql.ResultSet" %> 
<%@ page import="java.sql.Connection" %> 
<%@ page import="java.sql.DriverManager" %> 
<%! 
public int Converter(String str) 
{    
    int convrtr=0; 
    if(str==null) 
        { 
            str="0"; 
        } 
    else if((str.trim()).equals("null")) 
        { 
            str="0"; 
        } 
    else if(str.equals("")) 
        { 
            str="0"; 
        } 
    try{ 
            convrtr=Integer.parseInt(str); 
        } 
    catch(Exception e) 
        { 
        } 
    return convrtr; 
} 
%> 
<% 
    Connection con = null; 
    Class.forName("com.mysql.jdbc.Driver").newInstance(); 
    con = DriverManager
    .getConnection("jdbc:mysql://localhost:3306/DataBase","uname", "pwd"); 
  
    ResultSet rsPgin = null; 
    ResultSet rsRwCn = null; 
    PreparedStatement psPgintn=null; 
    PreparedStatement psRwCn=null; 
      
    // Number of records displayed on each page 
    int iSwRws=5;   
    // Number of pages index displayed 
    int iTotSrhRcrds=10;  
      
    int iTotRslts=Converter(request.getParameter("iTotRslts")); 
    int iTotPags=Converter(request.getParameter("iTotPags")); 
    int iPagNo=Converter(request.getParameter("iPagNo")); 
    int cPagNo=Converter(request.getParameter("cPagNo")); 
  
    int iStRsNo=0; 
    int iEnRsNo=0; 
  
    if(iPagNo==0) 
        { 
            iPagNo=0; 
        } 
    else{ 
            iPagNo=Math.abs((iPagNo-1)*iSwRws); 
        } 
      
    String sqlPgintn="SELECT SQL_CALC_FOUND_ROWS * 
    FROM tableName limit "+iPagNo+","+iSwRws+""; 
    psPgintn=con.prepareStatement(sqlPgintn); 
    rsPgin=psPgintn.executeQuery(); 
    // Count total number of fetched rows 
    String sqlRwCnt="SELECT FOUND_ROWS() as cnt"; 
    psRwCn=con.prepareStatement(sqlRwCnt); 
    rsRwCn=psRwCn.executeQuery(); 
      
    if(rsRwCn.next()) 
      { 
        iTotRslts=rsRwCn.getInt("cnt"); 
      } 
%> 
<html> 
    <head> 
        <title>Pagination using JSP page</title> 
    </head> 
<body> 
    <form name="frm"> 
        <input type="hidden" name="iPagNo" value="<%=iPagNo%>"> 
        <input type="hidden" name="cPagNo" value="<%=cPagNo%>"> 
        <input type="hidden" name="iSwRws" value="<%=iSwRws%>"> 
          
        <table width="100%" cellpadding="0" cellspacing="0" border="0" > 
        <tr> 
        <td>Emp Name</td> 
        <td>Emp Batch</td> 
        <td>Emp Address</td> 
        </tr> 
<% 
    while(rsPgin.next()) 
      { 
%> 
        <tr> 
            <td><%=rsPgin.getString("EmpName")%></td> 
            <td><%=rsPgin.getString("EmpBatchs")%></td> 
            <td><%=rsPgin.getString("EmpAddress")%></td> 
        </tr> 
<%  
     } 
%> 
<% 
    // Calculate next record start and end position  
    try{ 
        if(iTotRslts<(iPagNo+iSwRws)) 
            { 
                iEnRsNo=iTotRslts; 
            } 
        else
            { 
                iEnRsNo=(iPagNo+iSwRws); 
            } 
  
            iStRsNo=(iPagNo+1); 
            iTotPags=((int)(Math.ceil((double)iTotRslts/iSwRws))); 
        } 
    catch(Exception e) 
        { 
                e.printStackTrace(); 
        } 
%> 
<tr> 
<td colspan="3"> 
<div> 
<% 
     // Create index of pages  
    int i=0; 
    int cPge=0; 
    if(iTotRslts!=0) 
       { 
        cPge=((int)(Math.ceil((double)iEnRsNo/(iTotSrhRcrds*iSwRws)))); 
        int prePageNo=(cPge*iTotSrhRcrds)-((iTotSrhRcrds-1)+iTotSrhRcrds); 
        if((cPge*iTotSrhRcrds)-(iTotSrhRcrds)>0) 
            { 
        %> 
        <a href="index.jsp?iPagNo=<%=prePageNo%
        >&cPagNo=<%=prePageNo%>"><< Previous</a> 
        <% 
        } 
          
        for(i=((cPge*iTotSrhRcrds)-(iTotSrhRcrds-1));i<=(cPge*iTotSrhRcrds);i++) 
        { 
            if(i==((iPagNo/iSwRws)+1)) 
            { 
            %> 
        <a href="index.jsp?iPagNo=<%=i%>" 
        style="cursor:pointer;color:red"><b>
        <%=i%></b></a> 
            <% 
            } 
            else if(i<=iTotPags) 
            { 
            %> 
        <a href="index.jsp?iPagNo=<%=i%>"><%=i%></a> 
            <%  
            } 
        } 
      
        if(iTotPags>iTotSrhRcrds&& i<iTotPags) 
        { 
         %> 
        <a href="index.jsp?iPagNo=<%=i%
        >&cPagNo=<%=i%>">>> Next</a> 
        <% 
        } 
      } 
      %> 
    <b>Rows <%=iStRsNo%> - <%=iEnRsNo%>   
    Total Result  <%=iTotRslts%></b> 
</div> 
</td> 
</tr> 
</table> 
</form> 
</body> 
</html> 
<% 
try{ 
    if(psPgintn!=null){ 
        psPgintn.close(); 
    } 
    if(rsPgin!=null){ 
        rsPgin.close(); 
    }    
    if(psRwCn!=null){ 
        psRwCn.close(); 
    } 
    if(rsRwCn!=null){ 
        rsRwCn.close(); 
    } 
    if(con!=null){ 
        con.close(); 
    } 
  } 
catch(Exception e) 
  { 
    e.printStackTrace(); 
  } 
%> 
Listagem 2. Exemplo completo de paginação

Esta paginação é baseada no mysql. A página terminada é mostrado abaixo:

Exibindo saída de paginação
Figura 2. Exibindo saída de paginação

Conclusão

Assim, podemos concluir que a paginação é uma técnica para processar dados de forma adequada, que é eficiente e fácil de usar. Como sabemos buscar milhões de registros em uma única consulta de banco de dados consome quase toda a memória e CPU da máquina, desse modo a paginação é usado na maioria das aplicações para aumentar o desempenho. Para conseguir isso, milhões de discos são divididos em pequenos pedaços para a exibição de um número limitado de registros (digamos, 30 ou 40) por página. A maioria dos motores de busca como o Google e outros usam técnica de paginação para buscar resultado da pesquisa.