Um ponto muito importante em qualquer projeto é a tabulação de dados, independente da linguagem a qual estamos trabalhando. Quando trata-se de JSF (Java Server Faces) o primeiro componente que vem à mente, para tabulação de dados, é o DataTable. Este poderoso componente fornece recursos muito poderosos para que o desenvolvedor consiga trabalhar em conjunto com o ManagedBean de forma prática, rápida e fácil.

Neste artigo veremos como implementar várias funcionalidades ao dataTable do JSF, funcionalidades estas que já são padrões em frameworks como o Primefaces mas em nosso caso vamos construir nossa própria lógica usando o binding do JSF.

JSF e o DataTable

Possivelmente o DataTable é um dos componentes mais completos do JSF, com um mundo de possibilidades, para usá-lo na sua página xHTML você deve ter a tag abaixo:


xmlns:h="http://java.sun.com/jsf/html"

Com o link acima referenciando a letra 'h', nós podemos chamar o h:dataTable dentro da nossa página, um exemplo completo de declaração dessas tags é mostrado na Listagem 1.


<!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://java.sun.com/jsf/html"
     xmlns:f="http://java.sun.com/jsf/core"
     xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
</h:body>
</html>
Listagem 1. Exemplo completo de header do XHTML

Se você está começando agora com JSF e não tem as bibliotecas necessárias para usá-lo no seu projeto, você pode adicionar as linhas da Listagem 2 no seu pom.xml, caso esteja usando Maven.


<dependency>
   <groupId>com.sun.faces</groupId>
   <artifactId>jsf-api</artifactId>
   <version>2.2.9</version>
</dependency>

<dependency>
   <groupId>com.sun.faces</groupId>
   <artifactId>jsf-impl</artifactId>
   <version>2.2.9</version>
</dependency>
Listagem 2. Adicionando JSF ao pom.xml

Estamos usando a versão 2.2.9 do JSF que traz várias novidades como o uso de atributos customizados nos componentes, muito útil para uso de frameworks como Bootstrap.

Dada as configurações acima nós estamos prontos para usar o DataTable em nossa página XHTML, porém precisamos definir um ManagedBean que irá manipular este componente. Isso significa que os eventos disparados no nosso dataTable serão enviados ao nosso ManagedBean, que nada mais é do que uma classe Java, onde faremos os tratamentos necessários. Observe a Listagem 3.


import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.html.HtmlDataTable;
 
@ManagedBean(name = "manipuladorDataTableMB")
@ViewScoped
public class ManipuladorDataTableMB{
 
    private static final long serialVersionUID = 1L;
        
    private HtmlDataTable dataTable;
 
       public HtmlDataTable getDataTable() {
             return dataTable;
       }
 
       public void setDataTable(HtmlDataTable dataTable) {
             this.dataTable = dataTable;
       }            
 
}
Listagem 3. ManagedBean para manipular nosso DataTable

Nosso ManagedBean é muito simples, vejamos:

  1. Ele possui duas anotações @ManagedBean com o nome dele que será referenciado no XHTML, então chamaremos ele através do alias manipuladorDataTableMB no nosso XHTML. A outra anotação, @ViewScoped, diz respeito ao escopo do nosso ManagedBean na sessão do Browser, e este escopo significa que o nosso ManagedBean guardará os dados da requisição enquanto o usuário não mudar de visualização/view.
  2. O mais importante aqui é nossa variável 'dataTable' do tipo HtmlDataTable. Com ela nós faremos o binding do componente DataTable do XHTML para o 'dataTable' do nosso ManagedBean.
  3. É importante entender que com o conceito de 'Data Binding' é o princípio fundamental do que faremos neste artigo. Esta técnica possibilita a conexão entre a interface da aplicação e a lógica de negócio, e isso não se refere apenas a WEB. Quando temos um componente A, dada uma determinada tela do sistema, sendo controlando de uma classe onde tem uma regra de negócio B, chamamos isso de Data Binding.

Não podemos começar a trabalhar com o DataTable sem antes possuir os dados que serão manipulados, mas para não nos estendermos muito nós iremos criar os dados estaticamente na nossa classe ManipuladorDataTableMB, referenciando um Bean chamado Noticia. Observe a Listagem 4.


public class Noticia {
   
   private int id;
   private String titulo;
   private String texto;
   
   public Noticia(int id, String titulo, String texto){
         this.id = id;
         this.titulo = titulo;
         this.texto = texto;
   }
   
