Commit 7ec39503013e8dc400c0abe8bddd80e9eb455292

Authored by Emerson Oliveira
1 parent ddf1a667
Exists in master

Inclusão do capítulo de Paginação no Guia de Referencia do Demoiselle.

documentation/reference/pt-BR/master.xml
@@ -41,7 +41,7 @@ @@ -41,7 +41,7 @@
41 <xi:include href="logger.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> 41 <xi:include href="logger.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
42 <xi:include href="templates.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> 42 <xi:include href="templates.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
43 <xi:include href="security.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> 43 <xi:include href="security.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
44 - <!-- <xi:include href="paginacao.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> --> 44 + <xi:include href="paginacao.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
45 <xi:include href="properties.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> 45 <xi:include href="properties.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
46 </part> 46 </part>
47 <!-- parte 2 --> 47 <!-- parte 2 -->
documentation/reference/pt-BR/paginacao.xml
@@ -3,179 +3,288 @@ @@ -3,179 +3,288 @@
3 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" []> 3 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" []>
4 <chapter id="paginacao"> 4 <chapter id="paginacao">
5 5
6 - <title>Paginação</title> 6 + <title>Paginação</title>
7 7
8 - <para>  
9 - Neste capítulo serão considerados os seguintes assuntos:  
10 - <itemizedlist>  
11 - <listitem>motivação para o uso de um mecanismo padronizado para <emphasis>paginação</emphasis>;</listitem>  
12 - <listitem>funcionamento e uso da estrutura <literal>Pagination</literal> e do contexto de paginação (<literal>PaginationContext</literal>).</listitem>  
13 - </itemizedlist>  
14 - </para>  
15 -  
16 - <section>  
17 - <title>Introdução ao mecanismo</title>  
18 - <para>  
19 - A apresentação de conjuntos de registros de médio a grande porte em formato de tabelas em aplicações Web geralmente requer um  
20 - <emphasis>mecanismo de paginação</emphasis>, o qual permite ao cliente ver apenas um pedaço do resultado final, podendo este  
21 - navegar para frente e para trás através dos registros. A menos que o conjunto de registros seja garantidamente pequeno, qualquer  
22 - aplicação do tipo Web com funcionalidades de busca precisa ser dotada de paginação.  
23 - </para>  
24 - <para>  
25 - O mecanismo de paginação para as aplicações fornecido pelo <emphasis>Demoiselle Framework</emphasis> consiste em um algoritmo de  
26 - direcionado ao banco de dados (i.e., Database-Driven Pagination). Essa abordagem, apesar de requerer instruções SQL específicas  
27 - para obter porções determinadas de registros, é a mais utilizada por ser mais eficiente e produzir menos redundância dos dados.  
28 - </para>  
29 - <para>  
30 - É fornecido em tempo de execução um <emphasis>contexto de paginação</emphasis>, o qual tem escopo de sessão e armazena a informação  
31 - de paginação de cada entidade (i.e., bean) que necessite de tal mecanismo. Esse contexto é compartilhado entre as diversas camadas  
32 - da aplicação, especificamente entre as camadas de visão e persistência. Dessa maneira, a paginação dos dados é transparente para a  
33 - camada intermediária (i.e., negócio) e não interfere na modelagem das classes de um projeto.  
34 - </para>  
35 - </section>  
36 -  
37 - <section>  
38 - <title>Códigos de suporte</title>  
39 - <!--  
40 - <para>  
41 - // TODO: explicar Pagination e PaginationContext  
42 - </para>  
43 - -->  
44 - <para>  
45 - Veremos na seção seguinte como implementar a paginação em uma aplicação Java.  
46 -  
47 - - Farão parte do código de suporte para paginação:  
48 - * a classe Pagination: usada para manipular a paginação dos dados resultantes, contendo os campos currentPage (página atual, selecionada na camada de visão), pageSize (tamanho da página, a quantidade de registros que ela comportará) e totalResults (a quantidade de resultados existentes na base de dados);  
49 - * a classe PaginationContext: contexto usado para armazenar e fornecer estruturas do tipo Pagination;  
50 - * a classe PaginationConfig: armazenador de configurações referentes à paginação.  
51 -  
52 -- Códigos internos de suporte no Core:  
53 -  
54 - <programlisting role="JAVA"><![CDATA[  
55 -  
56 -public class Pagination {  
57 -  
58 - private int currentPage;  
59 - private int pageSize;  
60 -  
61 - private Long totalResults;  
62 - private Integer totalPages;  
63 -  
64 - // ...  
65 -}  
66 -  
67 -@SessionScoped  
68 -public class PaginationContext {  
69 -  
70 - private final Map<Class<?>, Pagination> map;  
71 -  
72 - public Pagination getPagination(Class<?> clazz) { ... }  
73 -  
74 - public Pagination get -->Pagination(Class<?> clazz, boolean create) { ... }  
75 -  
76 -}  
77 -  
78 -@Configuration  
79 -public class PaginationConfig {  
80 -  
81 - @Key("default_page_size")  
82 - private int defaultPageSize = 10;  
83 -  
84 - @Key("max_page_links")  
85 - private int maxPageLinks = 5;  
86 -  
87 -}  
88 -  
89 - - Códigos internos de suporte em JPA:  
90 -  
91 -public class JPACrud<T, I> implements Crud<T, I> {  
92 -  
93 - @Inject  
94 - private PaginationContext paginationContext;  
95 -  
96 - // ...  
97 -  
98 - public List<T> findAll() {  
99 -  
100 - final String jpql = "select this from " + getBeanClass().getSimpleName() + " this";  
101 - final Query query = getEntityManager().createQuery(jpql);  
102 -  
103 - final Pagination pagination = paginationContext.getPagination(getBeanClass());  
104 - if (pagination != null) {  
105 - if (pagination.getTotalPages() == null) {  
106 - pagination.setTotalResults(this.countAll());  
107 - }  
108 - query.setFirstResult(pagination.getFirstResult());  
109 - query.setMaxResults(pagination.getPageSize());  
110 - }  
111 -  
112 - // ...  
113 - }  
114 -  
115 -}  
116 -  
117 - - Códigos internos de suporte em JSF:  
118 -  
119 -public abstract class AbstractListPageBean<T, I> extends AbstractPage implements ListPageBean<T, I> {  
120 -  
121 - @Inject  
122 - private PaginationContext paginationContext;  
123 -  
124 - @Inject  
125 - private PaginationConfig paginationConfig;  
126 -  
127 - // ...  
128 -  
129 - public Pagination getPagination() {  
130 - return paginationContext.getPagination(getBeanClass(), true);  
131 - }  
132 -  
133 - public int getPageSize() {  
134 - return paginationConfig.getDefaultPageSize();  
135 - }  
136 -  
137 - public int getMaxPageLinks() {  
138 - return paginationConfig.getMaxPageLinks();  
139 - }  
140 -  
141 -}  
142 -  
143 -frameworkdemoiselle.pagination.default_page_size=50  
144 -frameworkdemoiselle.pagination.max_page_links=10  
145 -  
146 -]]></programlisting>  
147 - </para>  
148 - </section> 8 + <para>
  9 + Neste capítulo serão considerados os seguintes assuntos:
  10 + <itemizedlist>
  11 + <listitem><para>Motivação para o uso de um mecanismo padronizado para <emphasis>paginação</emphasis>;</para></listitem>
  12 + <listitem><para>Funcionamento e uso da estrutura <literal>Pagination</literal> e do contexto de paginação
  13 + (<literal>PaginationContext</literal>).</para></listitem>
  14 + </itemizedlist>
  15 + </para>
  16 +
  17 + <section>
  18 + <title>Introdução ao mecanismo</title>
  19 + <para>
  20 + A apresentação de conjuntos de registros de médio a grande porte em formato de tabelas em aplicações Web geralmente requer um
  21 + <emphasis>mecanismo de paginação</emphasis>, o qual permite ao cliente ver apenas um pedaço do resultado final, podendo este
  22 + navegar para frente e para trás através dos registros. A menos que o conjunto de registros seja garantidamente pequeno, qualquer
  23 + aplicação do tipo Web com funcionalidades de busca precisa ser dotada de paginação.
  24 + </para>
  25 + <para>
  26 + O mecanismo de paginação para as aplicações fornecido pelo <emphasis>Demoiselle Framework</emphasis> consiste em um algoritmo
  27 + direcionado ao banco de dados (i.e., Database-Driven Pagination). Essa abordagem, apesar de requerer instruções SQL específicas
  28 + para obter porções determinadas de registros, é a mais utilizada por ser mais eficiente e produzir menos redundância de dados,
  29 + diminuindo assim tráfego de rede, consumo de memória e reduzindo o tempo de resposta.
  30 + </para>
  31 + <para>
  32 + É fornecido em tempo de execução um <emphasis>contexto de paginação</emphasis>, o qual tem escopo de sessão e armazena a informação
  33 + de paginação de cada entidade (i.e., bean) que necessite de tal mecanismo. Esse contexto é compartilhado entre as diversas camadas
  34 + da aplicação, especificamente entre as camadas de visão e persistência. Dessa maneira, a paginação dos dados é transparente para a
  35 + camada intermediária (i.e., negócio) e não interfere na modelagem das classes de um projeto.
  36 + </para>
  37 + </section>
  38 +
  39 + <section>
  40 + <title>Códigos de suporte</title>
  41 + <!--
  42 + <para>
  43 + // TODO: explicar Pagination e PaginationContext
  44 + </para>
  45 + -->
  46 + <para>
  47 + O <emphasis>mecanismo de paginação</emphasis> do <emphasis>Demoiselle Framework</emphasis> permite que os parâmetros para a consulta
  48 + no banco sejam configurados de forma bastante prática. Por outro lado, a consulta paginada ao banco já é feita pela extensão
  49 + <literal>demoiselle-jpa</literal>. Dessa forma, basta ajustar os parametros da paginação, e pedir as consultas normalmente.
  50 + O resultado da consulta é então passado para algum componente de iteração de dados com suporte ao mecanismo conhecido como <emphasis>Lazy
  51 + Load</emphasis> (ou <emphasis>Lazy Loading</emphasis>).
  52 + </para>
  53 + <para>
  54 + Farão parte do código de suporte para paginação:
  55 + <itemizedlist>
  56 + <listitem>
  57 + <para>
  58 + A classe <literal>Pagination</literal>: usada para manipular a paginação dos dados resultantes, contendo os campos <literal>currentPage</literal>
  59 + (página atual, selecionada na camada de visão), <literal>pageSize</literal> (tamanho da página, a quantidade de registros que ela comportará)
  60 + e <literal>totalResults</literal> (a quantidade de resultados existentes na base de dados);
  61 + </para>
  62 + </listitem>
  63 + <listitem>
  64 + <para>
  65 + A classe <literal>PaginationContext</literal>: contexto usado para armazenar e fornecer estruturas do tipo <literal>Pagination</literal>;
  66 + </para>
  67 + </listitem>
  68 + <listitem>
  69 + <para>
  70 + A classe <literal>PaginationConfig</literal>: armazenador de configurações referentes à paginação.
  71 + </para>
  72 + </listitem>
  73 + </itemizedlist>
  74 + </para>
  75 +
  76 + <para>Códigos internos de suporte no Core:</para>
  77 +
  78 + <programlisting role="JAVA"><![CDATA[
  79 + public class Pagination {
  80 +
  81 + private int currentPage;
  82 + private int pageSize;
  83 +
  84 + private Long totalResults;
  85 + private Integer totalPages;
  86 +
  87 + // ...
  88 + }
  89 +
  90 + @SessionScoped
  91 + public class PaginationContext {
  92 +
  93 + private final Map<Class<?>, Pagination> map;
  94 +
  95 + public Pagination getPagination(Class<?> clazz) { ... }
  96 +
  97 + public Pagination get -->Pagination(Class<?> clazz, boolean create) { ... }
  98 +
  99 + }
  100 +
  101 + @Configuration
  102 + public class PaginationConfig {
  103 +
  104 + @Key("default_page_size")
  105 + private int defaultPageSize = 10;
  106 +
  107 + @Key("max_page_links")
  108 + private int maxPageLinks = 5;
  109 +
  110 + }
  111 + ]]></programlisting>
  112 +
  113 + <para>Códigos internos de suporte em JPA:</para>
  114 +
  115 + <programlisting role="JAVA"><![CDATA[
  116 + public class JPACrud<T, I> implements Crud<T, I> {
  117 +
  118 + @Inject
  119 + private PaginationContext paginationContext;
  120 +
  121 + // ...
  122 +
  123 + public List<T> findAll() {
  124 +
  125 + final String jpql = "select this from " + getBeanClass().getSimpleName() + " this";
  126 + final Query query = getEntityManager().createQuery(jpql);
  127 +
  128 + final Pagination pagination = paginationContext.getPagination(getBeanClass());
  129 + if (pagination != null) {
  130 + if (pagination.getTotalPages() == null) {
  131 + pagination.setTotalResults(this.countAll());
  132 + }
  133 + query.setFirstResult(pagination.getFirstResult());
  134 + query.setMaxResults(pagination.getPageSize());
  135 + }
  136 +
  137 + // ...
  138 + }
  139 +
  140 + }
  141 + ]]></programlisting>
  142 +
  143 + <para>Códigos internos de suporte em JSF:</para>
  144 +
  145 + <programlisting role="JAVA"><![CDATA[
  146 + public abstract class AbstractListPageBean<T, I> extends AbstractPage
  147 + implements ListPageBean<T, I> {
  148 +
  149 + @Inject
  150 + private PaginationContext paginationContext;
  151 +
  152 + @Inject
  153 + private PaginationConfig paginationConfig;
  154 +
  155 + // ...
  156 +
  157 + public Pagination getPagination() {
  158 + return paginationContext.getPagination(getBeanClass(), true);
  159 + }
  160 +
  161 + public int getPageSize() {
  162 + return paginationConfig.getDefaultPageSize();
  163 + }
  164 +
  165 + public int getMaxPageLinks() {
  166 + return paginationConfig.getMaxPageLinks();
  167 + }
  168 +
  169 + }
  170 + ]]></programlisting>
  171 + </section>
