Por que eu devo ler este artigo:

O desenvolvimento de sistemas web é muito comum no mercado Java, e definir qual ou quais frameworks utilizar é uma questão fundamental. Para isto é necessário conhecimento sobre os recursos disponíveis em cada framework como, por exemplo, o JSF.

Desenvolver sistemas web é uma realidade no mercado atual e o framework JavaServer Faces é a opção padrão do Java EE para resolver este tipo de problema. Uma das características do JSF é trabalhar de uma maneira orientada a componentes de tela e seus eventos (por exemplo, cliques). Desta maneira, podemos associar estes componentes a diversos aspectos de nosso sistema, como a execução de operações de negócio, conversões de valores, validações de campos, etc. Este framework também suporta internacionalização, a utilização de layouts unificados, e chamadas assíncronas ao servidor (AJAX).

Desenvolvimento para web é um assunto muito discutido no contexto da tecnologia Java. Há anos a comunidade de software tem se esforçado para projetar e criar melhores formas de criar sistemas para web com esta linguagem. Atualmente, uma das tecnologias mais utilizadas para o desenvolvimento em Java deste tipo de aplicação é o JavaServer Faces (JSF). O JSF é a especificação de um framework para aplicações web definido na padronização do Java Enterprise Edition (Java EE). A nova versão desta tecnologia (o JSF 2.0) traz uma série de recursos úteis para o desenvolvedor de software, como a definição de componentes através de anotações, trabalho nativo com Facelets, AJAX, integração com CDI e diversos outros itens.

Para demonstrar como utilizar este framework, este artigo visa apresentar ao leitor com algum conhecimento de aplicativos web em Java (por exemplo, Servlets e JSPs) as vantagens do JSF, já considerando os recursos desta segunda versão. Também é nosso intuito demonstrar alguns mecanismos úteis desta nova versão para conhecedores de JSF, integrada com o mecanismo padrão de injeção de dependências do Java EE (o CDI – Contexts and Dependency Injection), e a simplificação de sua utilização prática no dia a dia.

Neste artigo baseamos nossas explicações conforme desenvolvemos algumas funcionalidades em um sistema web. Portanto é fundamental que o leitor “brinque” um pouco com os recursos aqui exemplificados e adquira conhecimento a partir dessas experiências.

Para isso, desenvolveremos algumas funcionalidades básicas de um sistema de aluguel de carros. Primeiro aprenderemos como criar um pacote JSF 2 instalável em um servidor Java EE. Posteriormente criaremos uma funcionalidade exemplo (um cadastro de modelos de carros), demonstrando alguns componentes básicos do JSF e como funciona o ciclo de vida de uma chamada. Após isto, transformaremos pouco a pouco nossa aplicação, passando por conceitos como navegação, internacionalização, validadores, conversores, layouts, AJAX, etc.

Montando o ambiente no JavaServer Faces

Existem várias formas de preparar um ambiente para desenvolver uma aplicação com JSF 2. Uma maneira muito utilizada no mercado é através do projeto Maven. Para quem não conhece, o Maven é uma ferramenta bastante útil para tratar do empacotamento de projetos Java e gerenciar suas dependências (entre algumas outras coisas). Porém, estruturar adequadamente um projeto Maven pode ser complicado caso você não tenha experiência nesta ferramenta, portanto você pode utilizar as IDEs como o Eclipse e o NetBeans para ajudar nestes casos (eles possuem esqueletos de projetos web já prontos e fáceis de utilizar e gerar os pacotes necessários). No entanto, independente da solução adotada, o mais importante para um projeto Java web é discutir o conteúdo do pacote WAR (que em nosso caso será o locadora.war), pois representa o pacote de instalação da aplicação.

Consideramos que o leitor já possui conhecimento de como se cria uma aplicação web em Java (utilizando Servlets e/ou JSPs, por exemplo), bem como a estrutura básica de um arquivo WAR. Demonstraremos a preparação de um ambiente exemplo utilizando o Maven para configurar nosso projeto. Apesar disto, sugerimos que o leitor prepare sua aplicação Java Web da maneira com que já está acostumado, e por isto, nossos exemplos de aplicação estarão apenas baseados na estrutura do pacote WAR, e livre das ferramentas de desenvolvimento utilizadas para a montagem deste pacote.

Para este artigo, demonstraremos a API do JSF 2 já integrada com o CDI (um mecanismo de injeção de dependências padronizado no Java EE 6), e por isto, utilizaremos o servidor de aplicação JBoss 7.0.2-Final (Web Profile). Além de possuir uma versão gratuita para download, este servidor já possui suporte a ambas as tecnologias em versões consideravelmente atualizadas, e por isto nosso arquivo.war não necessita possuir nenhuma biblioteca específica (dentro de /WEB-INF/lib) para rodar, apesar de você necessitá-las em seu classpath no momento da compilação de seu código.

Durante o desenvolvimento do artigo, utilizamos o Maven para simplificar a manipulação de dependências e a construção de nosso projeto. A utilização desta tecnologia não é obrigatória para acompanhar o conteúdo apresentado, porém consideramos que a criação de um projeto Maven padroniza a administração de alguns recursos na aplicação web.

Preparando o JBoss

Para instalar o servidor de aplicação JBoss 7.0.2-Final, é necessário baixá-lo em https://www.jboss.org/jbossas/downloads. Após isto, descompacte-o no local de sua preferência.

Para a execução de uma aplicação básica, é apenas necessário rodar o arquivo standalone.bat (ou standalone.sh em caso de sistemas Linux), localizado no diretório bin deste servidor. Esta execução deverá iniciar o servidor de aplicações, que poderá ser acessado no navegador através do endereço http://localhost:8080. Para instalarmos uma aplicação web, é apenas necessário incluir o pacote WAR no diretório standalone/deployments deste servidor e a aplicação correspondente será automaticamente instalada.

Preparando um projeto Maven

Como já mencionado, a utilização do Maven não é obrigatória para seguir os nossos exemplos e um detalhamento desta tecnologia foge ao escopo deste artigo. Apesar disto, demonstramos como preparar uma aplicação Java Web com as dependências necessárias para rodar os exemplos aqui apresentados.

Para preparar o nosso projeto utilizando o Maven execute os seguintes passos:

  1. Instale o Maven seguindo os procedimentos encontrados em https://maven.apache.org/download.html;
  2. Crie um diretório com o nome locadora no local de sua preferência para representar o nosso projeto;
  3. Crie um arquivo com nome pom.xml dentro do diretório locadora com o conteúdo indicado na Listagem 1;
  4. Acesse o diretório locadora através de um prompt de comando e execute o comando: mvn clean install (espere o Maven realizar o download inicial das dependências e construir um pacote WAR);
  5. Verifique no diretório locadora/target se o arquivo locadora.war foi criado com sucesso.