   public int getId() {
         return id;
   }
   public void setId(int id) {
         this.id = id;
   }
   public String getTitulo() {
         return titulo;
   }
   public void setTitulo(String titulo) {
         this.titulo = titulo;
   }
   public String getTexto() {
         return texto;
   }
   public void setTexto(String texto) {
         this.texto = texto;
   }
}
Listagem 4. Bean Noticia

E com o Bean definido nós adicionamos um inicializador no ManipuladorDataTableMB, como mostra a Listagem 5.


private List<Noticia> noticias;
  
  public ManipuladorDataTableMB(){
     noticias = new ArrayList<Noticia>();
     noticias.add(new Noticia(1,"Noticia 001", "Texto 001"));
     noticias.add(new Noticia(2,"Noticia 002", "Texto 002"));
     noticias.add(new Noticia(3,"Noticia 003", "Texto 003"));           
     noticias.add(new Noticia(4,"Noticia 004", "Texto 004"));
     noticias.add(new Noticia(5,"Noticia 005", "Texto 005"));
  }

     public List<Noticia> getNoticias() {
           return noticias;
     }

     public void setNoticias(List<Noticia> noticias) {
           this.noticias = noticias;
}
Listagem 5. Inicializando o Bean Noticia como uma Lista

Criamos um construtor para nosso ManipuladorDataTableMB, e nele inicializamos a variável noticias que é declarada logo em baixo de 'private HtmlDataTable dataTable'.

Agora precisamos realizar o binding do nosso componente dataTable com o nosso ManagedBean, como mostra a Listagem 6.


<!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://java.sun.com/jsf/html"
     xmlns:f="http://java.sun.com/jsf/core"
     xmlns:ui="http://java.sun.com/jsf/facelets">

<h:head />
<h:body>
     <h:dataTable binding="#{manipuladorDataTableMB.dataTable}"
           value="#{manipuladorDataTableMB.noticias}" var="noticia">
           <h:column>
                  <f:facet name="header">ID</f:facet>
           #{noticia.id}
       </h:column>

           <h:column>
                  <f:facet name="header">Titulo</f:facet>
           #{noticia.titulo}
       </h:column>

           <h:column>
                  <f:facet name="header">Texto</f:facet>
           #{noticia.texto}
       </h:column>
     </h:dataTable>
</h:body>
</html>
Resultado:
ID
Titulo
Texto
1
Noticia 001
Texto 001
2
Noticia 002
Texto 002
3
Noticia 003'
Texto 003
4
Noticia 004
Texto 004
5
Noticia 005
Texto 005
Listagem 6. Fazendo binding do XHTML para o ManagedBean

Vamos entender o que foi feito acima de forma sucinta, pois nosso objetivo é mostrar o binding e não todas as funcionalidades do dataTable. Criamos no ManagedBean uma lista de objetos Noticia, e agora estamos populando nosso dataTable usando o atributo “value” onde passamos esta lista, usamos o atributo “var” para mapear um alias que poderá ser usado dentro da coluna, o #{noticia.titulo} faz referência a cada linha do registro que está sendo iterado no dataTable. O mais importante aqui é notar o uso do atributo “binding”, que faz referência a classe HtmlDataTable que criamos anteriormente no nosso ManagedBean.

De posse deste conhecimento já podemos começar a fazer alguns procedimentos com este componente, vejamos como saber a linha atual que está selecionada na Listagem 7.


//XHTML

<h:column>
<h:commandLink value="Selecionar"
 action="#{manipuladorDataTableMB.selecionarLinha()}" />
</h:column>

//ManagedBean
public void selecionarLinha(){
   Noticia noticiaSelecionada = (Noticia) dataTable.getRowData();
   System.out.println("Noticia Selecionada  = "+noticiaSelecionada.getId() + "|" + noticiaSelecionada.getTitulo());
}
Listagem 7. Checando linha selecionada

E não esqueça de colocar as tags “ e ” ao redor do dataTable, caso contrário você não conseguirá produzir o resultado esperado.

Quando o usuário clicar no link “Selecionar”, o método selecionarLinha() será chamado e o componente dataTable do ManagedBean já tem a linha selecionada e podemos recupera-la através do método getRowData().

Podemos também contar a quantidade de linhas contidas no dataTable, como mostra a Listagem 8.


public void selecionarLinha(){
   int count = dataTable.getRowCount();
   System.out.println("quantidade de registros = "+count);
}
Listagem 8. Contando número de registros

Tudo isso é feito sempre que o usuário clicar no link que criamos anteriormente.

Vejamos agora como fica nosso ManagedBean finalizado com o Binding e os métodos necessários para manipula-lo (Listagem 9).


package br.com.cardoso.mb;

