Paginação de Datatable Lazy com JSF (Primefaces)

Olá, tudo bem?

Vamos ver hoje como fazer uma paginação de um datatable JSF utilizando o modelo lazy em um managed bean de view scope. Quantos termos complicados em uma frase apenas.

Existem diversos frameworks JSF hoje no mercado que nos fornecem datatables prontos com paginação, ordenação e outras mais vantagens. Iremos utilizar como exemplo hoje o datatable do Primefaces.

É comum o datatable pegar todo a lista a ser exibida e alocar na sessão do usuário do servidor. Esse ato de alocar tudo na memória tem um impacto direto no desempenho do nosso servidor; cada usuário que exibir um datatable desse modo estará alocando mais espaço na memória do servidor.

Para ficar um pouco mais parecido com a vida real, no post de hoje será utilizado JPA e o HSQLDB como banco de dados, realizando as consultas com JPQL.

Ao final do post você irá encontrar o link para download do código fonte.

Iremos utilizar:

  • JSF 2.0 – Implementação JBoss 7
  • JBoss 7.1 – o tema proposto nesse post se aplica a qualquer servidor
  • Eclipse Indigo
  • JPA 2.0 – Implementação JBoss 7
  • HSQLDB (2.2.8) – O HSQL é um banco que roda na memória, apenas para facilitar nossa configuração.
  • Primefaces 3.2

Só para esclarecer, esse post não visa boas práticas ou colocar as devidas camadas de padrões de projetos. Pretendo apenas mostrar como aplicar paginação sem utilizar um managed bean de sessão.