Listagem 1. Conteúdo do arquivo pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
    http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>br.com.simpleit</groupId>
      <artifactId>locadora</artifactId>
      <packaging>war</packaging>
      <version>0.0.1-SNAPSHOT</version>
      <name>LocadoraDeCarros</name>
      <dependencies>
        <dependency>
              <groupId>javax</groupId>
              <artifactId>javaee-web-api</artifactId>
              <version>6.0</version>
              <scope>provided</scope>
        </dependency>
      </dependencies>
      <repositories>
        <repository>
          <id>Repo1</id>
          <name>Repo1</name>
          <url>http://repo1.maven.org/maven2</url>
        </repository>
                 
        <repository>
          <id>java.net2</id>
          <name>Repository hosting the jee6 artifacts</name>
          <url>http://download.java.net/maven/2</url>
        </repository>
    
      </repositories>
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.1</version>
            <configuration>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </plugin>
          <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.1.1</version>
            <configuration>
              <!-- Java EE 6 não precisa mais do web.xml-->
              <failOnMissingWebXml>false</failOnMissingWebXml>
            </configuration>
          </plugin>
        </plugins>
        <finalName>locadora</finalName>
      </build>
    </project>

Trabalhando com um projeto Maven

Se o procedimento de instalação e preparação do projeto foi realizado com sucesso, você já consegue construir pacotes WAR diretamente pelo Maven em qualquer momento apenas ao executar o comando mvn clean install, que criará um novo arquivo locadora.war a cada execução.

O arquivo pom.xml é o responsável pela configuração de nosso projeto. O arquivo exemplo, indicado pela Listagem 1, demonstra a definição da dependência das classes existentes no Java EE 6. Esta definição de dependências é uma das grandes vantagens da utilização do Maven, visto que o mesmo se encarregará de automaticamente realizar o download das dependências e adicionar as classes especificadas no Java EE 6 durante a compilação das classes de nosso projeto.

O Maven é uma ferramenta muito útil para a construção e administração de um projeto Java, porém é importante possuir os recursos ricos das IDEs atuais durante a programação de nossas classes. Para facilitar esta programação, sugerimos a utilização do plugin do Eclipse conhecido como M2Eclipse, que pode ser encontrado em http://eclipse.org/m2e/download/. Através deste plugin, é possível utilizar o Eclipse como ferramenta de desenvolvimento enquanto se utiliza o Maven para a geração de nosso pacote.

Independente da utilização ou não do M2Eclipse, para a construção adequada de um pacote WAR, um projeto web no Maven deve possuir uma estrutura básica indicada por alguns arquivos e diretórios. Compreender a divisão dos diretórios em um projeto Maven, bem como onde cada arquivo deve estar localizado, é fundamental para a boa utilização desta tecnologia. Segue uma explicação básica dos diretórios principais a serem utilizados em nossos exemplos:

  1. Todas as classes Java, a estrutura de diretórios dos pacotes, devem estar em locadora/src/main/java;
  2. Qualquer recurso estático a ser disponibilizado no Classpath (como, por exemplo, o arquivo de mensagens de nosso exemplo) deve estar localizado em locadora/src/main/resources;
  3. Páginas e outros recursos a serem diretamente indicados na raiz do pacote WAR devem ser disponibilizados no diretório locadora/src/main/webapp;
  4. O arquivo pom.xml deve estar diretamente acessível no diretório locadora.

Um exemplo da organização de alguns arquivos nesta estrutura em um projeto Maven hipotético pode ser observado na Listagem 2.

Listagem 2. Estrutura de um projeto exemplo no Maven
  redesocial
|
+--pom.xml
|
+--src
     |
     +--main
           |
          +--java
             |
             +--br/com/superlocadora/model/Usuario.java
             |
             +--br/com/superlocadora/mb/NovoUsuarioMB.java
             |
             +--br/com/superlocadora/repositorio/RepositorioDeUsuarios.java
         |
         +--resources
             |
             +--messages.properties
         |
         +--webapp
             |
             +--usuario/novo.xhtml
             |
             +--img/logo.png
             |
             +--css/estilos.css
             |
             +--index.html
             |
             +--WEB-INF
                   |
                   +--beans.xml
                   |
                   +--faces-config.xml
                   |
                   +--web.xml

Construindo o pacote WAR diretamente através de alguma IDE

Caso o leitor não esteja confortável com a utilização do Maven, pode utilizar outro mecanismo para criar seu pacote WAR, como por exemplo, uma IDE. No Eclipse isto pode ser feito através da criação de um projeto do tipo Dynamic Web Project, em que é possível estruturar um projeto Java Web e exportar arquivos WAR diretamente da estrutura deste projeto. Um aspecto que deve ser considerado para a preparação adequada deste ambiente é a necessidade das classes das tecnologias JSF e CDI em tempo de compilação. Estas classes são necessárias para que seja possível compilarmos as classes Java de nosso projeto, gerando assim arquivos .class adequados para o empacotamento. Para adicionar estas bibliotecas, o leitor deverá alterar o Build Path de seu projeto do Eclipse para conter os jars necessários do Java EE 6. Um JAR unificado que possui todas as classes necessárias em tempo de compilação pode ser encontrado em http://download.java.net/maven/2/javax/javaee-web-api/6.0/javaee-web-api-6.0.jar. Apesar desta necessidade em tempo de compilação, este JAR não precisa ser embarcado nos pacotes WAR que iremos criar, pois o servidor de aplicações já possui as classes necessárias para executar nossa aplicação.

Exemplo básico

Uma das maneiras de se explicar uma tecnologia é através de exemplos. Assim, para explicar o funcionamento básico do framework JSF, criaremos algumas funcionalidades exemplo de um sistema imaginário.

Vamos supor que devemos desenvolver algumas operações relacionadas a um sistema de locação de carros pela internet. Primeiramente, pretendemos que o usuário possa visualizar uma lista de modelos de carros com algumas características, dentre as quais ele possa escolher o mais adequado para suas necessidades. Para isto, criaremos uma funcionalidade básica de cadastro de modelos de carros. Este desenvolvimento será realizado de maneira simplista, visto que o nosso objetivo é aprender os conceitos básicos do JSF.

Pretendemos disponibilizar para nosso usuário uma tela de cadastro, como indicada na Figura 1, e uma tela de confirmação de cadastro, como indicada na Figura 2.

Tela de cadastro de um novo modelo de carro
Figura 1. Tela de cadastro de um novo modelo de carro
Visualização do modelo incluído
Figura 2. Visualização do modelo incluído

Para atingir o objetivo de desenvolver estas telas, criamos o arquivo /modelo/novo.xhtml com o conteúdo indicado na Listagem 1, utilizando algumas tags já padronizadas do JSF para criar componentes na tela. Inserimos o arquivo novo.xhtml dentro do diretório modelo simplesmente para tornar a URL da página um pouco mais significativa, possibilitando ao usuário acessar a página através de uma URL do tipo modelo/novo.xhtml. No entanto, é possível criar páginas diretamente na raiz do pacote WAR.