import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.html.HtmlDataTable;

@ManagedBean(name = "manipuladorDataTableMB")
@ViewScoped
public class ManipuladorDataTableMB{

private static final long serialVersionUID = 1L;
    
private HtmlDataTable dataTable;
private List<Noticia> noticias;

public ManipuladorDataTableMB(){
     noticias = new ArrayList<Noticia>();
     noticias.add(new Noticia(1,"Noticia 001", "Texto 001"));
     noticias.add(new Noticia(2,"Noticia 002", "Texto 002"));
     noticias.add(new Noticia(3,"Noticia 003'", "Texto 003"));         
     noticias.add(new Noticia(4,"Noticia 004", "Texto 004"));
     noticias.add(new Noticia(5,"Noticia 005", "Texto 005"));
}

public void selecionarLinha(){
     Noticia noticiaSelecionada = (Noticia) dataTable.getRowData();
     System.out.println("Noticia Selecionada  = "+noticiaSelecionada.getId() 
     + "|"+ noticiaSelecionada.getTitulo());
}

     public HtmlDataTable getDataTable() {
               return dataTable;
     }

     public void setDataTable(HtmlDataTable dataTable) {
               this.dataTable = dataTable;
     }

     public List<Noticia> getNoticias() {
               return noticias;
     }

     public void setNoticias(List<Noticia> noticias) {
               this.noticias = noticias;
     }            
}
Listagem 9. ManagedBean completo

Nosso managedBean é muito simples mas se resumo a tudo que precisamos para entender como fazer um binding do DataTable. Lembrando que o binding não está limitado apenas ao DataTable mas também pode ser utilizado em outros componentes.

Vejamos agora um processo de seleção um pouco mais complexo, a seleção de vários itens ao mesmo tempo. Podemos colocar um checkbox em cada coluna de forma que o usuário possa selecionar quantas achar necessário e depois realizar algum processamento.

Primeiro alteramos nosso bean inicial adicionando uma nova coluna chamada 'selected', como mostra a Listagem 10.


package br.com.cardoso.mb;

public class Noticia {
   
   private int id;
   private String titulo;
   private String texto;
   private boolean selected;
   
   public Noticia(int id, String titulo, String texto){
         this.id = id;
         this.titulo = titulo;
         this.texto = texto;
         this.selected = false;  
   }
   
   public int getId() {
         return id;
   }
   public void setId(int id) {
         this.id = id;
   }
   public String getTitulo() {
         return titulo;
   }
   public void setTitulo(String titulo) {
         this.titulo = titulo;
   }
   public String getTexto() {
         return texto;
   }
   public void setTexto(String texto) {
         this.texto = texto;
   }

   public boolean isSelected() {
         return selected;
   }

   public void setSelected(boolean selected) {
         this.selected = selected;
   }

}
Listagem 10. Bean com coluna selected

Temos agora um novo atributo chamado selected que possui seu valor padrão igual a false quando o objeto é instanciado. Preparamos agora nosso ManagedBean para receber a seleção de vários objetos e realizar alguma ação. Observe a Listagem 11.