66 thoughts on “Paginação de Datatable Lazy com JSF (Primefaces)

  1. Muito bacana o tutorial, só que essa linha:

    // set the page dize
    setPageSize(maxPerPage);

    deveria ser assim
    setPageSize(players.size());

    não?

    Abraço

    • Guilherme, boa noite.

      A função setPageSize(maxPerPage); serve para determinar a quantidade de registros que será exibida no datatable.

      Nesse caso, é um valor que o próprio Primefaces te fornece. Caso você utilize players.size() você irá definir que que ele deverá exibir o valor total da página.

      Espero ter ajudado,

      Obrigado pela visita.

      • Se você tiver apenas 3 registro , e o maxPerPage for 5.
        Será exibido somente 3 linhas ou 5 linhas (com em branco)?

        Abraço

        Obrigado pela atenção ; )

        • Olá Guilherme, boa noite.

          Vou perguntar para você igual eu pergunto aos meus alunos de java.

          Você fez o teste? O que aconteceu?

          Não entenda como má vontade minha, mas sou adepto à teoria de que: “vale mais a pena ensinar a pescar do que dar o peixe pronto”.

          Boa noite, inté+. [=

  2. Pingback: URL
  3. Consequi fazer um deste, mas se eu tento colocar o campo para filtro em um e passar esse parâmetro para a dao para fazer a pesquisa quando o usuario clicar em botao. Como faço? Ate consigo passar o parametro quando não tem a quando a coloco o parametro vem null. Tem ideia do que possa estar acontecendo?

  4. Olá amigao..ótima materia.

    mas no caso para funcionar o Filter do load() como é que ficaria?
    eu achei essa na net

    List predicates = new ArrayList();
    for(Iterator it = filters.keySet().iterator(); it.hasNext();) {
    String filterProperty = (String) it.next(); // table column name = field name
    String filterValue = (String) filters.get(filterProperty);

    Expression literal = criteriaBuilder.literal((String)filterValue);
    predicates.add(criteriaBuilder.like(from.get(filterProperty), literal));
    }
    accountQuery.where((Predicate[]) predicates.toArray(new Predicate[predicates.size()]));

    mas nao funcionou
    se poder me ajudar, agradeço.. valew

    • Olá Kleber, boa tarde.

      Não sei o que poderia ser.

      Confira o código para ver se todos os detalhes estão iguais aos apresentados aqui no post.

      Obrigado pela visita.

    • Olá kleber,

      Nesse projeto esta faltando informar ao datatable para buscar os dados via Lazy.

      No xhtml, na tag <p:dataTable coloque lazy=true

      • Maicon, boa tarde.

        Caso o leitor faça o post exatamente como demonstrado aqui, não será necessário o lazy no datatable. Apenas para as versões mais novas do primefaces que esse valor ficou obrigatório. Para confirmar faça o download do projeto na última página e utilize sem problemas. [=

        Fica a dica para quem estiver utilizando uma biblioteca do primefaces mais nova. [=

        Obrigado pela visita.

  5. Ao invés de efetuar um novo select para alimentar o setRowCount como você fez, não convém jogar o select do “find” para um array e depois só pegar o sized? eu uso assim sem prob.

    • Diegoo, boa tarde.

      A primeira consulta trás o resultado paginado, ou seja, se a paginação está de 10 itens o size total da primeira consulta é 10.
      A segunda consulta trará o total de registros na tabela independente do tamanho da paginação. Se sua tabela tiver 3.000 registros, o count voltará com 3.000 e não 10 que seria o total da primeira paginação.

      Espero ter ajudado.

  6. Aaaaaaaaaaaiiiiiiiiiiiiiiiiiiii Garoto, muito bem explicado, encontrei muita coisa na net porém nada detalhado como vc fez, parabéns!! sua implementação me será muito útil. Valeu!!!

  7. Primeiramente quero lhe parabenizar pelo post , muito interessante.

    Tenho uma duvida, na paginação do primefaces é obrigatório ter o na tag os atributos selection=”#{playerMB.player}” selectionMode=”single” ?

    Se poder me tirar esssa duvida agradeço.
    Se me permite gostaria de sugerir um post falando sobre binding compentente JSF no BackBean. Tenho pouquissimos artigos ne net falando e explicando claramente como isso funciona.

    Um Abraço

    • Olá Wenderson, boa tarde.

      Não, não precisa e selection nem o selecionMode, na versão mais nova do primefaces precisa do atributo lazy=”true”. [=

      Obrigado pela visita e pelas dicas.

  8. Fala grande Hebert, lendo os comentários percebi que a galera não esta conseguindo implementar o filterBy, então resolvi postar aqui uma possível solução utlizando seu proprio código, ai vai:

    lá na classe PlayerDAO e necessário alterar o metódo findPlayers como abaixo:

    @SuppressWarnings(“unchecked”)
    public List findPlayers(int startingAt, int maxPerPage, Map filters) {
    EntityManager em = myTransaction.getEntityManager();

    //regular query that will search for players in the db
    Query query = em.createQuery(“select p from Player p”);

    //implementação filterBy
    if (!filters.isEmpty()) {
    Iterator<Entry> iterator = filters.entrySet().iterator();
    while (iterator.hasNext()) {
    Entry entry = iterator.next();
    query.add(Restrictions.ilike(entry.getKey(), entry.getValue(), MatchMode.ANYWHERE));
    }
    }

    query.setFirstResult(startingAt);
    query.setMaxResults(maxPerPage);

    return query.getResultList();
    }

    adcionar os imports abaixo
    import java.util.Iterator;
    import org.hibernate.criterion.MatchMode;
    import java.util.Map;
    import java.util.Map.Entry;

    não esquecer de adicionar o novo parametro (Map filters) na chamada do metodo findPlayers na class PlayerLazyList,

    e pronto, resolvido!!! e mais uma vez, Parabéns pelo poster, e obrigado por compartilhar seus conhecimentos conosco, valeu!!!!

  9. Parabéns mais um post que leio, já não vou mais ao google, entro direto ao uaihebert.com, você poderia fazer um post sobre Converter?

    • Felipe, boa noite.

      Dei uma pesquisada rápida pela net e não encontrei nada sobre isso.

      Pode ser por causa do meu sono agora, ou por que realmente não tem.

      Uma solução bem simples e prática seria remover a opção {CurrentPageReport}. Eu nunca gostei muito dela mesmo. [=

      Desculpe não te ajudar como você queria. =/

      • Realmente acho que era cansaço, achei algo:

        paginatorTemplate=”{FirstPageLink} {PreviousPageLink} {CurrentPageReport} {JumpToPageDropdown} {NextPageLink} {LastPageLink}”
        currentPageReportTemplate=”[ Exibindo de {startRecord} a {endRecord} no total de {totalRecords}
        – Página: {currentPage}/{totalPages} ]”

  10. Olá Hebert. Peguei seu exemplo para implementar, mas estou quebrando a cabeça pra injetar o meu service, para fazer as transações, utilizo o Spring, e o service está anotado com @Service. Na classe do LazyList coloquei a anotação @Component e um @Autowired pra injetar o meu service. Mas ele vem “null”. Acredito que o primefaces quebra essa injeção de dependencias. Tens ideia do que realmente pode ser?

    • Junior, boa tarde.

      Infelizmente não sei te falar sem olhar seu código mais afundo.

      Poderia postá-lo no GUJ? Assim caso eu não consiga resolver, outra pessoa poderá ajudar.

      Obrigado pela visita.

  11. Olá primeiramente parabéns pelo post! Gostaia de saber se é possível limpar o startigngAt antes do método load ser chamado. O cenário é o seguinte tenho uma página de pesquisa, e toda vez que o usuário clica no botão buscar a pesquisa deverá ser feita a e retornar a primeira página dos registros.

    Obrigado.

    • Guilherme, boa tarde.

      Você poderia “reiniciar o objeto”, ou seja, fazer um new LazySuaClasse();

      Desse modo iria para a primeira página.

      Espero ter ajudado, desculpe a demora.

      Obrigado pelo apoio e até mais.

  12. Herbert, sabe me dizer se existe a possibilidade de adicionar algum delay no filterBy ?
    pois colocando como lazy os dados, ao colocar algo no filtro muito extenso as requisições no banco espancam o coitado…. eu pensei em limitar o numero minimo de caracteres no campo do filtro mas não fica legal… queria tipo… digitar.. e esperar uns 2 segundos até fazer a consulta

    • Otávio, bom dia.

      Até onde sei não, mas faz algum tempo que não acompanho as mudanças do Primefaces.

      Pode ser que tenha acontecido alguma mudança que eu não esteja sabendo.

      Obrigado pela visita.

  13. Muito obrigado.

    Ainda estou aprendendo a mexer com primefaces e esse código me ajudou muito!!!

    Não sei se é possível mas será que teria como ter essa paginação mais genérica?!! tipo como é feito com os repositórios (uma paginação que sirva para todas as classes)??!!

  14. desculpa, fiz seu projeto mas não mostra erro, só a lista sem registro algum

    —————————————————————————–

    o problema era no primefaces. como faço para usar o primefaces 4.0?

  15. Boa tarde aihebert.

    Talvez possa me ajudar. Iplementei um código genérico, e funciona perfeitamente no Glassfish, porém quando utilizo o Tomcat ele não entra no método load.

    • Fábio, boa tarde.

      Verifique se todas as bibliotecas estão presentes, se a versão também é a mesma.

      Caso não exista diferença, altere o estágio do JSF para development para que seja exibido caso algum erro aconteça.

      Att,

      • Pessoal, encontrei o problema. O componente que estava executando a ação era da PrimeFaces “p:”, sendo assim o erro não estava aparecendo no log, mudei para “h:” e foi possível identificar o erro, no construtor tive que inicializar o setPageSize(1), setRowIndex(1). Lembrando que no glassfish não precisei iniciar esses atributos.

        ———————————–

        Obrigado.

  16. uaihebert

    Uma pergunta…

    Existe alguma forma de alternar dinâmicamente pelas paginações da dataTable utilizando os componentes do primefaces ?

    Por exemplo de tempo em tempo alternar como se tivesse clicando no {NextPageLink}

    Um efeito como o Carousel – SlideShow do show case.

    Dede já agradeço e me desculpa se não for adequado esse tipo de pergunta aqui.

    E novamente parabéns pelo exelente trabalho.

  17. Bom dia, Hebert.

    Estou implementando a paginação real em meu projeto, seguindo os passos do seu livro “JSF Eficaz”. Consegui implementar quase tudo, exceto pelos filtros, pois o objeto exibido na dataTable contém atributos de tipos que não são String. Quando tento realizar o Query.setParameter, estoura uma exceção.
    Você teria alguma sugestão de como posso resolver meu problema?
    Obrigado.

    • Rodolfo, boa noite.

      Você poderia ajustar o seu setParameter para receber o parâmetro que você está enviando.

      Não tenho como falar o que é pois não analisei seu código e/ou seu erro.

      Obrigado pela visita, e desculpe a demora em responder. Estive muito ocupado nesse último mes.

  18. O que significa o metodo getDAO.countAll(filtod)

    no seu livro você promete explicar o DAO em questão, mas eu não encontrei

    • Kerllon, boa tarde.

      É o método que realiza a contagem de todos os registro no banco.

      Você olhou o código do livro?

      Lá tem tudo.

      Obrigado pela visita.

  19. Owww Hebert… essa paginação pode ser feita usando uma ação do usuario em um botão para pesquisar e preencher os dados em um datatable? Detalhe… é uma pesquisa envolvendo 2 objetos de entidade.

    • Flávio, boa tarde.

      Pode sim, você só tem que manter os dados da pesquisa em memória.

      Aí você poderá sempre repetir a pesquisa do usuário, mas paginada.

      Obrigado pela visita.

  20. Herbert,

    Estou usando em um projeto o LazyDataModel do próprio PimeFaces 5, ou seja, pego os parâmetros passados no método load e via JPA faço a pesquisa. Observei que ao incluir um PhaseListener, inicialmente para a fase Restore view e depois mudei para Render response, para gerar um menu dinamicamente para a tela o tempo de resposta aumentou muito. Vc sabe de algum problema de performance relacionando um PhaseListener juntamente com o LazyDataModel do próprio PrimeFaces?

  21. Olá Uaihebert na minha aplicação não esta trazendo os resultados e nao da erro aparentemente parrce que não chama o método load

    • Paulo, boa tarde.

      Infelizmente não sei te falar o que pode ser, sem uma mensagem de erro.

      Algo que eu suspeito que possa ser é que a nova versão do datatable do primefaces necessita do atributo lazy=”true”. (creio ser esse o nome do atributo)

      Obrigado pela visita

      • olá Uaihebert, era iss mesmo agora funcinou tudo certo so tive que mudar o metodo
        public List load(int startingAt, int maxPerPage, String sortField, SortOrder sortOrder, Map filters)

        para

        public List load(int startingAt, int maxPerPage, String sortField, SortOrder sortOrder, Map filters)

    • Welsson, boa tarde

      Honestamente não tenho a mínima idéia. Não sei o que seu código faria, como influenciaria no código e na consulta.

      Obrigado pela visita.

Leave a Comment