Para entendermos como desenvolver páginas utilizando o JSF, é necessário compreender alguns aspectos de seu funcionamento. O JavaServer Faces é um framework de desenvolvimento web orientado a componentes, isto é, é através da utilização de componentes de tela (ex: campos texto, botões, campos checkbox, etc.) que definimos o comportamento programático de uma página, associando métodos para serem executados de acordo com algum evento em um destes componentes – uma abordagem tradicional em APIs para desenvolvimento desktop (ex: Swing). Devido à sua localização dentro do pacote WAR – exemplificada na Listagem 3 – a página da Listagem 4 poderá ser acessada, após a instalação do pacote no container, através da URL http://localhost:8080/locadora/admin/modelo/novo.jsf.

Listagem 3. Pacote WAR para execução de uma página JSF básica
  locadora.war
locadora.war/admin
locadora.war/admin/modelo
locadora.war/admin/modelo/novo.xhtml
locadora.war/admin/modelo/visualiza.xhtml
locadora.war/WEB-INF
locadora.war/WEB-INF/classes
locadora.war/WEB-INF/classes/locadora
locadora.war/WEB-INF/classes/locadora/mb
locadora.war/WEB-INF/classes/locadora/mb/NovoModeloMB.class
locadora.war/WEB-INF/classes/locadora/model
locadora.war/WEB-INF/classes/locadora/model/Modelo.class
locadora.war/WEB-INF/classes/locadora/repositorio
locadora.war/WEB-INF/classes/locadora/repositorio/Repositorio.class
locadora.war/WEB-INF/beans.xml
locadora.war/WEB-INF/faces-config.xml
Listagem 4. Conteúdo do arquivo /admin/modelo/novo.xhtml
  <?xml version="1.0" encoding="ISO-8859-1"?>  
      <html xmlns="http://www.w3.org/1999/xhtml"
            xmlns:f="http://java.sun.com/jsf/core"      
            xmlns:h="http://java.sun.com/jsf/html">
      <h:head></h:head>
      <h:body>
      <h:form>
       
      <h3>Novo modelo</h3>
      <div>Descrição: <h:inputText value="#{novoModeloMB.modelo.descricao}"/></div>
      <div>Fabricante: 
            <h:selectOneRadio value="#{novoModeloMB.modelo.fabricante}">
                  <f:selectItems value="#{novoModeloMB.fabricantesDisponiveis}"/>
            </h:selectOneRadio>
      </div>
      <div>Ano:  
            <h:selectOneMenu value="#{novoModeloMB.modelo.ano}">
                  <f:selectItems value="#{novoModeloMB.anosDisponiveis}"/>
            </h:selectOneMenu>
      </div>
      <div>Alcóol: <h:selectBooleanCheckbox value="#{novoModeloMB.modelo.alcool}" /> </div>
      <div>Gasolina: <h:selectBooleanCheckbox value="#{novoModeloMB.modelo.gasolina}" /> </div>
      <div>
            <h:commandButton action="#{novoModeloMB.cadastra}" value="Cadastrar" />
      </div>
       
      </h:form>
      </h:body>
      </html> 

Para processarmos eventos em componentes de tela adequadamente, é primeiramente necessário vincular alguma ação em um destes componentes a um código Java. A maneira como conseguimos relacionar componentes de tela definidos em um arquivo XHTML com algum método é através da Expression Language (EL), que são expressões definidas com o auxílio da sintaxe #{valorDaExpressao}. Expressões EL podem gerar basicamente dois tipos de resultados: 1) um vínculo de valor (ValueExpression), que referencia uma relação getter/setter associada a algum objeto em nosso modelo; 2) um vínculo de método (MethodExpression), que referencia um método a ser executado dado uma ação.

Objetos vinculados com o comportamento de tela (seus eventos e componentes) tradicionalmente são chamados de ManagedBeans. A partir do Java EE 6, é possível associar objetos administrados pelo CDI aos componentes JSF– utilizando a anotação @Named desta API. O Managed Bean vinculado à tela da Figura 1 pode ser visualizado na Listagem 5.

  package locadora.mb;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
 
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
 
import locadora.model.Modelo;
import locadora.repositorio.Repositorio;
 
 
@Named
@RequestScoped
public class NovoModeloMB {
      
      private Modelo modelo = new Modelo();
      
      @Inject
      private Repositorio repositorio;
      
      public String cadastra(){
            System.out.println("Modelo " + modelo.getDescricao() + " cadastrado!");
            repositorio.adiciona(modelo);
            return "visualiza";
      }
 
      public List<String> getFabricantesDisponiveis(){
            return Arrays.asList("GM","Ford","Fiat","Hyundai");
      }
      
      public List<Integer> getAnosDisponiveis(){
            List<Integer> anos = new ArrayList<Integer>();
            for(int i = 1970; i <= 2012; i++){
                   anos.add(i);
            }
            return anos;
      }
      
      public Modelo getModelo() {
            return modelo;
      }
 
}
Listagem 5. Código do managed bean NovoModeloMB

O Managed Bean definido em NovoModeloMB.java é um objeto comum administrado pelo CDI. Um detalhe importante em sua implementação é a presença da anotação @RequestScoped, que define que este objeto vive dentro do contexto de uma mesma requisição web. Pelo fato de ser um objeto CDI, podemos utilizar também o mecanismo de injeção de dependências desta API, representado pela anotação @Inject, que indica ao container que este atributo deve ser automaticamente injetado com algum objeto no momento de sua criação.

No nosso caso, também trabalhamos com um objeto que representa um repositório global de objetos, isto é, um mecanismo para realizarmos operações como consultas e cadastros de objetos. Este repositório deverá ser único para a nossa aplicação, e definimos isto através da anotação @ApplicationScoped do CDI, disponível na Listagem 6. Este repositório representa o meio de acesso a dados, e pode ser evoluído para fazer acesso a algum banco de dados, porém atualmente apenas armazena os objetos em memória.

Listagem 6. Código da classe Repositorio

package locadora.repositorio;
 
//imports omitidos...
 
@Named
@ApplicationScoped
public class Repositorio implements Serializable{
            
      private List<Modelo> modelos = new ArrayList<Modelo>();
 
      public void adiciona(Modelo modelo) {
            modelos.add(modelo);       
      }      
      
}

Em nosso caso da página de criação de modelos de carros, os componentes da tela estão estabelecendo um vínculo com objetos através de expressões como #{novoModeloMB.modelo.descricao}, o que define uma expressão baseada em valor, isto é, um vínculo através de getters/setters. Devido a este vínculo, quando a tela for processada e disponibilizada para o usuário, o componente será preenchido com o valor correspondente ao objeto administrado pelo CDI “novoModeloMB” (que é o nome padrão da classe NovoModeloMB com a anotação @Named sem parâmetros) e nele será realizada a chamada getModelo().getDescricao(), que inicialmente não retornará valor algum, resultando em um campo vazio para preenchimento do usuário. Após o carregamento da página no navegador, este campo estará disponível para o preenchimento do usuário. Em uma próxima interação com alguma chamada ao servidor, como é o caso do botão Cadastrar, o valor preenchido pelo usuário neste campo será atualizado no objeto do tipo NovoModeloMB, localizado no servidor, seguindo a chamada getModelo().setDescricao(). O código da classe Modelo, que terá seus atributos preenchidos por valores indicados pelo usuário nos campos da página, está disponível na Listagem 7.