149 172
150 - <section>  
151 - <title>Implementação na aplicação</title>  
152 - <para>  
153 - Eis um exemplo de implementação de paginação em uma aplicação:  
154 - </para>  
155 - <programlisting role="JAVA"><![CDATA[  
156 - @Inject  
157 - private PaginationContext paginationContext;  
158 -]]></programlisting>  
159 - <programlisting role="JAVA"><![CDATA[  
160 - Pagination pagination = paginationContext.getPagination(Audit.class);  
161 -]]></programlisting>  
162 - <tip>  
163 - <para>  
164 - O método <literal>getPagination()</literal> do contexto <literal>PaginationContext</literal> é sobrecarregado, podendo aceitar  
165 - os seguintes argumentos: <literal>Class</literal> ou <literal>Class</literal> e <literal>boolean</literal>.  
166 - </para>  
167 - </tip>  
168 - <note>  
169 - <para>  
170 - A JPA 2.0, através da Query API, suporta controle de paginação independente de fornecedor de banco de dados.  
171 - Para controlar a paginação, a interface <literal>Query</literal> define os métodos <literal>setFirstResult()</literal> e  
172 - <literal>setMaxResults()</literal> para especificar o primeiro resultado a ser recebido e o número máximo de resultados a  
173 - serem retornados em relação àquele ponto. Internamente, são usadas instruções específicas do SGBD (ex: LIMIT e OFFSET no  
174 - PostgreSQL).  
175 - </para>  
176 - </note> 173 + <section>
  174 + <title>Implementação na aplicação</title>
  175 + <para>
  176 + Veremos nessa seção como implementar a paginação em uma aplicação Java. Para esse exmplo tomamos como base a aplicação de Bookmarks
  177 + fornecida pelo arquétipo <emphasis>JSF com JPA</emphasis> do <emphasis>Demoiselle Framework</emphasis> (para maiores detalhes
  178 + ver <link linkend="estrutura">Arquétipos</link>). Iremos utilizar o componente <literal>DataTable</literal> do <emphasis>PrimeFaces</emphasis>,
  179 + que oferece o mecanismo de <emphasis>Lazy Loading</emphasis> conhecido como <literal>LazyDataModel</literal>, muito útil para paginação
  180 + e classificação de dados.
  181 + </para>
  182 + <para>
  183 + Primeiro é preciso configurar um objeto <literal>LazyDataModel</literal> no construtor do <emphasis>Managed Bean</emphasis>
  184 + (<emphasis>BookmarkList</emphasis> nesse exemplo): instancia-lo e sobrescrever o método abstrado <literal>load</literal>, que recebe
  185 + vários argumentos. Esses argumentos são recuperados na página <literal>jsf</literal> que carrega a instância do objeto <literal>LazyDataModel</literal>.
  186 + </para>
  187 + <para>
  188 + Dentro do método <literal>load</literal> iremos pegar do contexto de paginação uma instância da implementação da interface <literal>Pagination</literal>
  189 + e ajustar alguns dos seus parâmetros para: indicar a partir de qual item a paginação deve iniciar, e o tamanho (quantidade de itens) de cada página.
  190 + Esses dados são usados no método <literal>findAll()</literal>, da classe <literal>JPACrud</literal> (extensão JPA), que utiliza o contexto de
  191 + paginação para pegar os parametros e fazer a consulta no banco buscando apenas os itens que estão dentro da pagina que o parametro
  192 + <literal>first</literal> indicar. O resultado é passado para a instancia do <literal>LazyDataModel</literal>, que é responsável por exibir
  193 + os dados de forma apropriada.
  194 + </para>
  195 + <para>
  196 + À classe <emphasis>BookmarkList</emphasis> devem ser adicionados os seguintes trechos de código:
  197 + </para>
  198 +
  199 + <programlisting role="JAVA"><![CDATA[
  200 + // ...
  201 + import java.util.Map;
  202 + import br.gov.frameworkdemoiselle.pagination.Pagination;
  203 +
  204 + // ...
  205 + private LazyDataModel<Bookmark> lazyModel;
  206 +
  207 + public BookmarkListMB() {
  208 + lazyModel = new LazyDataModel<Bookmark>() {
  209 +
  210 + @Override
  211 + public List<Bookmark> load (int first, int pageSize, String sortField,
  212 + SortOrder sortOrder, Map<String, String> filters){
  213 +
  214 + Pagination pagination = getPagination();
  215 + pagination.setPageSize(pageSize);
  216 + pagination.setFirstResult(first);
  217 +
  218 + List<Bookmark> itemsList = bc.findAll();
  219 +
  220 + lazyModel.setRowCount(pagination.getTotalResults());
  221 +
  222 + return itemsList;
  223 + }
  224 + };
  225 + }
  226 +
  227 + // ...
  228 +
  229 + public LazyDataModel<Bookmark> getLazyModel() {
  230 + return lazyModel;
  231 + }
  232 +
  233 + // ...
  234 + ]]></programlisting>
  235 +
  236 + <para>
  237 + No arquivo <literal>messages.properties</literal> adicione as linhas:
  238 + </para>
  239 +
  240 + <programlisting role="JAVA"><![CDATA[
  241 + page.first=0
  242 + page.rows=4
  243 + page.max.links=3
  244 + ]]></programlisting>
  245 +
  246 + <para>
  247 + Na página JSF <literal>bookmark_list.xhtml</literal>, substitua a linha:
  248 + </para>
  249 +
  250 + <programlisting role="JAVA"><![CDATA[
  251 + <p:dataTable id="list" var="bean" value="#{bookmarkListMB.resultList}">
  252 + ]]></programlisting>
  253 +
  254 + <para>
  255 + por:
  256 + </para>
  257 +
  258 + <programlisting role="JAVA"><![CDATA[
  259 + <p:dataTable id="list" var="bean"
  260 + value="#{bookmarkListMB.lazyModel}" lazy="true" paginator="true"
  261 + first="#{messages['page.first']}" rows="#{messages['page.rows']}"
  262 + pageLinks="#{messages['page.max.links']}">
  263 + ]]></programlisting>
  264 +
  265 + <para>
  266 + Com essas alterações simples, a aplicação Bookmarks passa a utilizar o mecanismo de paginação oferecido pelo <emphasis>Demoiselle Framework</emphasis>.
  267 + </para>
  268 +
  269 + <tip>
  270 + <para>
  271 + O método <literal>getPagination()</literal> do contexto <literal>PaginationContext</literal> é sobrecarregado, podendo aceitar
  272 + os seguintes argumentos: <literal>Class</literal> ou <literal>Class</literal> e <literal>boolean</literal>.
  273 + </para>
  274 + </tip>
  275 + <note>
  276 + <para>
  277 + A JPA 2.0, através da Query API, suporta controle de paginação independente de fornecedor de banco de dados.
  278 + Para controlar a paginação, a interface <literal>Query</literal> define os métodos <literal>setFirstResult()</literal> e
  279 + <literal>setMaxResults()</literal> para especificar o primeiro resultado a ser recebido e o número máximo de resultados a
  280 + serem retornados em relação àquele ponto. Internamente, são usadas instruções específicas do SGBD (ex: LIMIT e OFFSET no
  281 + PostgreSQL).
  282 + </para>
  283 + </note>
