O componente p:dataTable do framework PrimeFaces permite implementar LazyLoading de forma muito simples bastando que o desenvolvedor estenda LazyDataModel<T>, onde T é o tipo da entidade que será carregada na tabela. Por exemplo, suponha que você tenha uma entidade Pessoa, você deveria extender LazyDataModel da seguinte forma:
public class LazyTablePessoa extends LazyDataModel<Pessoa>{ private PessoaService service; @Override public List<Pessoa> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) { List<Pessoa>listPessoa = pessoaService.getPessoas(first, first + pageSize); int linhas = pessoasService.countPessoas(); setRowCount(linhas); return listPessoa; } //... outros métodos }Essa abordagem possui um problema se o projeto for crescendo e um número cada vez maior de entidades demandar lazy loading em determinadas telas. Dessa forma seria necessário implementar LazyDataModel para cada entidade que você queira exibir. Se houver 100 entidades para listar, você terá que implementar 100 extensões de LazyDataModel, cada uma com o código praticamente idêntico!
Generic Lazy Data Table
Somente os dados exibidos são carregados na memória. |
Podemos reduzir drasticamente essa quantidade de implementações criando uma única extensão genérica de LazyDataModel que atenda, digamos, 90% de todas as necessidades de exibição, ou seja, você podera ter 100 entidades no seu modelo, mas uma única implementação de LazyDataModel será suficiente para listar as entidade de acordo com o padrão lazing.
Para implementar este padrão precisamos criar:
- Uma DataTable genérica que extenda LazyDataModel
- Uma interface de serviço genérica que busque os dados. As especificações de busca para cada entidade variam de acordo com a implementação.
O diagrama de classes abaixo resume o modelo:
Implementando o diagrama
Pessoa.javapublic class Pessoa { private String nome; private int idade; private Date nascimento; //métodos getters & setters }
GenericService.java
public interface GenericService<T> { //a quantidade de registros que serão carregados List<T> buscaPaginada(int inicio, int fim); //a quantidade de registros na fonte de dados int countLinhas(); }PessoaService
import java.util.ArrayList; import java.util.Date; import java.util.List; public class PessoaService implements GenericService<Pessoa>{ //representando o banco de dados private List<Pessoa> dataSource; public PessoaService() { dataSource = new ArrayList<>(); for(int i = 0; i < 100; i++){ Pessoa p = new Pessoa(); p.setNome("Pessoa "+i); p.setIdade(i); p.setNascimento(new Date()); dataSource.add(p); } } //implementação para a entidade pessoa //as regras podem variar de entidade para entidade... @Override public List<Pessoa> buscaPaginada(int inicio, int fim) { return dataSource.subList(inicio, fim); } @Override public int countLinhas() { return dataSource.size(); } }
Nossa implementação de GenericLazyDataTable. Repare que o tipo do objeto é genérico (T), ou seja, a princípio não se sabe qual é o tipo de objeto sendo buscado nem qual é o critério de busca, que
dependerá da implementação fornecida para a interface GenericService.
import java.util.List; import java.util.Map; import org.primefaces.model.LazyDataModel; import org.primefaces.model.SortOrder; public class GenericLazyDataTable<T> extends LazyDataModel<T>{ private final GenericService genericService; public GenericLazyDataTable(GenericService genericService) { this.genericService = genericService; } @Override public List<T> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) { int linhas = genericService.countLinhas(); this.setRowCount(linhas); return genericService.buscaPaginada(first, first + pageSize); } }
O managed bean controller da página JSF
import java.io.Serializable; import javax.annotation.PostConstruct; import javax.faces.view.ViewScoped; import javax.inject.Named; @Named @ViewScoped public class ManagedBean implements Serializable{ private GenericLazyDataTable genericLazyDataTable; private GenericService genericService; @PostConstruct public void init(){ genericService = new PessoaService(); genericLazyDataTable = new GenericLazyDataTable(genericService); } public GenericLazyDataTable getGenericLazyDataTable() { return genericLazyDataTable; } }
E a página inicial index.xhtml
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head> <title>Lazy Pessoa</title> </h:head> <h:body> <p:dataTable value="#{managedBean.genericLazyDataTable}" var="pessoa" lazy="true" rows="20" paginator="true"> <p:column headerText="nome"> <h:outputText value="#{pessoa.nome}" /> </p:column> <p:column headerText="idade"> <h:outputText value="#{pessoa.idade}" /> </p:column> <p:column headerText="nascimento"> <h:outputText value="#{pessoa.nascimento}" > <f:convertDateTime pattern="dd/MM/yyyy" locale="pt" /> </h:outputText> </p:column> </p:dataTable> </h:body> </html>
Estrutura do projeto na IDE NetBeans 8.1 (utilizando Maven)
Tornando a implementação ainda mais genérica
É possível tornar esse modelo ainda mais genérico. Por exemplo poderíamos criar um campo Map em GenericLazyDataTable e sobrecarregar o método buscaPaginada de GenericService para definir filtros de busca. Algo como:
private Map<String, Object> filtrosPersonalizados; //outros campos... //pode ser chamado pelo Managed Bean public void adicionarFiltro(String nomeDocampo, Object tipoDoCampo) { filtrosPersonalizados.put(campo, object); }
No comments:
Post a Comment