Listagem 7. Código da classe Modelo
  package locadora.model;
       
      public class Modelo {
       
            private String descricao;
            private String fabricante;
            private Integer ano;
            private boolean gasolina;
            private boolean alcool;
            
            //getters e setters
      }

Definimos na Listagem 1 um componente visual que representa o botão de cadastro de modelos através da tag . Este botão está vinculado ao método cadastra() da classe NovoModeloMB através da expressão EL #{novoModeloMB.cadastra} e por isto ele será chamado quando o usuário clicar no botão. Ao ser executado o método cadastra() adicionará o atributo modeloao nosso repositório, retornando após isto a String “visualizar”, que indica ao container para encaminhar a requisição para a página visualizar.xhtml.

Neste exemplo estamos utilizando o CDI para manipular alguns de nossos objetos. Estamos anotando as classes NovoModeloMB e Repositorio com @Named, pois isto indica ao CDI que ele poderá criar e administrar objetos destas classes. Para o funcionamento correto do CDI, ainda é necessário criar um arquivo de configuração conforme a Listagem 8. Inicialmente este arquivo terá apenas um esboço de uma estrutura XML, sem muito conteúdo, porém é obrigatório para o funcionamento do CDI.

Listagem 8. Arquivo de configuração do CDI (/WEB-INF/beans.xml)
  
    <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
      
    </beans>

Também é muito comum a criação de um arquivo XML para algumas configurações diretamente vinculadas ao JSF, o arquivo faces-config.xml. A nova versão do JSF não obriga a existência deste arquivo para funcionar, porém diversos comportamentos suportados por este framework necessitam de configurações neste arquivo, logo já iremos criá-lo com o conteúdo indicado na Listagem 9.

Listagem 9. Arquivo de configuração do JSF (/WEB-INF/faces-config.xml)
  <?xml version="1.0" encoding="UTF-8"?>
      <faces-config xmlns="http://java.sun.com/xml/ns/javaee" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
      http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
      version="2.0">      
      
      </faces-config>

Partimos do princípio que o leitor possui alguma familiaridade com aplicações web em Java a ponto de conhecer a estrutura básica de um pacote WAR. O leitor pode utilizar diversas ferramentas para criar seu pacote WAR, dentre elas o Maven. Um breve detalhamento sobre o funcionamento do Maven pode ser observado na seção inicial deste artigo. No entanto, independente da tecnologia utilizada para a criação do pacote WAR, sua estrutura inicial com base no exemplo que estamos desenvolvendo pode ser observada na Listagem 3.

Ciclo de vida do JSF

Explicar como o JSF simula na web uma chamada de eventos em componentes de uma forma parecida com APIs para Desktop é um dos pontos mais complicados desta tecnologia. Em grande parte, esta capacidade se dá devido ao ciclo de vida deste framework. Uma ilustração sobre este ciclo de vida está disponível na Figura 3.

Ciclo de vida do JSF
Figura 3. Ciclo de vida do JSF

Os navegadores (browsers) acessam servidores web por meio do protocolo HTTP. Este protocolo foi inicialmente proposto para o compartilhamento de informações, e está fortemente baseado em realizar requisições por um recurso e obter uma resposta desta requisição. Ao se estudar o ciclo de vida JSF, o primeiro ponto a ser observado é que o JSF lê a estrutura de um arquivo XHTML e monta internamente uma árvore de componentes com base na definição indicada neste arquivo. Esta árvore de componentes é fundamental para que o JSF reconheça e saiba trabalhar de uma maneira orientada a componentes e seus eventos relacionados (como cliques de botão, entrada de foco em campos, cliques em links, etc.). O código XHTML enviado ao navegador do cliente é baseado nesta árvore de componentes.

Quando a tela é manipulada por um usuário em seu navegador, disparando algum evento que deva envolver processamento do servidor, a árvore de componentes desta página é carregada novamente pelo lado do servidor, o que ocorre na etapa Restaurar View.

Após isto, os valores referentes ao formulário, enviados pelo navegador, são armazenados na árvore de componentes no servidor. Logo após o armazenamento, estes valores são convertidos para valores mais adequados, já pensando em sua representação no modelo Java, utilizando os Converters – que trataremos posteriormente. Este ciclo de vida também possui uma etapa focada em processar validações individuais dos componentes, o que nos permite escrever e reutilizar validações elegantes através de Validators.

Com os dados dos componentes validados, o JSF aplica estes valores diretamente no modelo – como ocorreu a atualização do atributo descricao da classe Modelo em nosso exemplo. Após os dados da tela do usuário estarem em seus “devidos lugares”, o JSF invoca o método indicado para o evento correspondente à ação executada (como é o caso do método cadastra() em nossa classe NovoModeloMB). De acordo com o retorno do processamento do modelo, o JSF processa o resultado da navegação, isto é, para qual página essa requisição deve ser encaminhada. Com o resultado da navegação, o framework renderiza a resposta para o navegador baseada em alguma página XHTML, como é o caso do encaminhamento para a página visualizar.xhtml em nosso exemplo.

Conversores

Uma das primeiras etapas do ciclo de vida que é relevante para nosso desenvolvimento é a conversão dos valores preenchidos pelo usuário no navegador para valores mais interessantes de serem trabalhados no servidor, pensando em nossos tipos de dados complexos que podemos utilizar na programação Java.

Para exemplificar este item, desenvolvemos a funcionalidade de cadastro de clientes, como indicado na Figura 4. Nosso cliente deverá digitar seu CPF formatado em seu navegador, enquanto no servidor este valor deverá ser convertido para sem formato algum. Além disto, o cliente deverá informar sua data de nascimento formatada, enquanto no servidor esta informação será mais bem representada através de um objeto java.util.Date. Para este tipo de problema podemos utilizar os Converters. Estes são objetos responsáveis por converter informações indicados pelo usuário em uma representação mais adequada no servidor, e vice-versa.

Tela
    de Cadastro de clientes
Figura 4. Tela de Cadastro de clientes

O JSF já disponibiliza alguns conversores que podem ser utilizados imediatamente em nosso código, como é o caso do conversor para tipos data . Também é possível criar e utilizar conversores customizados em nossas páginas, como será necessário para o caso do campo CPF.

Para definir um conversor customizado, precisamos apenas criar uma classe que implemente a interface javax.faces.convert.Converter e anotá-la com @FacesConverter. Através desta anotação também podemos indicar o nome deste conversor, como é o caso de nosso CpfConverter, indicado na Listagem 10.

A criação de um conversor customizado também necessita da implementação de dois métodos, o getAsObject() e o getAsString(). O primeiro possui o objetivo de receber um valor String indicado pelo navegador e convertê-lo para uma representação mais significativa para o lado do servidor, enquanto o segundo faz o caminho oposto.