177 </section> 284 </section>
178 285
  286 +</chapter>
  287 +
179 <!--<section> 288 <!--<section>
180 <title>Um exemplo usando PrimeFaces</title> 289 <title>Um exemplo usando PrimeFaces</title>
181 <para> 290 <para>
@@ -238,7 +347,7 @@ public class AuditMB extends AbstractListPageBean&lt;Audit, Long&gt; { @@ -238,7 +347,7 @@ public class AuditMB extends AbstractListPageBean&lt;Audit, Long&gt; {
238 rows="#{auditMB.pageSize}" pageLinks="#{auditMB.maxPageLinks}">]]></programlisting> 347 rows="#{auditMB.pageSize}" pageLinks="#{auditMB.maxPageLinks}">]]></programlisting>
239 </section> 348 </section>
240 --> 349 -->
241 - 350 +<!--
242 <section> 351 <section>
243 <title>Referências</title> 352 <title>Referências</title>
244 <itemizedlist> 353 <itemizedlist>
@@ -246,8 +355,8 @@ public class AuditMB extends AbstractListPageBean&lt;Audit, Long&gt; { @@ -246,8 +355,8 @@ public class AuditMB extends AbstractListPageBean&lt;Audit, Long&gt; {
246 <listitem>Implementing Search Result Pagination in a Web Application (http://www.developer.com/java/other/article.php/3696226/)</listitem> 355 <listitem>Implementing Search Result Pagination in a Web Application (http://www.developer.com/java/other/article.php/3696226/)</listitem>
247 <listitem>A Pagination Technique Using Spring (http://www.developer.com/java/web/article.php/10935_3830886_1/)</listitem> 356 <listitem>A Pagination Technique Using Spring (http://www.developer.com/java/web/article.php/10935_3830886_1/)</listitem>
248 <listitem>Spring JDBC Pagination Tutorial (http://www.codefutures.com/tutorials/spring-pagination/)</listitem> 357 <listitem>Spring JDBC Pagination Tutorial (http://www.codefutures.com/tutorials/spring-pagination/)</listitem>
249 - <!-- <listitem>PrimeFaces DataTable - Lazy Loading (http://www.primefaces.org/showcase/ui/datatableLazy.jsf)</listitem> --> 358 + <listitem>PrimeFaces DataTable - Lazy Loading (http://www.primefaces.org/showcase/ui/datatableLazy.jsf)</listitem>
250 </itemizedlist> 359 </itemizedlist>
251 </section> 360 </section>
252 -  
253 -</chapter> 361 + -->
  362 +