public void mostrarLinhasSeleciondas(){      
   for(Noticia n : noticias){
         if (n.isSelected()){
                System.out.println("Noticia selecionada (ID | Titulo) 
                = "+n.getId() + "|"+ n.getTitulo());
                n.setSelected(false);
         }
   }
}
Listagem 11. Preparando o managedBean para seleção múltipla

Adicionamos um método que irá percorrer nosso ArrayList “noticias” e checamos se aquele registro foi selecionado ou não, caso seja selecionado então mostramos o valor da notícia. Em nosso XHTML fazemos da mesma forma que mostrada na Listagem 12.


<!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://java.sun.com/jsf/html"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:ui="http://java.sun.com/jsf/facelets">

<h:head />
<h:body>
   <h:form>
    <h:dataTable binding="#{manipuladorDataTableMB.dataTable}"
      value="#{manipuladorDataTableMB.noticias}" var="noticia">
      <h:column>
             <f:facet name="header">ID</f:facet>
    #{noticia.id}
    </h:column>

      <h:column>
             <f:facet name="header">Titulo</f:facet>
    #{noticia.titulo}
    </h:column>

      <h:column>
             <f:facet name="header">Texto</f:facet>
    #{noticia.texto}
    </h:column>

      <h:column>
             <h:commandLink value="Selecionar"
                    action="#{manipuladorDataTableMB.selecionarLinha()}" />
      </h:column>
      
      <h:column>
       <h:selectBooleanCheckbox value="#{noticia.selected}" />
      </h:column>
    </h:dataTable>

    <h:commandButton action="#{manipuladorDataTableMB.mostrarLinhasSeleciondas()}" 
value="Processar Selecionados" />
   </h:form>
</h:body>
</html>
Listagem 12. Seleção múltipla no XHTML

Agora nosso XHTML além de possuir o link 'selecionar' padrão, possui também um checkbox para cada registro, onde podemos selecionar o mesmo e depois clicar no botão 'Processar Selecionados', assim os valores selecionados serão enviados ao ManagedBean e podemos percorre-lo.

Depois de selecionar uma quantidade qualquer de registros e clicarmos no botão de Processar, a página deve ser recarregada e os valores voltam ao seu estado inicial, sem seleção.

Vamos adicionar mais complexidade ao nosso projeto adicionando um campo para que o usuário possa editar o valor selecionado, como mostra a Listagem 13.


<!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://java.sun.com/jsf/html"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:ui="http://java.sun.com/jsf/facelets">

<h:head />
<h:body>
   <h:form>
         <h:dataTable binding="#{manipuladorDataTableMB.dataTable}"
                value="#{manipuladorDataTableMB.noticias}" var="noticia">
                <h:column>
                       <f:facet name="header">ID</f:facet>
         #{noticia.id}
     </h:column>

                <h:column>
                       <f:facet name="header">Titulo</f:facet>
                       <h:inputText value="#{noticia.titulo}" />
     </h:column>

                <h:column>
                       <f:facet name="header">Texto</f:facet>
         <h:inputText value="#{noticia.texto}" />
     </h:column>
     
       <h:column>
            <h:commandLink value="Salvar"
                  action="#{manipuladorDataTableMB.salvar()}" />
            </h:column>

            <h:column>
            <h:commandLink value="Selecionar"
                  action="#{manipuladorDataTableMB.selecionarLinha()}" />
            </h:column>

            <h:column>
            <h:selectBooleanCheckbox value="#{noticia.selected}" />
            </h:column>
         </h:dataTable>
         
         <h:commandButton action="#{manipuladorDataTableMB
         .mostrarLinhasSeleciondas()}" value="Processar Selecionados" />
   </h:form>
</h:body>
</html>
Listagem 13. Editando valor selecionado

Acima mudamos a simples impressão dos valores Titulo e Texto da notícia em questão e estamos agora colocando um h:inputText para que o usuário possa alterar o título e o texto da notícia sem que precise ir para uma outra tela. Esta prática é muito comum quando trata-se de registros básicos que são primários para o cadastro de outros, exemplo: categoria de produtos, tipos de clientes e etc.

Quando o usuário muda o título da notícia nada acontece no managedBean, pois o valor só é processador no 'submit' do form que é realizado através do botão 'Salvar'que chama a action 'salvar()' do nosso ManagedBean. Apenas nesta etapa é que o ciclo de vida do JSF entra em ação e o processamento realmente começa.

Em nosso ManagedBean adicionamos o método salvar que na verdade apenas mostra os novos valores, como mostra a Listagem 14.


public void salvar(){
   Noticia noticiaSelecionada = (Noticia) dataTable.getRowData();
   System.out.println("Titulo novo = "+noticiaSelecionada.getTitulo());
   System.out.println("Texto novo = "+noticiaSelecionada.getTexto());
}
Listagem 14. Método salvar() do ManagedBean

Quando capturamos a notícia selecionada através do getRowData(), nós já temos os valores da notícia alterada, a partir da aqui você pode fazer validações e salvar no banco de dados, mas para efeitos didáticos estamos apenas mostrando no console os novos valores para certificar-se que eles estão vindo corretamente.

A quantidade de funcionalidades que você pode implementar com o binding de um dataTable são imensas, você literalmente pode criar um componente tão poderoso quanto os oferecidos por componentes terceirizados como PrimeFaces, Icefaces e etc., tudo depende da sua expertise, pois obviamente funções complexas exigem mais estudo, mais conhecimento e mais paciência.

Neste artigo criamos apenas a opção de seleção e edição, mas a seleção é o ponto de partida para a maioria das funções que você imagina desenvolver, por exemplo, ordenação, pesquisa, paginação e etc. A vantagem de utilizar o dataTable do JSF é o nível de customização que você pode fazer com este componente, pois quando você usa componentes como o dataTable do PrimeFaces você tem várias características que são adicionadas pelo próprio PrimeFaces e que podem ser indesejadas, como por exemplo o estilo do componente, o que pode trazer incompatibilidade com outros frameworks com o Bootstrap.