Listagem 10. Código de nosso conversor de CPF (CpfConverter)
  package locadora.converter;
       
      //imports...
       
      @FacesConverter("cpfConverter")
      public class CpfConverter implements Converter {
       
            public Object getAsObject(FacesContext facesContext, 
            UIComponent component, String valor) {
                  String semPontuacao = valor.replaceAll("\\.|-", ""); 
                  //removendo pontos e traços
                  return semPontuacao;
            }
       
            public String getAsString(FacesContext facesContext, 
            UIComponent component, Object objeto) {
                  String cpf = (String) objeto;
                  cpf = cpf.substring(0, 3) + "." + cpf.substring(3, 6) + "." 
                  + cpf.substring(6, 9) + "-" + cpf.substring(9, 11);
                  return cpf;
            }
       
      }

Após isto, já se pode vincular um conversor a elementos de uma página, através de recursos como o atributo converter de um componente, ou utilizar a tag dentro do componente a possuir um conversor. Um exemplo mais claro de sua utilização pode ser verificado no código da página de cadastro de clientes, disponibilizado na Listagem 11.

Listagem 11. Código do arquivo /admin/cliente/novo.xhtml
  <?xml version="1.0" encoding="ISO-8859-1"?>  
      <html xmlns="http://www.w3.org/1999/xhtml"
            xmlns:f="http://java.sun.com/jsf/core"      
            xmlns:h="http://java.sun.com/jsf/html">
      <h:head></h:head>
      <h:body>
      <h:form>
       
      <h3>Cadastro de novo cliente</h3>
      <div>
            Nome: <h:inputText value="#{novoClienteMB.cliente.nome}"/>
      </div>
      <div> Data de nascimento: 
            <h:inputText value="#{novoClienteMB.cliente.dataDeNascimento}">
                  <f:convertDateTime pattern="dd/MM/yyyy" type="date"/>
            </h:inputText>
      </div>
      <div>
            CPF: <h:inputText value="#{novoClienteMB.cliente.cpf}" converter="cpfConverter"/>
      </div>
      <div style="padding-top: 10px;">
            <h:commandButton action="#{novoClienteMB.cadastra}" value="Cadastrar" />
      </div>
       
      </h:form>
      </h:body>
      </html>

Estamos definindo o campo que representa o CPF do cliente na Listagem 11 com o atributo converter recebendo o valor cpfConverter. Isto indica ao JSF que este conversor deve ser utilizado para valores digitados neste campo.

Além disto, podemos utilizar algumas tags já presentes no JSF que representam conversores específicos, como é o caso de nosso campo data de nascimento. Neste campo utilizamos um conversor de data/hora do JSF e o configuramos para ler datas em formato dd/MM/yyyy e convertê-las em objetos do tipo java.util.Date.

Este exemplo da funcionalidade de cadastro de clientes é similar à tela de cadastro de modelos. Assim como em nosso primeiro exemplo, na tela de cadastro de clientes utilizamos um Managed Bean denominado NovoClienteMB, que pode ser observado na Listagem 12, para possuir informações sobre o modelo Java (neste caso representado pelo atributo cliente) e processar eventos de tela – como é o caso do método cadastra(). O nosso modelo de negócios, neste cenário representado pela classe Cliente, possui alguns dados básicos referentes a um cliente de nossa aplicação, e pode ser observado na Listagem 13.

Listagem 12. Código do managed bean NovoClienteMB
  package locadora.mb;
       
      // imports...
       
      @Named
      @RequestScoped
      public class NovoClienteMB implements Serializable{
       
            private Cliente cliente = new Cliente();
            
            @Inject
            private Repositorio repositorio;
            
            public String cadastra(){
                  repositorio.adiciona(cliente);
                  return "lista";
            }
       
            public Cliente getCliente() {
                  return cliente;
            }
            
            
      }
Listagem 13. Código da classe Cliente
  
    package locadora.model;
       
      public class Cliente {
            
            private String nome;
            private Date dataDeNascimento;
            private String cpf; 
       
            //getters e setters
      }

Além de serem utilizados para converter dados simples em complexos, os conversores também podem ser utilizados para apresentar informações representadas por objetos complexos de uma maneira mais amigável. O JSF nos permite melhorar essa representação, pois além de vincular conversores em componentes de entrada de dados, podemos vinculá-los a componentes de saída, como o . Para exemplificar este aspecto, disponibilizamos na Listagem 14 o código de uma página de listagem de clientes, com o objetivo de mostrar de maneira amigável a data de nascimento dos clientes e o CPF dos mesmos. A visualização desta página pode ser observada na Figura 5.

Listagem 14. Código do arquivo /admin/cliente/lista.xhtml

    <?xml version="1.0" encoding="ISO-8859-1"?>  
    <html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"      
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head></h:head>
    <h:body>
    <h:form>
     
    <h3>Lista de clientes</h3>
     
    <h:dataTable var="cliente" value="#{todosOsClientes}" border="1">
     
      <h:column>
        <f:facet name="header">
          Nome
        </f:facet>
        <h:outputText value="#{cliente.nome}" />
      </h:column>
      <h:column>
        <f:facet name="header">
          Data de Nascimento
        </f:facet>
        <h:outputText value="#{cliente.dataDeNascimento}">          
          <f:convertDateTime type="date" dateStyle="long" locale="pt,BR"/>
        </h:outputText>
      </h:column>
      <h:column>
        <f:facet name="header">
          CPF
        </f:facet>
        <h:outputText value="#{cliente.cpf}" converter="cpfConverter" />
      </h:column>
    </h:dataTable>
     
    </h:form>
    </h:body>
    </html>
Tela de listagem de clientes
Figura 5. Tela de listagem de clientes

Validadores

Sistemas precisam de validações. Dentre os diversos tipos de validação existentes em aplicações web, podemos precisar de validações individuais nos campos que criamos. Por exemplo, um valor de CPF válido não pode possuir qualquer sequência de números, enquanto uma data de nascimento correta sempre precisa ser anterior à data atual.

Para este tipo de problema, o JSF permite que vinculemos validadores aos componentes que definimos nas páginas. Da mesma forma que os conversores, podemos tanto criar validadores customizados quanto utilizar os validadores já disponibilizados pelo framework. Assim, podemos alterar nossa página de cadastro de clientes para possuir as seguintes restrições: 1) o campo nome é obrigatório e precisa possuir ao menos cinco caracteres; 2) o campo data de nascimento é obrigatório e necessariamente é anterior ao dia de hoje; 3) o campo CPF é obrigatório e precisa obedecer às regras de validação deste documento.

Para a validação de CPF, podemos criar um validador customizado. Isto pode ser feito facilmente apenas ao criar uma classe que implementa a interface javax.faces.validator.Validator e que seja anotada com @FacesValidator. O validador de CPF pode ser observado na Listagem 15. Além deste, também precisamos criar um validador customizado para verificar se a data de nascimento do cliente se encontra no passado, o que segue o mesmo princípio e por isso não o disponibilizamos no artigo.

Listagem 15. Novo código de CpfValidator

      package locadora.validator;
       
      //imports...
       
      @FacesValidator("cpfValidator")
      public class CpfValidator implements Validator{
            
            private FacesMessage msg;
       
            public CpfValidator() {
                  msg = new FacesMessage("Validacao CPF falhou","CPF inválido");
                  msg.setSeverity(FacesMessage.SEVERITY_ERROR);
            }
       
            
            @Override
            public void validate(FacesContext facesContext, 
            UIComponent componente, Object valor) throws ValidatorException {              
                  String cpf = (String) valor;
                  if (cpf.length() != 11)                 
                         throw new ValidatorException(msg);
                  String numero = cpf.substring(0, 9);
                  String digitoCalculado = calculaDigito(numero);
                  String digitoInformado = cpf.substring(9, 11);
                  if(!digitoCalculado.equals(digitoInformado))
                         throw new ValidatorException(msg);
            }
            
            private String calculaDigito(String numero) {
                  //Cálculo de Digito de CPF
            }
      }

Após a criação dos validadores customizados, já podemos vinculá-los aos nossos componentes na tela de cadastro de clientes. Para fazer isto, podemos tanto utilizar o atributo validator quanto utilizar a tag de dentro do componente. Também podemos utilizar validadores disponíveis por padrão no JSF, como é o caso do .

Além de vincular os validadores aos componentes, é necessário definir onde as mensagens de validação serão exibidas. Para isto, é apenas necessário criar componentes para disponibilizar mensagens de erro, vinculando-as aos componentes adequados através do atributo for, que deverá corresponder a algum atributo id de componente a ser validado. O código da tela de cadastro de clientes com validações está disponível na Listagem 16. Um resultado de um preenchimento inadequado do formulário pode ser observado na Figura 6.


    <?xml version="1.0" encoding="ISO-8859-1"?>  
    <html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"      
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head></h:head>
    <h:body>
    <h:form>
     
    <h3>Cadastro de novo cliente</h3>
    <div>
      Nome: 
        <h:inputText id="nome" value="#{novoClienteMB.cliente.nome}" required="true">
          <f:validateLength minimum="5" />
        </h:inputText>
        <h:message for="nome" />
    </div>
    <div>Data de nascimento: 
      <h:inputText id="dataDeNascimento" 
      value="#{novoClienteMB.cliente.dataDeNascimento}" required="true">
        <f:convertDateTime pattern="dd/MM/yyyy" type="date"/>
        <f:validator validatorId="dataPassadaValidator"/>
      </h:inputText>
      <h:message for="dataDeNascimento" />
    </div>
    <div>
      CPF: 
      <h:inputText id="cpf" value="#{novoClienteMB.cliente.cpf}" 
      converter="cpfConverter" required="true">
        <f:validator validatorId="cpfValidator"/>
      </h:inputText>
      <h:message for="cpf" />
    </div>
    <div style="padding-top: 10px;">
      <h:commandButton action="#{novoClienteMB.cadastra}" value="Cadastrar" />
    </div>
     
    </h:form>
    </h:body>
    </html>
Listagem 16. Código do arquivo /admin/cliente/novo.xhtml (com validadores)
Cadastro de novo cliente com validação
Figura 6. Cadastro de novo cliente com validação

Mensagens e Internacionalização

Um dos itens que podem ser relevantes para uma aplicação web é a necessidade de se adequar a usuários de diversos países e (ou) línguas. Chamamos este conceito de internacionalização.

Existem muitos aspectos que precisam ser considerados para se internacionalizar uma aplicação. Neste artigo trataremos apenas do recurso de mensagens do JSF, que é uma ferramenta útil para interagir com usuários de línguas diferentes na mesma aplicação.

Idealmente, para que os textos de nossa aplicação não fiquem presos a apenas uma língua, não podemos colocá-los diretamente em nosso código XHTML. É considerado como boa prática reunirmos estes textos em um arquivo de mensagens, e apenas referenciarmos algum texto estático em nosso XHTML através de uma chave. É muito comum no mundo Java utilizarmos arquivos de properties para esta finalidade. Isto se deve pois um arquivo de properties possui uma estrutura muito simples para a definição de propriedades em um sistema Java.

Para utilizarmos um arquivo de mensagens com internacionalização é preciso vincular um arquivo de properties no arquivo faces-config.xml, associando-o a alguma variável para podermos referenciá-lo em nossas páginas. Um exemplo desta configuração pode ser observado na Listagem 17.

Listagem 17. Código do arquivo faces-config.xml preparado para internacionalização

    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config
      xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
      http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
      version="2.0"> 
    
      <application>
        <resource-bundle>
          <base-name>messages</base-name>
          <var>msg</var>
        </resource-bundle>
          <locale-config>            
            <default-locale>pt_BR</default-locale>
            <supported-locale>en_US</supported-locale>
          </locale-config>
      </application>
    </faces-config>

Com esta configuração, indicamos também o arquivo padrão – caso o navegador do cliente não informe sua língua ao servidor – bem como a lista de arquivos disponíveis. Assim, poderemos em nossas páginas acessar as mensagens através da expressão #{msg.chave_da_mensagem} de maneira totalmente integrada à nossa forma de trabalho. A mensagem resultante irá depender da língua informada pelo navegador ao servidor. Caso seja português-brasil, o JSF procurará pelo arquivo messages_pt_BR.properties no diretório /WEB-INF/classes, enquanto se a língua do navegador do cliente estiver como en_US, o arquivo utilizado será o messages_en_US.properties.

Agora, podemos alterar nosso cadastro de clientes para utilizar mensagens internacionalizadas. Para isto, criamos os arquivos messages_pt_BR.properties e messages_en_US.properties, que estão disponíveis nas Listagens 18 e 19. O código da página de cadastro de clientes atualizado com mensagens internacionalizadas pode ser observado na Listagem 20, enquanto o funcionamento da página em inglês pode ser verificado na Figura 7, sendo que o comportamento em português permanece o mesmo.

Listagem 18. Conteúdo do arquivo messages_pt_BR.properties
  cliente_novo_titulo=Cadastro de Novo Cliente
      cliente_novo_nome=Nome
      cliente_novo_cpf=CPF
      cliente_novo_dataDeNascimento=Data de Nascimento
      cliente_novo_cadastrar=Cadastrar
Listagem 19. Conteúdo do arquivo messages_en_US.properties
ode] cliente_novo_titulo=New Customer cliente_novo_nome=Name cliente_novo_cpf=Identification Number (CPF*) cliente_novo_dataDeNascimento=Birthday cliente_novo_cadastrar=Register
Listagem 20. Conteúdo do arquivo /admin/cliente/novo.xhtml (com mensagens internacionalizadas)

    <?xml version="1.0" encoding="ISO-8859-1"?>  
    <html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"      
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head></h:head>
    <h:body>
    <h:form>
     
    <h3><h:outputText value="#{msg.cliente_novo_titulo}" /></h3>
    <div>
      <h:outputText value="#{msg.cliente_novo_nome}:" />
        <h:inputText id="nome" value="#{novoClienteMB.cliente.nome}" required="true">
          <f:validateLength minimum="5" />
        </h:inputText>
        <h:message for="nome" />
    </div>
    <div><h:outputText value="#{msg.cliente_novo_dataDeNascimento}:" />
      <h:inputText id="dataDeNascimento" 
      value="#{novoClienteMB.cliente.dataDeNascimento}" required="true">
        <f:convertDateTime pattern="dd/MM/yyyy" type="date"/>
        <f:validator validatorId="dataPassadaValidator"/>
      </h:inputText>
      <h:message for="dataDeNascimento" />
    </div>
    <div>
      <h:outputText value="#{msg.cliente_novo_cpf}:" />
      <h:inputText id="cpf" 
      value="#{novoClienteMB.cliente.cpf}" converter="cpfConverter" required="true">
        <f:validator validatorId="cpfValidator"/>
      </h:inputText>
      <h:message for="cpf" />
    </div>
    <div style="padding-top: 10px;">
      <h:commandButton action="#{novoClienteMB.cadastra}" 
      value="#{msg.cliente_novo_cadastrar}" />
    </div>
     
    </h:form>
    </h:body>
    </html>
Cadastro de novo cliente em inglês
Figura 7. Cadastro de novo cliente em inglês

Montando layouts unificados com Facelets

Uma novidade na versão 2 do JSF é que temos suporte padrão à utilização de Facelets. Facelets é um projeto desenvolvido com o intuito de substituir o JSP como mecanismo de visualização (View) em um contexto JSF. Dentre suas principais características, está a facilidade de criar tags customizadas e a definição de layouts através de modelos.

Vamos supor que queremos definir um layout único para diversas páginas da nossa aplicação. Podemos, por exemplo, querer que algumas de nossas páginas possuam uma foto de um carro em sua parte superior, como um cabeçalho. Um exemplo desta estrutura visual pode ser observado na Figura 8.

Página de cadastro de modelo com layout unificado
Figura 8. Página de cadastro de modelo com layout unificado

Para administrar esta estrutura visual de maneira unificada, isto é, permitir alguma futura alteração na mesma sem a necessidade de modificar todos os XHTML referentes a cada página, o Facelets nos permite utilizar o recurso de composição de layouts.

No Facelets, um layout composto é normalmente utilizado através de arquivos de template. Um arquivo de template, como o demonstrado na Listagem 21, é um arquivo XHTML comum, porém indica alguns “pontos de inserção”, isto é, pontos na página em que algum conteúdo deve ser incluído. Esses pontos podem ser definidos através da tag .

Listagem 21. Código do arquivo /layout/template.xhtml

    <?xml version="1.0" encoding="ISO-8859-1"?>  
    <html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"   
      xmlns:h="http://java.sun.com/jsf/html">
    
    <h:head>
      <title>Locadora de Carros</title>
    </h:head>
     
    <h:body>
    <div>
      <h:graphicImage value="/img/carro.jpg" />
    </div>
     
    <div>
      <ui:insert name="corpo"/>
    </div>
    </h:body>
     
    </html>

Ao indicarmos os pontos de inserção através da tag , devemos também definir qual é o nome do conteúdo referente a este ponto. O nome atribuído a cada ponto de inserção é importante, pois no desenvolvimento de alguma página podemos utilizar a mesma estrutura visual informada no template, apenas definindo o conteúdo a ser associado a cada um dos pontos de inserção, vinculando-os através do nome – como indicado na Listagem 22.

Ao criarmos páginas como o caso do cadastro de modelo de veículos, que deve partilhar da estrutura visual definida em nosso template, não utilizamos mais a tag , e sim a tag , afirmando que esta página deve ser “encaixada” na estrutura indicada, vinculando-a através do atributo template desta mesma tag.

A definição do trecho a ser inserido na estrutura definida pelo template é indicada através da tag , vinculando o conteúdo interno desta tag ao ponto de inserção definido pela tag no arquivo de template, associando-os pelo atributo name. Desta forma, unificamos a lógica do template em nossa aplicação, facilitando sua manutenção e possíveis alterações.

Listagem 22. Código da página /modelo/novo.xhtml

    <?xml version="1.0" encoding="ISO-8859-1"?>
          
    <ui:composition xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"      
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      template="/layout/template.xhtml">
    <ui:define name="corpo">
    <h:form>
     
     
    <h3>Novo modelo</h3>
    <div>Descrição: <h:inputText value="#{novoModeloMB.modelo.descricao}"/></div>
    <div>Fabricante: 
      <h:selectOneRadio value="#{novoModeloMB.modelo.fabricante}">
        <f:selectItems value="#{novoModeloMB.fabricantesDisponiveis}"/>
      </h:selectOneRadio>
    </div>
    <div>Ano:  
      <h:selectOneMenu value="#{novoModeloMB.modelo.ano}">
        <f:selectItems value="#{novoModeloMB.anosDisponiveis}"/>
      </h:selectOneMenu>
    </div>
    <div>Alcóol: <h:selectBooleanCheckbox value="#{novoModeloMB.modelo.alcool}" /> </div>
    <div>Gasolina: <h:selectBooleanCheckbox value="#{novoModeloMB.modelo.gasolina}" /> </div>
    <div>
      <h:commandButton action="#{novoModeloMB.cadastra}" value="Cadastrar" />
    </div>
     
    </h:form>
    </ui:define>
    </ui:composition>

Dinamizando nossas páginas com Ajax

Outro recurso muito utilizado em sistemas web é uma técnica denominada AJAX (Asynchronous Javascript And Xml). Para entendermos a razão do surgimento desta técnica é importante compreender algumas restrições e problemas da arquitetura de sistemas web. Os sistemas web são, de forma geral, baseados no protocolo HTTP. É esse protocolo que define como será a conversa entre o navegador do usuário e o servidor web. O protocolo HTTP é fundamentado na requisição por um recurso qualquer (página, imagem, som, vídeo, etc.) e a resposta que o servidor web provê com base no conteúdo correspondente a este recurso.

Pelo fato de sistemas na internet estarem baseados no HTTP, o conceito de página web é muito presente. Quando você pensa em página, já lhe vem à mente a ideia de um recurso estático (que não é dinâmico). Apesar disto, na medida do tempo, desenvolvedores começaram a buscar formas de executar operações no servidor web, de acordo com alguma operação no navegador do usuário, sem precisar recarregar a página inteira novamente.

O AJAX é uma alternativa a este tipo de problema. Este recurso possibilita processar alguma operação indicada pelo cliente (navegador) sem precisar requisitar uma página inteira novamente para o servidor, promovendo também uma interação mais agradável para o usuário. Ao usar essa técnica, uma requisição web é enviada para o servidor “por trás dos panos” e a página demonstrada pelo navegador não é recarregada – e sim apenas uma parte dela.

Este tipo de técnica é útil em vários momentos, porém realizaremos um exemplo simples com fins didáticos. Vamos desenvolver uma listagem de modelos de carros que nos permitirá excluir alguns deles sem a necessidade de recarregar a tela da listagem inteira novamente. Esta listagem pode ser observada na tela para exclusão de modelos exibida Figura 9.

Página de listagem de modelos
Figura 9. Página de listagem de modelos

O usuário poderá excluir qualquer um destes modelos previamente cadastrados. Para aprimorar a usabilidade da nossa aplicação, podemos desenvolver esta operação de exclusão de modelos de maneira a utilizar a técnica AJAX, para exemplificar o suporte que o JSF nos disponibiliza para usufruir desta técnica. Com isto, é possível indicar que a tela não seja totalmente processada e recarregada, mas sim apenas a tabela ou o botão em questão.

Para capacitar a operação de um componente JSF via AJAX, devemos apenas inserir a tag internamente ao componente escolhido, preenchendo alguns atributos que serão mais bem tratados a seguir. Um exemplo disto pode ser observado na Listagem 23.

Listagem 23. Código do arquivo /admin/modelo/lista.xhtml

    <?xml version="1.0" encoding="ISO-8859-1"?>  
    <html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"      
      xmlns:h="http://java.sun.com/jsf/html">
          
    <h:head></h:head>
    <h:body>
    <h:form id="formListagem">
     
    <h3>Lista de modelos</h3>
    <h:dataTable id="tabela" var="modelo" border="1" value="#{todosOsModelos}"
     binding="#{listagemDeModelosMB.tabelaDeModelos}">
     
      <h:column>
        <f:facet name="header">
               Descrição
        </f:facet>
        <h:outputText value="#{modelo.descricao}" />
      </h:column>
      <h:column>
        <f:facet name="header">
               Fabricante
        </f:facet>
        <h:outputText value="#{modelo.fabricante}" />
      </h:column>
      <h:column>
        <f:facet name="header">
               Ano
        </f:facet>
        <h:outputText value="#{modelo.ano}"/>
      </h:column>
      <h:column>
        <h:commandButton action="#{listagemDeModelosMB.excluiCliente}" value="Excluir" >
          <f:ajax execute="@this" render="@form"/>
        </h:commandButton>
      </h:column>
    </h:dataTable>
     
    <h:commandButton action="#{listagemDeModelosMB.sair}" value="Sair" />
     
    </h:form>
    </h:body>
    </html>

Neste exemplo, definimos um botão com conteúdo “Excluir” e habilitamos a capacidade deste componente ser processado através de AJAX. Ao habilitar esta capacidade, devemos informar quais componentes o navegador deve enviar para serem processados no servidor através do atributo execute. Para executar a exclusão de um modelo, não precisamos que nenhum componente seja processado no servidor, exceto o componente do próprio botão excluir. Isto ocorre porque para a exclusão se concretizar, a única informação importante é qual dos botões “Excluir” o usuário clicou, vinculando qual modelo deve ser excluído. Para identificarmos que este componente deve ser processado, indicamos o valor @this no atributo execute.

Após a requisição AJAX, definimos através do atributo render qual parte da página deve possuir seus valores atualizados para o cliente (navegador), dado o novo contexto do modelo pós-processamento da operação.

Outro recurso interessante neste código é a utilização do atributo binding. Este atributo indica ao JSF qual getter/setter utilizar para vincular o componente específico (no caso uma dataTable) a algum atributo em nosso código Java (no caso o atributo tabelaDeModelos). Com esse recurso, podemos simplesmente verificar qual foi o modelo selecionado e deletá-lo diretamente no repositório no servidor. Um exemplo do atributo vinculado a este componente dataTable através do binding disponível na Listagem 23 pode ser visto na Listagem 24.

Listagem 24. Código da classe ListagemDeModelosMB

    package locadora.mb;
     
    // imports
     
    @Named
    @RequestScoped
    public class ListagemDeModelosMB implements Serializable{
     
      private HtmlDataTable tabelaDeModelos;
    
      @Inject
      private Repositorio repositorio;
    
    
      public void excluiCliente(){
        Modelo modeloSelecionado = (Modelo) tabelaDeModelos.getRowData();
        repositorio.remove(modeloSelecionado);
      }
    
      public HtmlDataTable getTabelaDeModelos() {
        return tabelaDeModelos;
      }
    
      public void setTabelaDeModelos(HtmlDataTable tabelaDeModelos) {
        this.tabelaDeModelos = tabelaDeModelos;
      }
                
          
    }

Conclusões

Vimos neste artigo como realizar algumas operações básicas com o JavaServer Faces (JSF) e alguns recursos interessantes que a versão 2 nos permite usufruir.

Consideramos interessante a abordagem utilizada pelo JSF de trabalhar baseado em componentes, pois é fácil vincular o estado da tela através de atributos de Managed Beans, bem como processar eventos destes componentes como métodos destes objetos.

A versão 2 do JSF trouxe diversas facilidades úteis no dia a dia do desenvolvedor, como a configuração baseada em anotações, a integração com o CDI, a utilização de Facelets, o suporte nativo a AJAX, entre tantos outros recursos.

Além de ser um framework muito utilizado no mercado, suas melhorias nesta nova versão, bem como a simplificação de seu desenvolvimento dentro do contexto do Java EE 6, tornam esta tecnologia bastante atrativa para novos projetos web. Outro aspecto que deve ser ressaltado é que o JSF é o mecanismo padrão do Java EE para suporte a desenvolvimento de sistemas web. Com isto, uma aplicação que o utilize rodará em qualquer servidor de aplicação que atenda a esta especificação.


Links Úteis


Saiba mais sobre Java ;)

  • Carreira Programador Java: Nesse Guia de Referência você encontrará o conteúdo que precisa para iniciar seus estudos sobre a tecnologia Java, base para o desenvolvimento de aplicações desktop, web e mobile/embarcadas.
  • Linguagem Java: Neste Guia de Referência você encontrará todo o conteúdo que precisa para começar a programar com a linguagem Java, a sua caixa de ferramentas base para criar aplicações com Java.
  • Hibernate: Neste Guia de Referência você encontrará cursos, devcasts e artigos que demonstram todos os recursos do Hibernate.
  • Spring Framework: Neste Guia de Referência você encontrará o conteúdo que precisa para aprender a desenvolver aplicações utilizando o Spring Framework e seus subprojetos.
  • JSF - JavaServer Faces: Neste Guia de Referência você encontrará todo o conteúdo que precisa para conhecer o JSF, especificação Java que traz conceitos do padrão MVC e que facilita a construção de interfaces web utilizando componentes.
  • REST e Java: Devido a sua simplicidade, os Web Services RESTful têm se tornado cada vez mais populares. Neste guia você encontrará os conteúdos que precisa para dominar esse modelo que permite a construção de serviços menores a APIs completas.
  • Padrões de Projeto em Java: Neste guia de consulta você encontrará diversos conteúdos sobre padrões de projeto e arquitetura e como aplicá-los em suas aplicações Java, tais como os padrões GoF e Refactoring.