Meu livro perdido de JSF - um guia incompleto pra quem precisa aprender rápido

Um livro inacabado de JSF que vai te ajudar a dar os primeiros passos na tecnologia caso algum projeto apareça na sua frente e você precise se virar rápido

Meu livro perdido de JSF - um guia incompleto pra quem precisa aprender rápido

O material que você lerá a seguir é um livro inacabado que escrevi para a equipe da itexto num momento em que pouquíssimas pessoas falavam em JSF (era 2018, 2019 se não me falha a memória).

Os livros que encontrei não atendiam as demandas da itexto naquele momento: precisávamos evoluir um legado bem grande escrito em JSF. Como líder técnico e alguém que já tinha tido alguma experiência com a tecnologia no passado tomei o caminho que era o mais rápido para nós: iniciar a escrita deste livro.

O tempo era curto, o projeto já estava entrando e a equipe precisava estar pronta. Então não sei muito bem como, mas em umas oito horas escrevi este material.

Importante: este livro está inacabado. Seu objetivo é te fornecer a base para que você possa dar os primeiros passos no JSF e se virar daí pra frente. Não vá ficar triste com o final deste livro, hein? Eu avisei!

Introdução - ESTA É PARA LER!

Então de repente você se viu na necessidade de evoluir uma base de código baseada em JSF e está perdido por não saber direito por onde começar. É necessário um guia direto que te torne produtivo rápido, te fornecendo apenas o estritamente necessário para que, com o tempo, o aprofundamento no framework se torne natural e mais fácil.

Este guia foi escrito pensando em você. Especialmente se sua experiência principal não é lidando diretamente com Java EE, mas sim Spring ou outros frameworks que sejam `action based`.

Você já sabe ou tem alguma noção a respeito do que é o JSF: é um framework voltado para o desenvolvimento de aplicações web voltado para a plataforma Java EE. Não irei lhe explicar neste livro o que é o Java EE, mas vou te mostrar como o JSF funciona de fato.

Normalmente leitores de material técnico pulam a introdução. Te imploro, não pule esta, pois é vital para que você possa ter máximo proveito deste material.

JSF e eu - esta parte você pode pular

Este livro nasce da minha própria experiência: quando o JSF apareceu em 2004 fui um dos muitos que se maravilhou com a tecnologia. Sem sombra de dúvidas se mostrava como o futuro: eu, que estava saindo do desenvolvimento desktop e lutando para entender a web de repente me via diante de um framework que me possibilitava um modelo de desenvolvimento muito parecido com aquele que estava acostumado no Delphi, Visual Basic ou mesmo Swing (Java): componentes e um pensamento muito voltado para janelas, no caso, páginas que se pareciam com as antigas janelas que estava acostumado a desenvolver.

E eu realmente gostava da coisa: ao ponto de ter inclusive publicado cursos sobre o JSF com Facelets mais ou menos naquela época.

O tempo passou, a web se mostrava cada vez mais atraente e simples. Passei a conhecer outros frameworks, como Ruby on Rails, Grails e Spring que de repente me fizeram ver o JSF como uma das tecnologia tola: por que pensar como desktop se eu estava na web? Ainda pior, o modelo de desenvolvimento que havia conhecido no JSF não tirava proveito da web: era como se a web fosse baseada em formulários.

Com o tempo JSF foi apagado da minha vida profissional, Grails, Spring e outros frameworks tomaram seu lugar e, essencialmente, JSF que era uma das minhas expertises sumiu da minha vida.

Algum tempo depois surgiu a necessidade/oportunidade de manter uma grande base de código baseada em um JSF que desconhecia: o JSF 2. Em um primeiro momento achei que seria fácil aprender, mas não foi o caso. O material que encontrava a respeito não me satisfazia, ainda pior: era cheio de lacunas (vou ser honesto, achei um lixo, o que me motivou a escrever este livro).

Para piorar, encontrar profissionais que dominassem o JSF na minha localidade (Belo Horizonte) se tornou difícil, razão pela qual optei por voltar aos princípios. Reaprender JSF do zero e, com isto, preparar o material que pudesse ser usado por minha equipe para que esta rápidamente pudesse aprender o framework, suas dificuldades (e também vantagens) e, com isto, pudéssemos evoluir código legado baseado no framework.

Viramos o jogo com a escrita deste material: em três semanas já estávamos produtivos no framework e eu conseguia delegar a execução de atividades nesta base legada para outras pessoas. Ainda melhor: começamos a ver oportunidades graças às características intrínsecas do framework que não conseguíamos ver antes, o que ampliou significativamente a nossa própria visão a respeito do mercado (não apenas legado, mas novas soluções também).

E não seria um exagero dizer que também adquiri uma nova visão a respeito da plataforma Java EE: ela se mostra agora como uma alternativa surpreendentemente mais atraente do que via até então. E todos os dias me pergunto: por que não prestei atenção no JSF e seu ecossistema antes???

Este livro e você - esta parte você DEVE ler

Este guia portanto é feito para você que caiu de paraquedas em um projeto baseado em JSF 2 e precisa dar conta deste recado rápido. O público inicial deste guia é a equipe da itexto, porém como com o tempo o guia foi crescendo, acredito que em breve deverá ser disponibilizado para um público maior.

Conhecimentos que você deve ter

Sobre este público interno: é importante que você saiba dele caso você não faça parte do nosso time, por que supõe que exista o conhecimento das seguintes tecnologias:

  • Java
  • Maven
  • Apache Tomcat
  • O uso de uma IDE de mercado (focarei aqui inicialmente no Eclipse)
  • Desenvolvimento web
  • Um pouco de Spring, pois usaremos alguns dos conceitos deste como analogia para explicar o funcionamento do JSF.

Para facilitar a compreensão deste material também é incluído código fonte, que poderá ser usado tanto para iniciar novos projetos quanto para ilustrar muitos dos tópicos apresentados neste trabalho.

Como ler este livro - LEIA ISTO

Sequencialmente, não cometa o erro de pensar neste material como um livro de referência. Fui costurando o conteúdo de tal maneira que cada capítulo te prepara para o próximo. Sendo assim você se encontrará constantemente (espero) voltando ao capítulo anterior para relembrar conceitos.

Faça os exercícios: ao contrário dos meus outros livros este é totalmente focado na prática e é essencialmente um tutorial no sentido de que meu objetivo é pegar você pela mão e lhe guiar a cada passo para que você possa interiorizar o modo de trabalho que o JSF oferece.

É necessária uma mudança de mentalidade caso seu background seja o Spring ou outro framework baseado em ações que é muito difícil de ser obtida com uma leitura meramente sequencial sem experimentação.

Experimente, erre, tente de novo, e se não conseguir ou não entender, não perca tempo e me escreva - kico@itexto.com.br - estou aqui pra te ajudar.

(há planos para a disponibilização de um fórum exclusivo para este material em breve)

(após a segunda leitura este livro pode ser usado como referência, mas na primeira, jamais. Não cometa este erro)

Sabe o código fonte que acompanha este livro? Brinque com ele, use-o como seu laboratório mas, mais importante: não use este código em produção. Usei uma abordagem estritamente pedagógica com ele.

Peço inclusive que faça mais: ao invés de copiar, veja como o escrevi, critique-o, encontre erros, escreva algo melhor (é fácil), tanto em produção quanto em seus estudos.

Se quiser ter um aproveitamento ainda maior, faça como eu: enquanto escrevia este livro implementei um ERP para a itexto (é um dos exemplos do livro, inclusive (em sua forma rudimentar)) com aquilo que aprendia para que novas cicatrizes, vindas da zona de guerra (também conhecida como ambiente de produção) pudessem proliferar sobre minha carne. Valeu à pena o exercício.

Sobre o escopo deste guia

O objetivo é apresentar apenas como funciona o JSF em si: não iremos tratar aqui de questões relacionadas à persistência. Esta, quando ocorrer, não usará um banco de dados relacional: no máximo um sistema de arquivos.

Acredito que sabendo apenas o básico a respeito do JSF você, leitor, estará preparado para prosseguir nestes demais tópicos por conta própria. Observe que esta é a primeira versão do guia ainda, sendo assim nada impede que apêndides sejam incluídos posteriormente a este material.

Isto não quer dizer que o livro se aplique apenas ao JSF. Lá na frente iremos ver rápidamente como o CDI funciona: seu conhecimento é essencial para que possa entender a fundo o comportamento do JSF a partir da versão 2.3.

Enquanto CDI não for mencionado diretamente, já sabe: estaremos falando do JSF 2.2 (apesar do código fonte que escrevemos desde o início ser baseado na versão 2.3 do framework).

Background que pode ser útil

Se você tem alguma experiência no desenvolvimento de aplicações desktop ou para dispositivos móveis (apps) este conhecimento lhe será útil. JSF surge em uma época na qual estávamos deixando o desenvolvimento desktop e a web se mostrava como o caminho a seguir.

E um caminho que tinha um empecilho: a esmagadora maioria dos desenvolvedores na época tinha mais experiência no ambiente desktop que web. Então, por que não tentar trazer para a web um ambiente de desenvolvimento similar ao que tínhamos com Delphi, Visual Basic, Power Builder, Swing ou outros? JSF claramente tenta simular estes ambientes.

Houve inclusive tentativas interessantes, mas que falharam miseravelmente, tais como o Netbeans Visual Web JSF, que nos provia uma interface do tipo arrastar e soltar para montar interfaces baseadas em web e, observando o modo como interagimos com formulários, fica claro que temos aqui um desenvolvimento baseado em eventos. Muito parecido com o…​ Visual Basic ou Delphi ou Swing…​

Aliás, um dos objetivos originais do JSF 1 era este: ter um framework que nos possibilitasse não apenas desenvolver aplicações web, mas também para o ambiente desktop, PDAs (alguém se lembra disto) e outros ambientes. Quer uma prova? Leia a primeira edição do livro Core JavaServer Faces.

O objetivo final

JSF não tem mais o sex appeal de quando surgiu ou após o lançamento da versão 2.0. A partir da 2.1 já era considerada uma tecnologia "chata" e sem grandes atrativos para os jovens profissionais.

Entretanto apesar de não ter mais este sex appeal, isto não quer dizer que seja uma tecnologia ruim ou mesmo ultrapassada. Iniciei a escrita deste livro pensando no JSF como algo irrelevante: minha opinião a seu respeito deu um giro de 180 graus enquanto desenvolvi este trabalho.

E sei bem que não temos boa produtividade com ferramentas que não gostamos. Sendo assim meu objetivo é aumentar a sua produtividade mostrando que esta não é uma tecnologia irrelevante, mas bastante interessante e com várias aplicações muito interessantes.

Se o sistema que você for desenvolver não tem uma API, apenas páginas, tendo a acreditar hoje que JSF deve ser levado em consideração como uma alternativa bastante viável e muito produtiva: bem mais do que me lembrava em meu primeiro contato com o framework mais de dez anos atrás (o tempo voa).

Mas sabe o que seria legal? Se no futuro "alguém" conseguisse fazer com que código JSF gerasse aplicações móveis ou desktop, né?

2. Preparando seu ambiente de desenvolvimento para o guia

Tal como o próprio nome indica, este é um guia, ou seja, iremos guias seu aprendizado a partir da leitura deste conteúdo e também a partir da execução de práticas que aqui serão descritas. Sendo assim é importante que os seguintes componentes estejam instalados em seu computador:

  • Sistema operacional (óbvio) - pode ser tanto Linux, Windows ou macOS, entretanto nossa ênfase aqui será o Linux.
  • JDK 8 ou posterior - mas os exemplos serão realizados usando a versão 8 (busque pelo último release disponível).
  • Maven 3.3.9.
  • Eclipse - busque pela distribuição (Eclipse IDE for Enterprise Java Developers) - https://www.eclipse.org/downloads/packages/
  • Apache Tomcat 8.5 - http://tomcat.apache.org

Sobre o JSF, será usado seu último release, que é o 2.3, lançado em 2017.

Instalando o Apache Tomcat

Neste guia iremos usar o Apache Tomcat 8.5, cuja instalação é bastante simples. O primeiro passo consiste em baixar a versão 8.5 no site oficial do projeto: https://tomcat.apache.org . Neste site, ao lado esquerdo estará exposto o link para download, tal como pode ser visto no print a seguir:

Na página de download busque pela seção Binary distributions e, na sequência, baixe a versão Core no formato zip, tal como exposto no print a seguir:

Realizado o download do arquivo zip, tudo o que você precisa fazer consiste em descompacta-lo no diretório de sua preferência. Caso esteja usando os sistemas Linux ou macOS, pode ser que seja necessário também alterar as permissões de alguns arquivos para que sejam executáveis. Estes arquivos consistem em todos aqueles com a extensão ".sh" armazenados na pasta bin da sua instalação do Tomcat.

Configurando o Eclipse

No momento da escrita deste guia a melhor opção para a manutenção de bases de código, em minha avaliação, é o Eclipse usando a distribuição Eclipse IDE for Enterprise Java Developers pelas seguintes razões:

  • É uma opção gratuita.
  • O Eclipse já tem maturidade comprovada pelo mercado.
  • Infelizmente o último release do Netbeans (10) não tem tantos recursos quanto a versão 8.5 no desenvolvimento de aplicações Java EE, o que é uma pena.

Caso o Eclipse não esteja instalado em sua máquina, use este link (https://www.eclipse.org/downloads/packages/) para baixar a distribuição Eclipse IDE for Enterprise Java Developers clicando sobre a opção, tal como apresentado no print a seguir:

A instalação é relativamente simples: basta descompactar o arquivo compactado no diretório de sua preferência e, na sequência, iniciar o Eclipse clicando sobre o executável que se encontra no diretório raíz da sua instalação.

O primeiro passo consiste em configurar um workspace para que possamos realizar nossas experimentações: no momento em que o Eclipse for iniciado, você verá a janela de seleção de workspace, tal como apresentado na imagem a seguir: escolha o diretório que lhe seja mais atraente neste momento.

Na janela inicial do Eclpse, busque pela aba Servers. Ela será muito parecida com a apresentada na imagem a seguir:

Caso não encontre a aba, vá ao menu Window → Show View: a opção Servers será uma das primeiras expostas. Caso não seja o caso, clique sobre a opção Others e, na janela de busca, digite Servers.

Clique sobre o link No servers available. Click this link to create a new server. Surgirá uma janela similar à apresentada na imagem a seguir. Selecione a opção Apache e, na sequência, a sub-opção Tomcat v8.5 Server.

Clique sobre a opção Next (ou Próximo se estiver em português) e, na sequência, sobre o botão Browse para que seja selecionado o diretório no qual você tenha instalado o Tomcat em seu computador.

É recomendado que você também selecione a versão do Java (JRE) a ser usada. Há duas opções: a padrão, usada para iniciar o Eclipse, ou uma customizada. Selecione a customizada, isto nos possibilitará garantir que, mesmo que iniciemos o Eclipse com outra versão do Java, sempre estejamos usando a mesma versão da JRE (Java Runtime Environment) para os nossos projetos neste guia.

Clicando sobre o botão "Finish" da última janela terá nos configurado o Eclipse para que este possa interagir com o Tomcat de forma automatizada, o que é essencial para que possamos obter produtividade mínima no desenvolvimento com JSF. Observe agora a aba Servers do Eclipse: sua instalação do Tomcat estará disponível para você, tal como pode ser visto na imagem a seguir:

Antes de iniciar a parte prática deste guia é importante responder a uma pergunta fundamental, que é o assunto do próximo capítiulo.

3. O que é o JSF?

Um pouco de história pra entender o contexto atual

É um framework voltado para o desenvolvimento de aplicações web na plataforma Java EE (JEE). Mais do que isto, o JSF (Java Server Faces) é o framework padrão para o desenvolvimento de interfaces web no Java EE, o que, em si, o torna uma alternativa bastante atraente para clientes corporativos pelas seguintes razões:

  • Há a certeza (ou ao menos a intenção) de que se trata de uma tecnologia que será mantida por um longo prazo.
  • Por ser um padrão, ao menos em teoria (falsa atualmente, veremos mais a frente as razões) será mais fácil de encontrar mão-de-obra qualificada para dar manutenção em projetos baseados nesta tecnologia.
  • Possui um corpo de mantenedores forte, cujo risco de desaparecimento imediato é pequeno.
  • Evita-se o risco de se ficar preso a um único fornecedor, dado que outros poderão implementar a especificação que define como o JSF deve se comportar.

Mais do que um framework, o JSF é na realidade uma especificação (JSR 314 para ser mais preciso https://jcp.org/en/jsr/detail?id=314), ou seja, um comitê define quais os recursos que deverão estar disponíveis em toda nova versão do framework, assim como os comportamentos esperados para as suas implementações. A ideia é que a partir de uma especificação existam diversas implementações criadas por distintos fornecedores, evitando-se com isto cair em um vendor lock-in ou mesmo o desaparecimento repentino da tecnologia. A ideia é muito boa, entretanto trás consigo alguns poréns que ficam claros observando o histórico do JSF desde seu lançamento:

  • v1.0 - 11/3/2004
  • v1.1 - 27/5/2004 (foi essencialmente um release focado na correção de bugs)
  • v1.2 - 2006
  • v2.0 - 2009
  • v2.1 - 2010
  • v2.2 - 2013
  • v2.3 - 2017

Algumas notas históricas são importantes para nos ajudar a entender por que não há tantas pessoas hoje interessadas em aprender e dominar o JSF. A começar pelo lançamento da versão 2.0 que, na prática, quebrou a compatibilidade com versões anteriores. Era possível realizar a migração, entretanto o esforço era significativo, fazendo com que econômicamente muitas vezes o esforço não se justificasse se comparado à reescrita em outros frameworks ou formas de desenvolvimento.

Vemos que a versão 2.1 foi lançada apenas um ano após, trazendo uma série de novos recursos ao framework, entretanto observamos uma média de 3 a 4 anos para o lançamento das versões 2.2 ou 2.3. Comitês infelizmente são lentos (especialmente no caso de uma tecnologia tão usada como JSF) demais para o desenvolvimento de uma tecnologia inserida em um contexto de rápidas mudanças.

Entre 2010 a 2017 a visão que tínhamos do desenvolvimento web mudou bastante. Enquanto até 2009, 2011 aproximadamente a renderização do lado servidor, tal como o JSF propõe era aceitável e mesmo defendida, a partir de 2011 observamos uma mudança fundamental no modo como aplicações web deveríam ser desenvolvidas: ao invés de termos uma solução monolítica, na qual a interface web e regras de negócio pertencem a um mesmo pacote, vemos a emergência do desacoplamento do frontend do backend.

Frameworks como Angular, EmberJS, Backbone e muitos outros nos mostraram que o desenvolvimento desacoplado destas duas partes dos sistemas (frontend e backend) não era só viável, como também economicamente interessantes. Ao termos a lógica de negócio dos nossos sistemas isolados, sem qualquer conexão direta com interfaces gráficas, temos a possibilidade de não ter apenas uma interface, mas infinitas variações, sejam elas web ou não (pense em sistemas embarcados acessando estas APIs, ou mesmo de mídia rica, como estes que executam em smart tvs).

Junto a esta "nova" visão sobre como deveria ser o desenvolvimento de soluções está o fato do JSF ser uma solução inteiramente voltada à renderização do lado servidor e, também, totalmente voltada apenas para a plataforma Java. Observe o ambiente de desenvolvimento que montamos para este guia: Java é parte essencial para o desenvolvimento de interfaces baseadas em JSF. Hoje em dia desenvolvedores frontend estão muito mais interessados (e estão certos) em desenvolver usando apenas tecnologias padrão web definidas pelo W3C (World Wide Web Consortium - https://w3.org) e derivada das mesmas, tais como ocorre com os frameworks JavaScript hoje.

Sendo assim, JSF como uma tecnologia a ser adotada para novos projetos hoje não é a primeira opção que vêm à mente da maior parte das organizações que desejam estar na crista (ou ao menos próximas) da onda tecnológica, justamente por que vemos hoje a API não apenas como a exposição dos nossos sistemas, mas sim como uma oportunidade para a geração de novos negócios.

Como funciona o JSF

Difícilmente você verá uma API desenvolvida usando JSF, mas apenas páginas, e isto por uma razão muito simples: JSF é feito pensando na renderização de páginas, e apenas isto. Indo um pouco além, temos aqui um framework baseado no modelo de componentes (component based), e não de ações (action based).

Dado que este guia é voltado para você, que caiu de paraquedas em um projeto baseado em JSF e que já está habituado ao "novo" modelo de desenvolvimento acima mencionado, no qual temos backend e frontend completamente desacoplados, vamos primeiro voltar às bases e lembrar como funciona um framework action based. Um detalhe: JSF também é um framework baseado no modelo MVC (Model View Controller). Então primeiro vamos dar mais um passo pra trás e relembrar o que é este padrão de projeto.

Relembrando o MVC

MVC é uma sigla: Model, View, Controller. Na minha opinião o modo como as letras são apresentadas na sigla influenciam na má compreensão do padrão. Sendo assim acredito que a melhor maneira de pensarmos neste padrão seja a partir do diagrama a seguir:

(neste guia iremos apresentar o padrão sob o ponto de vista de aplicações web, sendo assim você deve pensar aqui no protocolo HTTP como a base desta descrição)

O sobrecarregado Controlador

Tudo começa pelo Controlador. Este possui um papel orquestrador:

  • É o ponto inicial da interação do usuário com o servidor.
  • É ele que sabe qual parte do modelo deverá ser consultada.
  • Também é ele que saberá qual visualização deverá ser retornada ao usuário que realizou a solicitação.

E seu conhecimento a respeito do sistema deve ser apenas este. Não é papel do controlador saber se o valor retornado pelas regras de negócio consultadas está ou não correto. Também não é seu papel saber se a renderização enviada para o usuário final está tal como esperada. Seu papel é apenas o de orquestrar quem deverá ser chamado e o que deverá ser respondido.

Um pouco além, o controlador também realiza uma terceira função, a de transformador de dados. E esta transformação poderá ocorrer em dois momentos:

  • Transformando os parâmetros de entrada recebidos pela requisição para o formato correto que possa ser entendido pela camada de negócio (o modelo).
  • E também transformando o resultado retornado pela camada de negócios (Modelo) para que possa ser corretamente renderizado pela camada de visualização (Visão).

Sendo assim o controlador além de realizar estas transformações e também saber quem deverá chamar (orquestrar), possui mais uma função: a de realizar a validação formal dos parâmetros recebidos. Pensemos em um controlador que é iniciado a partir da URL a seguir:

GET http://magica.com.br/pessoa/1979

Esta URL tem como último componente o número 1979, que representa o identificador do registro a ser retornado/renderizado. Cabe aqui mais uma validação formal: será que o registro existe mesmo? Não existindo, devemos então retornar de cara o código 404 (not found/não encontrado) como resposta e sequer chamar o controlador.

Acho que após esta descrição talvez tenha ficado mais claro para você por que dizem por aí que ficar colocando regras de negócio neste componente é uma má ideia…​ Bom, prosseguindo.

O Modelo

O modelo é o responsável por ter implementadas todas as regras de negócio que um sistema deve executar. Entram aqui ações como algoritmos: que tipo de usuário pode ser excluído ou editado?, quem pode editar um usuário?, quem pode acessar o sistsema?, há um rosto nesta imagem?.

Mas mais do que isto: é aqui também que se define possíveis integrações que o sistema precise para funcionar. Estas integrações vão desde as mais simples, como a conexão com o banco de dados, até a chamada de webservices ou sistemas de mensageria.

E neste ponto há um conflito com o que acabo de mencionar sobre o fato do Controlador verificar se um registro existe. Ao verificar se um registro existe, não estaria o controlador fazendo mais do que esperado de si? A resposta é não. Idealmente o Modelo representa uma abstração do mundo, isto é, uma representaçaõd o mundo analógico em um computador.

Sendo assim, o ideal é que, no mesmo exemplo da URL mencionada no exemplo do Controlador, que o Modelo não conheça uma pessoa representada pelo valor inteiro 1979, mas sim por um Objeto que representa uma pessoa, que tem como um dos seus atributos o valor inteiro 1979. Esta é uma diferença fundamental.

O Modelo sempre deve se apresentar ao Controlador como uma interface na qual seus métodos sejam, idealmente, abstrações de objetos de negócio, e não atributos destes objetos de negócio. E o que é um objeto de negócio? Uma abstração que se manifesta, por exemplo, como um objeto, ou mesmo classes ou registros, e raríssimas vezes como atributos primitivos, tais como simples números ou valores booleanos.

Uma característica importante do modelo também é esta: ele não sabe de nada além de si mesmo. Um bom Modelo não sabe quem o renderizará ou quem o invocará: apenas sabe as regras de negócio e integrações de que precisa para que possa operar.

A Visão

Finalmente temos a visão. Enquanto o Controlador conhece os componentes do sistema que deverão ser invocados, e o Modelo conhece as integrações e algoritmos que deverão ser chamados, a Visão só deve se preocupar em gerar uma representação dos dados que recebe e nada mais do que isto.

A Visão se manifesta sob as mais diferentes formas: uma página HTML, um documento JSON, um arquivo Excel ou PDF. Seu objetivo final é dar um retorno que seja compreensível para aquele que iniciou a sua interação com o sistema.

E tal como o Modelo, a Visão também tem uma visão muito limitada do mundo: para ela tanto faz de onde vieram os dados que estão sendo renderizados, desde que possam ser renderizados.

O máximo que a Visão pode nos dar de retorno é um erro nos informando que os dados que recebeu não estão aptos para serem renderizados.

Leis básicas do MVC
  • Controlador deve saber qual Modelo invocar e qual Visão usar para renderizar o resultado obtido.
  • Modelo jamais saberá que um dia pode ser renderizado ou mesmo quem o invoca.
  • A Visão só se preocupa em renderizar os dados que recebe.

Seguindo estas três leis você obtém sistemas mais fáceis de serem mantidos e, principalmente, extendidos. Mas agora já falamos demais sobre MVC. Devemos prosseguir para entender como ele se manifesta em frameworks action based e component based.

Mais a frente você verá que esta minha descrição do padrão MVC foi bastante enviesada, pois leva em consideração uma visão action based do mundo…​

MVC em frameworks Action Based

Talvez você não tenha em mente nenhum framework action based por que está imerso nesta realidade há anos. Mas se está escrevendo um frontend que é totalmente desacoplado do backend, é grande a possibilidade do framework adotado na escrita deste backend (se é que há um framework) seja action based. Entender seu funcionamento fica mais fácil sob a ótica de sua aplicação no padrão MVC.

Em frameworks action based que sigam o padrão MVC há normalmente um ator oculto chamado Frontend Controller. Seu papel consiste em, no momento em que uma requisição é recebida, interpretar o endereço acessado e, com isto, encontrar qual o Controlador responsável pela execução daquela chamada.

O diagram a seguir expõe um fluxo padrão em frameworks action based ao acessar uma URL tal como, por exemplo: http://magic.itexto.com.br/pessoa/1979

1. É realizada a requisição inicial

O usuário envia a requisição ao nosso servidor ao endereço http://magic.itexto.com.br/pessoa/1979. Esta requisição é recebida pelo Frontend Controller.

2. Frontend Controller decide o que fazer

Com a requisição em mãos (que pode incluir também um corpo/payload) o Frontend Controller deve analisar a URL solicitada. É neste momento em que descobre-se a existência ou não de um Controlador que será o responsável pela execução daquela requisição. Não havendo um controlador, a resposta padrão costuma ser o retorno do código HTTP 404 (não encontrado/not found) ao solicitante.

Encontrando o controlador responsável, é repassado a este a requisição recebida.

Apenas uma nota importante: o Frontend Controller também pode ser extendido neste ponto para que verifique se o solicitante possui ou não acesso à aplicação, negando com isto seu acesso.

O trabalho do Frontend Controller na realidade costuma ser bem mais árduo do que a mera seleção de controladores. É ele também o responsável pela execução do binding, isto é, na transforamção dos parâmetros enviados na requisição em objetos que façam sentido à aplicação. Apenas para lembrar, o HTTP trafega apenas informações textuais. Sendo assim, é papel do Frontend Controller em diversos frameworks transformar os atributos recebidos em números, objetos, valores booleanos, etc.

3. Controlador invoca o Modelo

O Controlador realiza as transformações necessárias para que o modelo possa ser invocado. Seleciona o modelo desejado e, na sequência, o executa, obtendo com isto o valor de retorno que será usado posteriormente na renderização da resposta ao solicitante.

4. Controlador invoca a Visão

Com o resultado obtido a partir do Modelo, o Controlador executa as transformações necessárias para que o resultado obtido possa ser enviado ao módulo responsável por gerar a renderização da resposta a ser enviada ao solicitante.

A Visão então retorna ao Controlador aquilo que deverá ser retornado ao usuário final.

5 e 6 - Acaba a requisição

Este é o momento em que o Frontend Controller envia o resultado do processamento ao usuário que realizou a requisição à nossa aplicação. Note que aqui o fluxo talvez sequer passe pelo Controlador, dado que pode ter sido fornecida uma URL inválida ao Frontend Controller ou mesmo um payload incorreto.

O fluxo descrito nesta seção é exatamente o adotado pelo framework Spring MVC.

MVC em frameworks Component Based - o JSF

A ordem é diferente quando estamos falando do JSF: talvez esta seja uma das maiores dificuldades enfrentadas por aqueles que estão dando os primeiros passos no framework. Imaginemos agora uma URL um pouco diferente: a solicitação será iniciada em http://magic.itexto.com.br/pessoas.xhtml que é a página responsável por listar as pessoas cadastradas no sistema.

No caso de frameworks baseados em componentes (você vai entender mais a frente por que usamos o termo componente), iremos usar o fluxo adotado pelo JSF, mas que não irá variar muito em outras soluções, tais como o Apache Tapestry (http://tapestry.apache.org) ou Stripes (https://github.com/StripesFramework/stripes).

Novamente, vamos a mais um diagrama:

1. A requisição é recebida

No caso do JSF também existe um Frontend Controller. Ele inclusive possui um nome: Facelets Server. Este é o responsável por toda a execução do JSF. No momento em que a requisição é recebida é seu papel identificar o que deverá ser renderizado e, na sequência, iniciar o fluxo.

A grande diferença nos frameworks component based está na ordem em que o MVC é acionado. Neste caso, não estamos iniciando o processamento a partir de um controlador: o controlador, na realidade, é o próprio Frontend Controller, que apenas delega o início do processamento à visão, e não a outro controlador.

Muita atenção para este ponto: não existe outro controlador aqui. Existe um componente de visão que será o responsável por acionar o modelo. Lembra um pouco atrás quando falei que a visão do MVC que havia apresentado era bastante enviesada e baseada na experiência com frameworks action based? É por que no caso do JSF a Visão adquire aspectos de Controlador.

2. Acionando o Modelo

A visão no JSF consiste em páginas escritas no formato XHTML. A seguir podemos ver um exemplo de página JSF bastante simples e talvez seu primerio contato a componentes JSF:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>JSF Labs da itexto</title>
</h:head>
<h:body>
   <h1>JSF Labs</h1>
   <p>Olá #{pessoa.nome}
</h:body>
</html>

Observe que há a definição do namespace h. Ele aponta para as tags customizadas do JSF usadas para a renderização de conteúdo HTML. No caso, estmaos usando aqui dois componentes: <h:head>, usado para renderizar a tag <head> do HTML e o <h:body>, usado para (adivinha!) renderizar a tag <body> na página.

O que nos interessa aqui é o segundo componente <h:body>. Observe o trecho a seguir:

  <p>Olá #{pessoa.nome}

Este é o momento em que acionamos o que chamamos de Managed Bean. Neste primeiro momento o que você deve saber a seu respeito é que o Managed Bean consiste em uma classe Java padrão, que implementa o padrão Java Beans (https://pt.wikipedia.org/wiki/JavaBeans) e cujo ciclo de vida será gerenciado pelo JSF. Em nosso exemplo a classe representa uma pessoa. E podemos ver sua implementação no código a seguir:

@ManagedBean
public class Pessoa {
    private String nome;

    public String getNome() {
       return this.nome;
    }

    public void setNome(String valor) {
      this.nome = valor;
    }
}

O bloco \#{pessoa.nome} é o que chamamos de EL (Expression Language), e o que ele está fazendo ali é, basicamente, instruindo o JSF a chamar o método getNome() do nosso Managed Bean.

Vemos aqui então a Visualização invocando o Modelo. Obtemos o resultado, este resultado é usado na renderização do componente <h:body> e, na sequência, define o resultado que será retornado ao usuário que iniciou a interação com o servidor.

3 e 4 - Finalização da requisição

Assim que a Visualização termina seu trabalho, ou seja, "se renderiza", o resutlado é retornado ao Frontend Controller que, por sua vez, retorna o conteúdo a quem iniciou a interação com o servidor.

As Leis do MVC se alteram

No caso do JSF as leis do MVC são ligeiramente alteradas.

  • A Visualização sabe qual Modelo chamar.
  • O Modelo continua sem saber quem o chama (e deve continuar assim).

O Modelo, representado pelo Managed Bean, que foi muito mal apresentado até agora a você neste guia, no entanto, é um pouco mais complexo do que você viu aqui. Na realidade, é bem mais complexo. Isto porque nos Managed Beans é que implementamos, além das regras de negócio, também algumas regras de navegação, ou seja, Managed Beans também podem desempenhar o papel de Controladores.

Algumas observações sobre o JSF

Relembrar o modelo MVC e panoramicamente entender como se aplica no caso do JSF é fundamental. Se você deseja realmente evoluir de forma produtiva e segura sistemas baseados em JSF, meu primeiro conselho é: mude sua forma de pensar AGORA. Enquanto estiver lidando com código fonte JSF, esqueça o modelo enviesado do MVC que apresentei, ou seja, aprenda com meu erro.

Observe que há um erro proposital na escrita deste texto. Ao lhe descrever o MVC o fiz pensando em frameworks action based na descrição do seu fluxo. Ao pensarmos neste padrão de projeto o que você deve ter em mente inicialmente não é o fluxo, mas a função.

  • Controlador - orquestra a navegação.
  • Visualização - gera o retorno para o usuário final.
  • Modelo - contempla as regras de negócio e possíveis integrações.

No caso do JSF estes papéis podem se misturar. No momento em que perceber isto, refatore imediatamente suas classes. As organize de tal maneira que fique claro quando um Managed Bean (já vamos ver eles) está interagindo na navegação do usuário e quando está executando funções de negócio. Isto é vital para que você possa sempre retornar código-fonte em um estado superior ao que recebeu.

Lembre-se: evoluir legado = sempre devolver o código-fonte em um estado superior ao que foi recebido.

Um "retorno ao passado"

Ao lidarmos com JSF em alguns aspectos temos a impressão de estarmos voltando no tempo. Você, desenvolvedor Spring ou Grails ou Micronaut ou qualquer outro framework action based atual na JVM irá se deparar com a necessidade de manipular arquivos que talvez sequer saiba que existam, tal como o web.xml, ou mesmo voltar à edição de outros arquivos XML, tal como o faces-config.xml.

É fundamental remover sua resistência a este fato. Você precisará, por exemplo, ter a execução da sua aplicação a partir do Tomcat (tal como vimos na configuração do ambiente de desenvolvimento), algo que não é comum nos dias de hoje (2015 pra frente). Sendo assim saber gerenciar o Tomcat passa a ser importante. Recomendo que seu conhecimento vá além do mero iniciar o servidor: busque entender suas configurações e tudo o que este pode lhe oferecer.

E vou além: pense em outros containers além do Tomcat: neste guia usamos este, mas no dia a dia não é raro, ao lidarmos com sistemas baseados em JSF, precisarmos gerenciar servidores Wildfly, JBoss (antes de virar Wildfly), WebLogic e outros. Dizem que o servidor de aplicações Java é coisa do passado, certo? Diga isto para aqueles que mantém estas bases de código e depois conversamos. :)

Este retorno ao passado na realidade não deve sequer ser visto como um retorno, mas sim como um reconhecimento de uma realidade atual. São práticas e um modelo de desenvolvimento criados na década passada, entretanto ainda atuais e adotados por inúmeras equipes de desenvolvimento no mundo inteiro. Ignorá-los é limitar seu próprio crescimento profissional além da sua própria compreensão de modelos mais recentes de desenvolvimento.

4. Primeiros passos

O objetivo desta seção é ser o mais prática possível. Iremos realizar atividades rápidas que tem como objetivo te tornar minimamente produtivo com o JSF. Não há muita teoria e sugiro que seja lida sequencialmente. Caso não saiba nada sobre o framework, segure sua ansiedade e, por favor, leia os passos apresentados a seguir na sequência, visto que cada passo é a base para o seguinte.

É fundamental também que você não apenas leia, mas também pratique. Caso esteja diante do seu computador, garanta que o ambiente de desenvolvimento do guia esteja já devidamente configurado e, sempre que puder, conforme vai lendo os exemplos, repita-os em seu computador.

Assim você terá neste primeiro momento uma concepção instintiva de como o JSF funciona para que no próximo capítulo possamos nos aprofundar no framework e, mais importante, fornecer as bases para que seja possível uma manutenção efetiva de sistemas legados baseados nesta tecnologia.

4.1 Criação de um novo projeto JSF usando Maven

Geração do código fonte inicial

Para iniciar o projeto rapidamente, será usado o arquétipo (archetype) padrão do Maven para a criação de projetos Java voltados para a web: maven-webapp-archetype.

Para criar um novo projeto, basta executar o comando a seguir:

mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes \
                       -DarchetypeArtifactId=maven-archetype-webapp \
                       -DarchetypeVersion=1.4

Será criado um projeto que já contém inclusive as dependências necessárias para a versão 2.3 do JSF. Você pode comprovar isto abrindo o arquivo pom.xml do projeto e verificando as dependências, tal como exposto a seguir:

<dependency>
	 <groupId>org.glassfish</groupId>
	 <artifactId>javax.faces</artifactId>
	 <version>2.3.0</version>
</dependency>

Se a dependência não for criada, você deve incluí-la.

Caso esteja usando o Eclipse como IDE, não é necessário executar este procedimento por linha de comando. Basta criar um novo projeto baseado em Maven e, no passo em que for selecionar o arquétipo, selecionar o maven-archetype-webapp tal como exposto na imagem a seguir:

Observação: note que no comando Maven acima mencionado é usado um número de versão diferente do arquétipo (1.4) daquele que aparece na janela do Eclipse. Isto pode gerar código diferente do apresentado. Sendo assim verifique se a dependência do JSF foi realmente incluída no novo projeto criado pela IDE.

Arquivos essenciais de configuração

O arquivo web.xml

O arquivo webapp/WEB-INF/web.xml é o descritor web (web descriptor) padrão de uma aplicação Java EE. Nele é que configuramos os servlets do projeto.

No caso de um projeto baseado em JSF, é necessário configurarmos o servlet JSF. Esta é uma configuração simples. Copie o código a seguir para o arquivo web.xml:

<servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>

Esta configuração define os comportamentos essenciais para o funcionamento do JSF:

  • Apresenta o servlet JSF (Faces Servlet), nos dizendo qual o seu nome (Faces Servlet) e a classe que o implementa.
  • Define a ordem de carregamento do servlet (1, a mais baixa no arquivo).
  • Define que qualquer URL que termine em .xhtml será tratada pelo JSF.
As configurações do JSF - faces-config.xml

Crie um arquivo chamado faces-config.xml no diretório webapp/WEB-INF do projeto com o conteúdo a seguir:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.1"
       xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xi="http://www.w3.org/2001/XInclude"
       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_2.xsd">
</faces-config>

Testando o projeto

A melhor maneira de se testar o projeto é criando a nossa primeira página. Crie o arquivo index.xhtml no diretório webapp do projeto com o código fonte a seguir:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>JSF Labs da itexto</title>
</h:head>
<h:body>
   <h1>JSF Labs</h1>
</h:body>
</html>

Logo na sequência, usando sua IDE, execute o projeto no servidor Tomcat. Na imagem a seguir você pode ver o resultado no navegador embarcado do Eclipse:

Código de exemplo

Na pasta src, busque pelo projeto jsflabs-vazio. Ele contém exatamente o código fonte que foi criado neste passo a passo e poderá ser usado em diversos outros pontos do guia para que você realize suas experimentações.

4.2 Melhorando a sua experiência com o Eclipse

É possível melhorar bastante a sua experiência com o Eclipse em projetos JSF. Para tal, vamos simular a criação de um novo projeto. Copie a pasta jsflabs-vazio para um outro local qualquer de sua preferência em seu computador e, na sequência, importe este projeto para o workspace que criamos no Eclipse seguindo os passos a seguir:

  • Vá ao menu "File" e clique sobre a opção "Import…​"
  • Na nova janela que surgir, escolha a opção "Maven" → "Existing Maven Project"
  • Selecione o diretório no qual criou o novo projeto.

Uma vez importado (aguarde a IDE terminar seu trabalho baixando todas as dependências necessárias, assim como as configurações básicas do projeto), clique sobre o projeto na aba "Projects" e, na sequência, sobre a opção "Properties".

Na janela que expõe os detalhes do projeto (vide print a seguir), clique sobre a opção "Project Facets" e marque as seguintes opções:

  • Dynamic Web Project (selecione a última versão disponível (3.1 no momento de escrita deste guia).
  • JavaServer Faces - 2.3 (ou a versão do JSF com que estiver trabalhando, só há vesões a partir da 2.0).

4.3 Navegação essencial - seu primeiro formulário

Vamos iniciar nosso projeto com uma interação bastante simples: um "Olá Mundo" a lá JSF. A aplicação que iremos criar é bastante simples. Nosso usuário ao acessar o projeto irá se deparar com o formulário apresentado na imagem a seguir:

Ao preencher seu nome e clicar sobre o botão "Oi!", verá a página seguinte:

Mão na massa

Primeiro passo - criar o projeto

Você pode criar o projeto tal como mencionamos na seção "Criação de um novo projeto JSF usando Maven" ou simplesmente criar uma cópia do projeto "jsflabs-vazio", presente na pasta src deste guia.

Logo na sequência, importe o projeto para o seu workspace. Recomendamos que execute o procedimento que descrevemos em "Melhorando a sua experiência com o Eclipse".

Criando nosso primeiro formulário

Quando trabalhamos com JSF sempre iremos criar páginas no formato XHTML. Caso nunca tenha visto uma página neste formato, pense nela como um "HTML bem formatado" ou, melhor ainda, como um "HTML formatado com XML".

Isto implica em mudanças bem sutis (talvez nenhuma) no modo como você está acostumado a escrever suas páginas. Na realidade, há uma única mudança: basta escrevê-las como se fossem documentos XML, ou seja, todas as tags deverão ser fechadas. Para que entenda melhor este formato vamos primeiro criar a página index.xhtml do nosso projeto (diretório src/main/webapp), cujo código fonte é apresentado a seguir que iremos dissecar aos poucos:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>JSF Labs da itexto</title>
</h:head>
<h:body>
   <h1>JSF Labs - Olá você!</h1>
   <h:form>
   	Qual o seu nome?
   	<h:inputText id="nome" value="#{nome}" required="true"></h:inputText>
   	<h:commandButton action="ola" value="Oi!"/>
   </h:form>
</h:body>
</html>

Como pode ser visto, é um documento XML padrão, só que com algumas tags HTML. Pra começar, temos a definição do esquema e também dos namespaces que usaremos em nosso documento:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

Observe que definimos um namespace XML (https://www.w3schools.com/xml/xml_namespaces.asp) na tag <html>. Caso o conceito seja novo para você, namespaces são um importante recurso do XML. Servem para que evitemos conflitos de nome. Neste caso, estamos definindo dois:

Observe que no corpo da nossa página existe a tag <h:body>, enquanto no HTML convencional temos uma tag com o mesmo nome (<body>). A inclusão do prefixo h serve para que possamos distinguir uma da outra. Umam dúvida comum neste ponto seria: "minha aplicação vai precisar estar conectada à Internet para funcionar?". Não: estas URLs são usadas apenas para que o framework JSF saiba de onde carregar as definições dos componentes, o que é feito de uma forma completamente offline (ao menos em teoria).

Logo na sequência teremos o corpo da tag <html>, que é composto na realidade por dois componentes JSF:

<h:head>
	<title>JSF Labs da itexto</title>
</h:head>
<h:body>
   <h1>JSF Labs - Olá você!</h1>
   <h:form>
   	Qual o seu nome?
   	<h:inputText id="nome" value="#{nome}" required="true"/>
   	<h:commandButton action="ola" value="Oi!"/>
   </h:form>
</h:body>

O primeiro componente, <h:head> é usado para, como você já devia supor, renderizar o conteúdo da tag <head> do HTML. Na prática, neste exemplo é inclusive desnecessário. Está aqui apenas como exemplo, se tivéssemos digitado apenas a tag padrão <head>, teríamos exatamente o mesmo resultado final.

O segundo componente, <h:body>, este sim, é necessário no caso de uma aplicação JSF. Ele renderiza o conteúdo da tag <body>, entretanto tem uma função adicional aqui: conter um sub-componente extremamente importante, que é o <h:form>, responsável, como já deve imaginar, para se renderizar formulários em JSF, mas também por ser o componente fundamental responsável por qualquer interação gerenciada pelo framework.

No formulário <h:form> você observará a existência de dois outros componentes do JSF: <h:inputText>, usado para a renderização de componentes textuais, e <h:commandButton>, usado para a renderização de botões de submissão, ou seja, inputs do tipo submit do HTML convencional. Ambos os componentes são do tipo de entrada de dados (input) do JSF, e devem ser renderizados sempre dentro da tag <h:form>.

Mas antes, vamos analisar o componente <h:inputText>, cujo código fonte é replicado a seguir:

<h:inputText id="nome" value="#{nome}" required="true"/>

O resultado final da sua renderização será código HTML muito próximo do exposto a seguir:

<input type="text" id="nome" required="true"/>

Os mesmos atributos que usamos no HTML são aplicados em <h:input>, entretanto há uma diferença: observe o que digitamos no atributo value:

value="#{nome}"

O conteúdo entre áspas está em uma linguagem especial, chamada EL (Expression Language). Seu papel consiste em traduzir nosso interesse para os parâmetros que serão trafegados pelo JSF. No caso, estamos dizendo que ao submeter nosso formulário, o que digitarmos no campo nome deverá estar armazenado em uma variável chamada nome.

Logo na sequência, observe como foi definido o segundo componente: <h:commandButton>

<h:commandButton action="ola" value="Oi!"/>

Temos aqui mais um componente JSF: neste caso, a tag <h:commandButton>, tal como mencionado antes, irá renderizar um componente do tipo input, porém do tipo submit, bem similar ao HTML expresso a seguir:

<input type="submit" value="Oi!"/>

O campo action não foi renderizado. O que ele quer dizer neste momento?

Processando nosso formulário

Vamos criar nossa segunda página agora, ela se chama ola.xhtml (na mesma pasta src/main/webapp), e cujo conteúdo é apresentado a seguir:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>JSF Labs da itexto</title>
</h:head>
<h:body>
   <h1>Você por aqui?</h1>
   <p>Olá #{nome}</p>
</h:body>
</html>

Sim: o atributo action de index.xhtml nos diz qual a página que renderizará o conteúdo da variável nome que definimos acima. E o valor da variável é expresso a partir do trecho em EL apresentado em detalhe a seguir:

<p>Olá #{nome}</p>

Nós submetemos o conteúdo em index.xhtml, o JSF o obtem e, na sequência, renderiza no arquivo XHTML que definimos como ação (action) no formulário. Observe que você não precisa colocar a extensão .xhtml. O próprio JSF já sabe que o direcionamento vai para outra página XHTML.

É hora de você executar o código: clique sobre o arquivo index.xhtml com o botão direito do seu mouse e, na sequência, selecione a opção Run As e, na sequência Run on Server. Selecione o Tomcat configurado para seu Workspace e, na sequência, veja a página ser renderizada no navegador embarcado do Eclipse.

Se algo der errado, compare o código que digitou com o que fornecemos com este guia na pasta src/jsflabs-primeira-interacao.

Resumindo

Você viu aqui o fluxo mais simples possível que podemos criar no JSF: um fluxo que não tem nenhum dos tais Managed Beans sobre os quais falamos brevemente agora há pouco.

Também ficou mais claro o que queremos dizer quando usamos o termo componente em JSF: são estas tags, específicas do framework, identificadas por um namespace que, ao serem processadas, geram como resultado código HTML.

Neste momento você também consegue perceber como o padrão MVC, sobre o qual falamos agora há pouco se manifesta aqui. No momento em que um componente é renderizado, este verifica se há parâmetros a serem fornecidos ao modelo (no nosso caso, o modelo é o próprio Frontend Controller do JSF que recebe o parâmetro nome), envia estes parâmetros para processamento, o Frontend Controller analisa quem será a resposta da solicitação e, na sequência, passa os valores para que os mesmos possam ser renderizados como retorno.

Experimente: modifique este código fonte gerado incluindo mais parâmetros: como seria um formulário com nome e sobrenome? Brinque um pouco com este exemplo antes de passarmos para o próximo exemplo no qual, finalmente, teremos nosso primeiro contato com um Managed Bean.

Dica: o código fonte deste primeiro exemplo pode

ser acessado na pasta src/jsflabs-primeira-interacao.

4.4 Seu primeiro Managed Bean

Após termos mencionado esta personagem tantas vezes no texto, chegou o momento de finalmente apresentá-la a vocês. Gostaria muito de dizer que o primeiro managed bean a gente nunca esquece, mas se você leu a introdução deste guia, já sabe que estaria mentindo. Entretanto é um conceito bastante simples, mas que ficará mais claro conforme iniciemos nossa prática.

O que significa ser um Managed Bean?

Antes de começarmos é importante responder a esta pergunta. A começar pela primeira palavra: o que managed (gerenciado) significa? Essencialmente estamos falando de objetos que não são gerenciados pelo programador, mas sim pelo framework.

Mas o que significa ser gerenciado? Significa que o ciclo de vida do objeto (quando é criado e destruído) não é definido pelo programador, mas sim por outra entidade, ou seja, pelo framework. Quando estivermos apresentando aqui os Managed Beans você notará algo interessante: em momento algum você os instanciará, quem fará isto o tempo inteiro será o próprio JSF.

Ok, você agora sabe o que gerenciado significa, mas o que Bean quer dizer? Vêm dos primordios do Java: inicialmente representa uma unidade de código auto contida em uma classe, isto é, uma classe que represente uma funcionalidade.

Posteriormente surgiu o conceito de JavaBean: uma classe Java padrão que segue os seguintes princípios:

  • Tem um construtor padrão.
  • Possui implementados em si métodos get e set (getters e setters) usados para obter e definir o valor de suas propriedades.
  • Implementam a interface java.io.Serializable.

Sendo assim, um Managed Bean seria uma classe que segue o padrão JavaBean e que é gerenciada pelo JSF. Mas mais do que isto, veremos que o estado da aplicação é contido nestes objetos, e que eles irão frazer bem mais do que simplesmente manter este estado. Também irão guiar a navegação em nosso projeto.

Mão na massa - implementando nosso Managed Bean

Este projeto será uma evolução do que vimos na seção Navegação essencial - seu primeiro formulário. Agora nosso formulário é um pouco mais elaborado: nele iremos fornecer nosso nome e sobrenome.

A página inicial será similar à apresentada a seguir:

Preenchendo o formulário, seremos direcionados a uma nova página, em que seremos saudados pelo nosso exemplo:

A página inicial e nosso primeiro Managed Bean

Iremos modificar a página index.xhtml (pasta src/main/webapps) para que fique tal como no exemplo a seguir:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<head>
	<title>JSF Labs da itexto</title>
</head>
<h:body>
   <h1>JSF Labs - Olá você!</h1>
   <h:form>

   	Seu nome: <h:inputText id="nome" value="#{pessoa.nome}" required="true"/><br/>
   	E o sobrenome? <h:inputText id="sobrenome" value="#{pessoa.sobrenome}" required="true"/><br/>
   	<h:commandButton action="ola" value="Entre!"/>
   </h:form>
</h:body>
</html>

Temos exatamente os mesmos componentes que vimos na seção anterior. Entretanto há uma pequena diferença aqui: observe o que digitamos como valor do atributo value nos dois componentes <h:inputText> de nossa página:

Seu nome: <h:inputText id="nome" value="#{pessoa.nome}" required="true"/><br/>
E o sobrenome? <h:inputText id="sobrenome" value="#{pessoa.sobrenome}" required="true"/><br/>

Este pessoa é nosso Managed Bean. Tal como mencionado, é uma classe Java padrão. Nós a criamos no pacote br.com.itexto.jsf e sua implementação pode ser vista no trecho a seguir:

package br.com.itexto.jsf;
import javax.faces.bean.ManagedBean;

@ManagedBean
public class Pessoa {

	private String nome;
	private String sobrenome;

	public Pessoa() {

	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public String getSobrenome() {
		return sobrenome;
	}

	public void setSobrenome(String sobrenome) {
		this.sobrenome = sobrenome;
	}
}

Observe que não foi implementada a interface java.io.Serializable: ela é opcional no caso do JSF, mas todos os outros atributos estão aqui:

  • Getters e setters.
  • Construtor padrão (que é opcional caso a classe não tenha nenhum outro construtor, está aqui apenas para fins didáticos).

A grande diferença está na anotação @ManagedBean, pertencente ao pacote javax.faces.bean, que é usada para identificar esta classe como um Managed Bean. Observe que não é necessária nenhuma configuração adicional: no momento em que a aplicação JSF é iniciada o classpath da aplicação é lido em busca de todas as classes que possuam esta anotação.

A anotação @ManagedBean está marcada como deprecated por que?

Talvez sua IDE marque esta anotação como deprecated. Isto ocorre por que a partir do Java EE 7 recomenda-se o uso do CDI para o gerenciamento de beans, e não amis o JSF puro, tal como estamos fazendo neste guia.

Qual anotação você usa então? @Named.

È importante saber como o JSF trata nossos managed beans. Voltemos à página index.xhtml:

Seu nome: <h:inputText id="nome" value="#{pessoa.nome}" required="true"/><br/>
E o sobrenome? <h:inputText id="sobrenome" value="#{pessoa.sobrenome}" required="true"/><br/>

Ali, aonde estamos definindo o atributo value como sendo #{pessoa.nome} e \#{pessoa.sobrenome}, no momento em que for realizada a submissão do formulário o JSF irá chamar os métodos setNome e setSobrenome com os valores ali digitados. E por que o bean se chama pessoa e não Pessoa? Mera convenção: por padrão o JSF irá identificar nossos Managed Beans como o nome da classe tendo a primeira letra em minúsculo. Então Pessoa vira pessoa e ManagedBean vira mangedBean.

E é possível dar um nome customizado ao meu bean? Claro! Basta usar o atributo name da anotação @ManagedBean, tal como no exemplo a seguir:

@ManagedBean(name="biscoito")
public class Pessoa {
// e assim o bean passou a se chamar biscoito

Agora, vejamos como os dados são recebidos. Para tal, iremos revisitar a nossa página ola.xhtml, cujo código agora é:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>JSF Labs da itexto</title>
</h:head>
<h:body>
   <h1>Você por aqui?</h1>
   <p>Olá #{pessoa.nome} #{pessoa.sobrenome}</p>
</h:body>
</html>

É essencialmente igual à versão anterior. Só que agora ao invés de \#{nome} referenciamos o atributo nome (getNome()) da classe Pessoa. E por padrão, por quanto tempo durará o nosso bean, ou seja, quando a nossa instância será destruída? Após a execução da requisição (por padrão). Como verificar isto? Faça este teste.

O que você vê? Apenas o texto Olá, sem nada depois. O Managed Bean não foi criado por uma requisição anterior.

Resumindo

Vimos aqui a nossa primeira manifestação de um Managed Bean. Neste exemplo este serviu apenas para receber os dados que digitamos em nosso formulário para que possamos renderiza-lo na resposta. Não é um uso muito interessante, mas pelo menos você pode ver como código XHTML referencia um Managed Bean e, ainda mais interessante: também aprendeu a como executar o data binding contra um bean.

Você também aprendeu a implementar uma classe que seja um Managed Bean. Se prestou atenção no texto, viu que a anotçaão @ManagedBean não é mais recomendada, entretanto a usaremos durante a maior parte deste guia, afinal de contas nosso objetivo aqui é tratar apenas do JSF de forma isolada. Posteriormente podemos até mesmo conhecer melhor o CDI (um recurso maravilhoso do Java EE), mas por enquanto seremos como o Model do JSF: teremos um escopo bastante limitado, apenas a renderização de páginas web e nossa navegação entre estas com JSF.

Você pode encontrar o código fonte do nosso exemplo em src/jsflabs-primeiro-bean. Mas recomendo que você primeiro tente melhorar o projeto jsflabs-primeira-interacao para que possa ir experimentando.

4.5 Nosso segundo Managed Bean - navegando

Agora não teremos apenas um managed bean, mas dois! E iremos além: veremos um managed bean que irá também decidir qual a página que deverá ser renderizada no momento em que o formulário for submetido.

Nossa aplicação de exemplo é bastante simples: na realidade, é uma evolução do porjeto jsflabs-primeiro-bean que vimos na seção anterior. Ao acessar a página index.xhtml o usuário verá agora um formulário com três campos, tal como na imagem a seguir:

O usuário digitará o nome e o sobrenome da pessoa, mas tambeḿ marcará (ou não) uma caixa de checagem (checkbox) que instruirá nossa aplicação a respeito do fato daquela pessoa ser bem vinda ou não em nosso ambiente.

Caso a pessoa seja bem-vinda, veremos a seguinte página de resposta:

E se a pessoa não for bem vinda? Bom, então apresentaremos a seguinte página:

Talvez devessemos ser mais simpáticos com o Ruivo Hering. Ok, pediremos desculpas após explicarmos como chegamos a este resutlado final.

Mão na massa - os novos beans e nosso primeiro checkbox

Para começar vamos ver como ficou o código fonte da página index.xhtml:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<head>
	<title>JSF Labs da itexto</title>
</head>
<h:body>
   <h1>JSF Labs - Olá você!</h1>
   <h:form>

   	Seu nome: <h:inputText id="nome" value="#{navegacao.pessoa.nome}" required="true"/><br/>
   	E o sobrenome? <h:inputText id="sobrenome" value="#{navegacao.pessoa.sobrenome}" required="true"/><br/>
   	Bem vindo? <h:selectBooleanCheckbox value="#{navegacao.bemVindo}"/>
   	<h:commandButton action="#{navegacao.escolha}" value="Entre!"/>
   </h:form>
</h:body>
</html>

Não mudou muita coisa: mas podemos observar a presença de um novo componente JSF, o <h:selectBooleanCheckbox>. O nome é muito ruim, mas o usamos para renderizar um checkbox (caixa de seleção) cujo valor seja um atributo booleano. Observe também que agora há um novo bean agora, chamado navegacao. Vamos ver como ele é?

package br.com.itexto.jsf;
import javax.faces.bean.ManagedBean;

@ManagedBean
public class Navegacao {

	private boolean bemVindo;

	private Pessoa pessoa;

	public Navegacao() {
		this.pessoa = new Pessoa();
	}

	public String escolha() {
		return this.bemVindo ? "ola" : "tchau";
	}

	public boolean isBemVindo() {
		return bemVindo;
	}

	public void setBemVindo(boolean bemVindo) {
		this.bemVindo = bemVindo;
	}

	public Pessoa getPessoa() {
		return pessoa;
	}

	public void setPessoa(Pessoa pessoa) {
		this.pessoa = pessoa;
	}
}

Observe que interessante: nós referenciamos aqui a pessoa que está dentro do bean navegação (\#{navegacao.pessoa.nome}, notou?). E também observe que nosso construtor padrão aqui é útil: ele instancia um objeto do tipo Pessoa para evitar um erro do tipo NullPointerException (velho conhecido seu este erro, certo?).

Há também uma pequena mudança na implementação do Bean pessoa. Vamos ver?

package br.com.itexto.jsf;

public class Pessoa {

Removi a anotação @ManagedBean. Por que? Por que neste exemplo ela só faz sentido dentro do bean Navegacao. E também porque quis mostrar a você que os managed beans podem ser mais complexos. Eu poderia muito bem ter incluído um atributo bemVindo em Pessoa, mas aí estaria penas lhe incentivando a seguir más práticas, e um dos objetivos deste guia é ajudar a evoluir sistemas baseados em JSF, certo?

Bem: agora é importante observar um pequeno detalhe na página index.xhtml: observe o que foi incluído no componente <h:commandButton>:

<h:commandButton action="#{navegacao.escolha}" value="Entre!"/>

No caso, observe o valor que digitamos no atributo action. É uma chamada ao método escolha, que definimos no bean Navegacao. Vamos relembrar este trecho?

public String escolha() {
	return this.bemVindo ? "ola" : "tchau";
}

O método retorna uma string, cujo nome correponde a uma das páginas que criamos para o projeto: uam se chama ola.xhtml (você já a conhece) e agora uma nova, chamada tchau.xhtml. De acordo com o estado do atributo bemVindo do bean Navegacao uma ou outra será retornada, guiando assim a navegação do usuário.

Provavelmente você já deve estar imaginando como é o código fonte de ola.xhtml e tchau.xhtml, mas por desencargo de consciência, as incluo aqui. Primeiro, a que você já conhece: ola.xhtml:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>JSF Labs da itexto</title>
</h:head>
<h:body>
   <h1>Você por aqui?</h1>
   <h2>Saiba que te amamos muito!</h2>
   <p>Olá #{navegacao.pessoa.nome} #{navegacao.pessoa.sobrenome}</p>
</h:body>
</html>

E tchau.xhtml não é muito diferente. Vamos a ela:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>JSF Labs da itexto</title>
</h:head>
<h:body>
   <h1>Você por aqui?</h1>
   <h2>Não gostamos de você, saia daqui!</h2>
   <p>Sim, você mesmo #{navegacao.pessoa.nome} #{navegacao.pessoa.sobrenome}</p>
</h:body>
</html>

Resumindo com exercícios

Neste exemplo você pode ver um Managed Bean interferindo diretamente na navegação do usuário. Em sistemas reais é algo muito similar o que ocorre: você verá um método retornando uma string que aponta para a página que será renderizada pelo JSF.

É importante contar que esta não é a única forma de definirmos como será a navegação no sistema. JSF oferece recursos mais avançados para tal (dica: o arquivo faces-config.xml que ainda não tocamos).

Agora é sua vez de experimentar: modifique o código fonte escrito, crie novas páginas, inclua novas condições e métodos que guiem a navegação do usuário. Seguem alguns exercícios:

  • Crie arquivos de páginas em outras pastas que não sejam a raíz de webapp. Como seria a navegação se as páginas de resposta ficassem em webapp/paginas, por exemplo? Experimente.
  • Experimente criar lógicas mais complexas para este formulário: e se houvesse uma terceira opção de redirecionamento baseada no que for digitado. E se houvesse uma página de erro para o qual o usuário seja direcionado caso o nome ou sobrenome não tiver sido fornecido?

4.6 Listas

Até este momento temos conhecimento mínimo a respeito do modo como JSF lida com o data binding. Essencialmente temos em nossos managed beans propriedades únicas tais como vimos nos exemplos até agora: um único indivíduo, com um único nome e sobrenome.

Mas as coisas começam a ficar mais interessantes quando relacionamentos do tipo um-para-muitos começam a surgir. Nos próximos exemplos iremos imaginar como seria a implementação do site de treinamentos da itexto, o Formação itexto.

Neste novo cenário temos um aluno que pode se inscrever em vários cursos, por exemplo. Como lidamos com este tipo de situação? Veremos como lidar com situações nas quais precisamos de caixas de seleção (menus drop down) ou situações nas quais mais de uma opção precisam ser selecionadas. Começaremos com um modelo bastante simples e, posteriormente, lidaremos com situações um pouco mais complexas.

Começando com menus de seleção (drop down menus)

Talvez este nome lhe pareça estranho, mas é algo bastante comum. Vamos ilustrar a situação com o formulário de matricula da Formação itexto apresentado na imagem a seguir:

Na opção Curso há uma série de opções disponível para o aluno. Após selecionar a que mais lhe agrada, este será direcionado para uma página de boas vindas, tal como a exposta a seguir:

O exemplo é bastante simples e para tal iremos criar um novo projeto baseado no anterior que vimos. Começaremos pela implementação do managed bean, que se chamará Aluno e cuja implementação você pode ver a seguir:

package br.com.itexto.jsf;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class Aluno {

	private String nome;

	private String sobrenome;

	private String curso;
	// getters, setters e construtor ocultos
	// para facilitar a leitura do código
}

Observe que não criamos neste momento uma classe para representar os cursos. Ao invés disto estamos usando uma propriedade bem simples do tipo String (melhoraremos muito isto no futuro).

O próximo passo consiste na construção do nosso formulário de matricula, que chamaremos aqui de selecao.xhtml e cuja implementação você pode ver a seguir:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

<head>
	<title>JSF Labs da itexto</title>
</head>
<h:body>
   <h1>Formação itexto - Matricule-se!</h1>
   <h:form>
   	<p>Nome: <h:inputText value="#{aluno.nome}"/></p>
   	<p>Sobrenome: <h:inputText value="#{aluno.sobrenome}"/></p>
   	<p>Curso:
   		<h:selectOneMenu value="#{aluno.curso}">
   			<f:selectItem itemLabel="JSF" itemValue="JSF"/>
   			<f:selectItem itemLabel="Grails" itemValue="Grails"/>
   			<f:selectItem itemLabel="Spring" itemValue="Spring"/>
   			<f:selectItem itemLabel="Node.js" itemValue="Node.js"/>
   		</h:selectOneMenu>
   	</p>
   	<h:commandButton value="Inscrever" action="selecao-resposta"/>
   </h:form>
</h:body>
</html>

Há novidades interessantes neste trecho. Comecemos pelo novo namespace, f:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

Observe que estamos referenciando outro conjunto de componentes do JSF, o Core. Falaremos mais a respeito dos conjuntos de componentes padrão do JSF mais à frente. Neste momento o que você deve levar em consideração é qual componente estamos usando a partir do namespace f: <f:selectItem>. Observe o trecho a seguir:

<h:selectOneMenu value="#{aluno.curso}">
	<f:selectItem itemLabel="JSF" itemValue="JSF"/>
	<f:selectItem itemLabel="Grails" itemValue="Grails"/>
	<f:selectItem itemLabel="Spring" itemValue="Spring"/>
	<f:selectItem itemLabel="Node.js" itemValue="Node.js"/>
</h:selectOneMenu>

Dois novos componentes nos são apresentados: o primeiro é <h:selectOneMenu>, usado para renderizar uma caixa de seleção. Sozinho este não será muito útil, é necessário que lhe digamos quais opções deverão ser apresentadas. Entra então em cena o segundo componente (e o primeiro que veremos do namespace Core do JSF: <f:selectItem>.

Esta nossa listagem de opções é fixa (péssimo para a esmagadora maioria dos casos), mas serve para ilustrar o uso de <f:selectItem>, que será usado para renderizar o elemento <option> do HTML padrão. Observe os nomes dos parâmetros: itemLabel diz respeito ao texto que é apresentado ao usuário final, enquanto itemValue o valor que será submetido pelo formulário.

Em um cenário mais próximo da realidade teríamos uma base de dados na qual existiria uma tabela contendo ao menos dois atributos: um identificador e um texto representando o nome do curso. Sendo assim, neste cenário mais próximo da realidade poderíamos ter código similar ao apresentado a seguir:

<h:selectOneMenu value="#{aluno.curso}">
	<!-- Observe os identificadores no atributo itemValue -->
	<f:selectItem itemLabel="JSF" itemValue="1"/>
	<f:selectItem itemLabel="Grails" itemValue="2"/>
	<f:selectItem itemLabel="Spring" itemValue="3"/>
	<f:selectItem itemLabel="Node.js" itemValue="4"/>
</h:selectOneMenu>

Sendo realizada a submissão do formulário, o atributo curso do bean Aluno será preenchido e o código a seguir, da página selecao-resposta.xhtml será renderizado:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">

<head>
	<title>JSF Labs da itexto</title>
</head>
<h:body>
   <h1>Formação itexto - Matricule-se!</h1>
   	<p>Olá #{aluno.nome} #{aluno.sobrenome}!</p>
   	<p>Bem vindo ao curso de #{aluno.curso}</p>
</h:body>
</html>

Agora vamos melhorar um pouco mais este exemplo.

Adicionando dinamismo aos menus de seleção

E se quiséssemos obter a lista de opções de cursos a partir de um banco de dados, como deveríamos proceder? Foge ao escopo deste guia mostrar como gerenciar conexões JDBC ou com bases relacionais. Entretanto, podemos simular uma base de dados com a inclusão de um novo bean, que chamaremos aqui de CursosDAO e cuja implementação pode ser vista a seguir:

package br.com.itexto.jsf;

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

import javax.faces.bean.ManagedBean;

@ManagedBean
public class CursosDAO {

	private List<Curso> cursos;

	public CursosDAO() {
		/*
			Os dados poderíam muito bem
			vir de um banco de dados, mas apenas
			para fins didáticos, são definidos no
			próprio construtor
		*/
		this.cursos = new ArrayList<Curso>();
		this.cursos.add(new Curso(1, "JSF"));
		this.cursos.add(new Curso(2, "Grails"));
		this.cursos.add(new Curso(3, "Spring"));
		this.cursos.add(new Curso(4, "Node.js"));
	}

	public List<Curso> getCursos() {
		return this.cursos;
	}
}

Notou que temos um atributo do tipo List<Curso>? A classe Curso foi implementada por nós, é bastante simples e você pode ver o código a seguir:

package br.com.itexto.jsf;

public class Curso {

	private int id;

	private String nome;

	public Curso() {}

	// um construtor adicional apenas para
	// que digitemos menos código :)
	public Curso(int id, String nome) {
		this.id = id;
		this.nome = nome;
	}
	// ocultando getters e setters
}

Nossa página selecao.xhtml precisa sofrer apenas uma pequena modificação para obter a lista de cursos dinâmicamente. Vamos ver?

<h:form>
   	<p>Nome: <h:inputText value="#{aluno.nome}"/></p>
   	<p>Sobrenome: <h:inputText value="#{aluno.sobrenome}"/></p>
   	<p>Curso:
   		<h:selectOneMenu value="#{aluno.curso}">
   			<f:selectItems value="#{cursosDAO.cursos}" itemLabel="#{curso.nome}" itemValue="#{curso.id}" var="curso"/>
   		</h:selectOneMenu>
   	</p>
   	<h:commandButton value="Inscrever" action="selecao-resposta"/>
</h:form>

A diferença está no conteúdo da tag <h:selectOneMenu>. Entra um novo componente em ação, <f:selectItems>, responsável pro renderizar uma lista de objetos do tipo <f:selectItem> com base nos parâmetros passados. Vejamos quais são estes parâmetros:

  • value - irá apontar para a lista sobre a qual iremos iterar. No caso, o resultado da chamada ao método getCursos do managed bean CursosDAO.
  • var - qual o nome da variável sobre a qual o loop irá realizar suas iterações. É essencial, e seu uso ficará claro nos dois parâmetros expostos a seguir.
  • itemLabel - qual a expressão que resultará no texto apresentado ao usuário final. Observe que a expressão aponta para a variável curso, criada em var.
  • itemValue - similar a itemLabel. A diferença é que aqui a expressão denotará qual o valor do atributo value que será renderizado.

Não é necessária qualquer alteração na página de resposta (select-response.xhtml).

Seleção múltipla com checkbox

Agora vamos melhorar um pouco mais nosso formulário. E se ao invés do aluno escolher apenas um curso, ele pudesse escolher mais que um? O aluno acessaria uma página tal como a apresentada na imagem a seguir, em que forneceria seu nome, sobrenome e selecionaria quais os cursos de seu interesse:

E após ter se inscrito, receberia uma resposta tal como a apresnetada a seguir na página select-multiplo-response.xhtml:

O primeiro passo consistirá na criação de um novo managed bean para representar esta nova situação. O chamaremos de AlunoMultiplo, e sua implementação pode ser vista a seguir:

package br.com.itexto.jsf;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class AlunoMultiplo {

	private String nome;

	private String sobrenome;

	String[] cursos;
	// getters e setters gerados, porém
	// removidos desta listagem
}

Observe que temos agora um array do tipo String para representar os cursos selecionados para o aluno. Para ilustrar este conceito, iremos criar uma nova página, chamada selecao-multipla.xhtml e cujo código fonte você vê a seguir:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

<head>
	<title>JSF Labs da itexto</title>
</head>
<h:body>
   <h1>Formação itexto - Matricule-se!</h1>
   <h:form>
    <h2>Seleção dinâmica</h2>
   	<p>Nome: <h:inputText value="#{alunoMultiplo.nome}"/></p>
   	<p>Sobrenome: <h:inputText value="#{alunoMultiplo.sobrenome}"/></p>
   	<p>Cursos:
   		<h:selectManyCheckbox value="#{alunoMultiplo.cursos}">
   			<f:selectItems value="#{cursosDAO.cursos}" itemLabel="#{curso.nome}" itemValue="#{curso.nome}" var="curso"/>
   		</h:selectManyCheckbox>
   	</p>
   	<h:commandButton value="Inscrever" action="selecao-multipla-resposta"/>
   </h:form>
</h:body>
</html>
package br.com.itexto.jsf;


import javax.faces.bean.ManagedBean;


@ManagedBean
public class AlunoMultiplo {



private String nome;




private String sobrenome;




	String[] cursos;
	// getters e setters gerados, porém
	// removidos desta listagem
}

Observe que não há muitas mudanças em relação ao código anterior. As diferenças realmente interessantes estão contidas neste trecho:

<h:selectManyCheckbox value="#{alunoMultiplo.cursos}">
   			<f:selectItems value="#{cursosDAO.cursos}" itemLabel="#{curso.nome}" itemValue="#{curso.nome}" var="curso"/>
	</h:selectManyCheckbox>

Um novo componente surge: <h:selectManyCheckbox>, que é usado para renderizar uma lista de caixas de seleção (checkbox) que irão representar quais os cursos que o aluno quer se matricular. Observe outro detalhe bastante sutil: os atributos itemLabel e itemValue do componente <f:selectItems> possuem a mesma expressão: curso.nome. Isto se deve ao fato do managed bean AlunoMultiplo ter os cursos represnetados como uma matriz de objetos do tipo Stirng, e não Curso.

Ao submetermos o formulário seremos direcionados para a página selecao-multipla-resposta.xhtml, que foi o conteúdo que definimos para o atributo action do commandButton deste formulário. Há novidades interessantes aqui: veja a listagem a seguir:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">

<head>
	<title>JSF Labs da itexto</title>
</head>
<h:body>
   <h1>Formação itexto - Matricule-se!</h1>
   	<p>Olá #{alunoMultiplo.nome} #{alunoMultiplo.sobrenome}!</p>
   	<p>Você se inscreveu nestes cursos:</p>
   	<ul>
   		<ui:repeat var="curso" value="#{alunoMultiplo.cursos}">
   			<li>#{curso}</li>
   		</ui:repeat>
   	</ul>

</h:body>
</html>

A primeira novidade diz respeito a mais um conjunto de componentes representado pelo namespace ui (URL http://java.sun.com/jsf/facelets), os componentes Facelets. O que nos interessa neste momento é o componente <ui:repeat> que serve essencialmente para introduzirmos um loop na renderização da nossa página. Observe os parâmetros que passamos para este componente:

  • value - aponta para a lista sobre a qual iremos iterar. No caso, para o método getCursos do mangaed bean AlunoMultiplo.
  • var - o nome da variável sobre a qual iremos iterar.

A cada iteração do loop o conteúdo da tag <ui:repeat> será renderizado. No nosso caso, expondo a lista de cursos selecionados no formulário anterior à renderização da página selecao-multipla-resposta.xhtml.

Quem são os Facelets?

Facelets foi uma tecnologia que surgiu no JSF 1.1/1.2 e que forneceu a base para o JSF 2.0. Basicamente, a tecnologia foi apresentada nestes releases inclusive para que pudéssemos realizar a migração para a versão 2.0 do JSF que estava por vir.

Dentre as novidades estava a possibilidade se criarmos templates que nos possibilitaríam manter a identidade visual dos nossos projetos dentre outros recursos. Falaremos mais sobre os Facelets mais à frente neste guia.

Resumindo

Nesta rápida seção vimos como lidar com listas no JSF de uma forma bastante rudimentar, quando precisamos lidar apenas com atributos de nossos managed beans qeu sejam do tipo textual. A realidade, no entanto, é mais complexa: queremos que a partir de um identificador um objeto completo nos seja retornado, não apenas um dos seus atributos.

O código fonte deste capítulo pode ser encontrado no projeto jsflabs-bean-listas, mas não podemos deixar este capítulo sem alguns exercícios.

  • Vimos que o managed bean AlunoMultiplo tem um atributo do tipo matriz. E se fosse um atributo do tipo List<String>, o que ocorreria? Experimente!
  • Modifique o managed bean CursosDAO para que gere aleatóriamente uma lista de cursos.

4.7 Conversores

No último exemplo vimos como usar listas na modelagem de nossos managed beans. Não sei em relação a você, mas quando me lembro do código fonte que escrevi para a classe Aluno sinto arrepios:

package br.com.itexto.jsf;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class Aluno {

	private String nome;

	private String sobrenome;

	private String curso; // sério?

	// getters e setters omitidos
}

Há algo de muito errado aqui: pra começar, se o Aluno está relacionado a um curso, este não deveria ter um atributo do tipo Curso ao invés de uma string? Será que no JSF não há como implementar o relacionamento entre objetos usando algo como um identificador ou algo assim? Afinal de contas, quando pensamos na modelagem que vimos até agora, o natural seria algo como o diagrama a seguir, certo?

Isto por que não raro (99% dos casos) ao desenvolvermos nossos sistemas pensamos no relacionamento entre entidades. Pensando em uma base de dados relacional, teríamos ali ao menos duas tabelas neste exemplo: uma para representar o Aluno outra para o Curso, sendo que na primeira tabela existiria um campo que referenciaria o identificador da segunda (as famigeradas chaves estrangeiras), certo?

Sendo assim podemos pensar em um algoritmo bem rápido para fazer este relacionamento de acordo com a modelagem original:

  • Selecionamos o curso para o usuário, que no caso é representado pelo seu nome.
  • Após ter sido feita a seleção, buscamos no banco de dados o curso cujo nome foi aquele fornecido.
  • E aí teríamos uma classe de domínio na qual realizaremos este relacionamento.

Mas e se houvessem dois cursos com o mesmo nome, porém com versões diferentes, qual deles selecionaríamos? Como pode ver não há como fugir dos identificadores aqui, e este é o meu gancho para que possa lhe apresentar o conceito de Conversor (Converters) do JSF.

Uma nova modelagem

Vamos modificar as classes Aluno e Curso para que fiquem tal como na listagem a seguir em que apresentamos as classes Aluno e Curso.

package br.com.itexto.jsf;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class Aluno {

	private String nome;

	private String sobrenome;

    private Curso curso; (1)
	// getters e setters suprimidos
}

public class Curso {
	private long id; (2)

	private String nome;

	// getters e setters suprimidos
}

1 Bem mais natural e o correto: você está referenciando a abstração Curso, não um dos seus atributos.

2 Por trás dos panos faremos com que nosso código de forma transparente referencie, na realidade, este id.

Observe que só incluimos a anotação @ManagedBean em Aluno, pois ele sim é nosso managed bean, e não Curso, que apenas representa a nossa informação. A propósito, precisamos obter uma lista de cursos de algum lugar. Criaremos portanto um DAO para que possamos obter a lista de cursos que serão apresentados em nosso exemplo. Vamos a ele?

package br.com.itexto.jsf;

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

import javax.faces.bean.ManagedBean;

@ManagedBean (1)
public class CursosDAO {

	private List<Curso> cursos;

	public CursosDAO() { (2)
		this.cursos = new ArrayList<Curso>();
		this.cursos.add(new Curso(1, "JSF"));
		this.cursos.add(new Curso(2, "Grails"));
		this.cursos.add(new Curso(3, "Spring"));
		this.cursos.add(new Curso(4, "Node.js"));
	}

	public Curso findById(int id) { (3)
		Curso resultado = null;
		for (Curso curso : this.cursos) {
			if (curso.getId() == id) {
				resultado = curso;
				break;
			}
		}
		return resultado;
	}

	public List<Curso> getCursos() {
		return this.cursos;
	}

}

1 Notou que temos aqui um Managed Bean? Atenção para este detalhe, pois será mencionado adiante.

2 No construtor padrão iremos alimentar a lista interna de cursos para simular um banco de dados.

3 Usado para que possmaos buscar um curso a partir do seu identificador. Usaremos mais tarde este recurso neste capítulo.

O que é um DAO?

DAO (Data Access Object) é um padrão de projeto bastante popular que tem como principal objetivo centralizar todo o código fonte responsável por interagir com uma base de dados.

O que realmente interessa em um DAO é sua interface. Em nosso exemplo, esta é composta por dois métodos:

  • getCursos() - que retorna a lista de todos os cursos cadastrados.
  • findById(int id) - que nos retornará o curso tendo como base o seu identificador.

A razão pela qual o foco está na interface é o desacoplamento. Em nosso exemplo inicial estamos usando uma base de dados inteiramente armazenada e criada em memória. Futuramente, se quisermos usar um SGBD real, como o MySQL ou PostgreSQL, basta mudar nossa implementação para que todas as classes cliente sejam automaticamente atualizadas sem qualquer necessidade de reescrita ou intervenção manual do desenvolvedor.

Nossa "nova" nova aplicação

É importante que nos relembremos da aplicação que iremos criar. Para o usuário final esta será composta por apenas duas páginas. Na primeira iremos realizar a matricula do aluno, tal como pode ser visto na imagem a seguir:

Será apresentada uma caixa de seleção na qual irão ser expostos os cursos que serão disponibilizados pelo nosso DAO. Selecionando todos os campos, seremos direcionados para a próxima página, na qual iremos saudar o usuário:

Basicamente um exemplo bastante banal em que simplesmente iremos direcionar o usuário para uma outra página e nesta apresentar os dados que foram fornecidos no formulário anterior. Entretanto nos fornece o essencial para que possamos lhe apresentar, ao final da demonstração, como funcionam os conversores do JSF.

Nossas páginas

Vamos começar pela página selecao.xhtml. Ela é bastante similar à apresentada em nosso exemplo anterior (4.6), mas com algumas mudanças sutis.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

<head>
	<title>JSF Labs da itexto</title>
</head>
<h:body>
   <h:form>
    <h2>Inscreva-se</h2>
   	<p>Nome: <h:inputText value="#{aluno.nome}"/></p>
   	<p>Sobrenome: <h:inputText value="#{aluno.sobrenome}"/></p>
   	<p>Curso:
   		<h:selectOneMenu value="#{aluno.curso}"> (1)
   			<f:selectItems
               value="#{cursosDAO.cursos}" (2)
               itemLabel="#{curso.nome}"
               itemValue="#{curso}" (3)
               var="curso"/>

   		</h:selectOneMenu>
   	</p>
   	<h:commandButton value="Inscrever" action="selecao-resposta"/>
   </h:form>
</h:body>
</html>

1 Observe que estamos referenciando aqui o atributo curso, do tipo Curso em Aluno e não mais uma string.

2 Nosso Managed Bean CursosDAO entra em ação nos fornecendo a lista de cursos cadastrados em nosso banco de dados em memória (e imaginário).

3 Fundamental - note que itemValue agora referencia o objeto completo curso definido pelo atributo var e não apenas o nome do curso.

É imporante lembrar aqui como era a mesma página tal como a apresentamos na seção 4.6. Observe a diferença na tag f:selectItems:

<f:selectItems
    value="#{cursosDAO.cursos}"
    itemLabel="#{curso.nome}"
    itemValue="#{curso.nome}" (1)
    var="curso"/>

1 Atenção para este ponto: referenciamos um atributo do curso, não o curso em si.

A tag <f:selectItems> itera sobre um conjunto de itens (e isto é válido para outras tags também, tal como a <core:for> que veremos adiante), entretanto, apesar do nosso HTML final a ser renderizado pelo JSF não ter acesso direto a todos os atributos dos objetos gerenciados pelo lado servidor, isto não quer dizer que você, do lado servidor, precise referenciar apenas seus atributos e não o objeto como um todo.

Após a apresentação destas pequenas diferenças, vamos à página para a qual nosso usuário é direcionado após preencher o formulário, que é a selecao-resposta.xhtml:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">

<head>
	<title>JSF Labs da itexto</title>
</head>
<h:body>
   <h1>Formação itexto - Bom ter você aqui!</h1>
   	<p>Olá #{aluno.nome} #{aluno.sobrenome}!</p>
   	<p>Bem vindo ao curso de #{aluno.curso.nome}</p> (1)
</h:body>
</html>

1 A única mudança: referenciamos o atributo nome, do atributo curso do managed bean aluno.

Como pode ver a única mudança diz respeito a que atributos referenciamos em nossa página. O atributo nome do atributo curso de aluno. Apenas por curiosidade, vamos ver como seria renderizada a página se mudassemos este trecho marcado pelo a seguir?

<p>Bem vindo ao curso de #{aluno.curso}</p> (1)

Olha que interessante, o JSF irá renderizar o objeto curso associado ao nosso managed bean aluno. Como a nossa classe Curso usando a função toString(), padrão do Java para tal. Como não a sobrescrevemos na classe Curso, será chamada a implementação padrão que retorna um texto que é o nome completo da classe seguido do seu endereço na memória.

Funções toString, equals, hashCode

Toda classe no Java é uma sub-classe de java.lang.Object, que é a responsável por conter todos os comportamentos mais essenciais que qualquer objeto gerenciado pela linguagem deve seguir.

Há algumas funções contidas em java.lang.Object que você, iniciante no Java, deve conhecer e, sempre que possível, sobrescrever em suas classes.

  • String toString() - retorna uma representação textual do seu objeto.
  • boolean equals(Object o) - retorna verdadeiro caso seu objeto seja semânticamente igual ao passado como parâmetro.
  • int hashCode() - que retorna um valor inteiro que identifica únicamente seu objeto quando armazenado em uma estrutura do tipo HashMap.

No contexto deste capítulo o que realmente nos interessa é a função toString, pois é usada para gerar uma representação textual dos nossos objetos nas páginas XHTML que escrevemos.

Agora que você viu como o objeto é renderizado em sua forma bruta, a grande questão que fica é: como estamos tranformando estes textos/identificadores em objetos do tipo Curso?

Finalmente, os conversores

Para entendermos como os conversores funcionam é importante que nos aprofundemos primeiro no funcionamento do próprio protocolo HTTP. Apesar dos frameworks servirem para que este seja abstraído não há como fugir de uma rápida descrição do seu funcionamento para que possamos entender como os conversores operam.

Essencialmente o protocolo HTTP trafega apenas texto. Ele não conhece tipos diferentes de dados tais como valores numéricos, booleanos e muito menos objetos complexos compostos por inúmeros atributos. Entretanto em nossos formulários o tempo inteiro passamos informações que não são puramente textuais, tal como no que apresentamos neste exemplo, em que estamos selecionando objetos.

Este processo de transformar os valores que digitamos em nossos formulários nos tipos que realmente representam e, na sequência, fornecê-los a nossos controladores (managed beans) é o que chamamos de data binding.

O data binding pode ser implementado das mais variadas formas de acordo com o framework que esteja usando em seu desenvolvimento e, na realidade, sempre estará presente no desenvolvimento de aplicações web (mesmo caso você seja um destes lobos solitários que optou por criar o próprio framework e trilhar um caminho de intensa dor e aflição).

No caso do JSF o data bindin é implementado usando o conceito de Converters (conversores). Por padrão o framework já trás pré-implementados diversos conversores para os tipos fundamentais e mais comuns: valores booleanos, datas, números inteiros ou de ponto flutuante, etc. A lista completa dos conversores padrão fornecidos pelo JSF pode ser vista neste link: https://docs.oracle.com/javaee/7/tutorial/jsf-page-core001.htm#BNAST

Sempre que em seu managed bean referenciamos um atributo na página XHTML que aponta para uma propriedade de um destes tipos, um destes conversores será chamado. Entretanto, observe que eles apontam apenas para os tipos primitivos do Java (com exceção do BigDecimal e datas) e não para os objetos do seu sistema. Nâo há como a Oracle e os responsáveis pelo desenvolvimento do framework saberem que um dia eu estaria escrevendo a classe br.com.itexto.jsf.Curso.

Não fique triste, o JSF é bastante extensível e uma das extensões que usaremos é a implementação do nosso próprio conversor, algo que faremos agora.

Nosso primeiro conversor

Implementar um conversor é muito simples. Basta que você crie uma classe que implemente a interface javax.faces.convert.FacesConverter e, para torna-la imediatamente disponível ao seu sistema, aplique a anotação @FacesConverter. Quer ver a nossa implementação do conversor para a classe Curso?

package br.com.itexto.jsf;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

@FacesConverter(forClass=Curso.class) (1)
public class ConversorCurso implements Converter  { (2)

	private final CursosDAO dao = new CursosDAO(); (3)

    @Override
	public String getAsString(FacesContext context,
                              UIComponent component,
                              Object value) {
		if (value instanceof Curso) {
			return Integer.toString(((Curso) value).getId());
		}
		return null;
	}

	@Override
	public Object getAsObject(FacesContext context,
                              UIComponent component,
                              String value) {
		try {
			Integer id = Integer.parseInt(value);
			return dao.findById(id);
		} catch (NumberFormatException t) {
			// ocorreu algum erro durante a conversao
			return null;
		}
	}

}

1 A anotação instrui o JSF a, sempre que o processo de data binding estiver lidando com um objeto que seja do tipo Curso a usar o nosso conversor.

2 Esta é a interface que define o contrato que deve ser seguido pelo nosso conversor.

3 Como obtemos uma instância do nosso DAO responsável por obter a lista de cursos e também nos retornar um curso específico com base no seu identificador.

Primeiro vamos observar os métodos que somos obrigados a escrever a partir do momento em que implementamos a interface javax.faces.convert.Converter: a partir deles fica claro o funcionamento deste recurso.

Vamos começar pela função getAsString que recebe três parâmetros: FacesContext, UIComponent e value, do tipo java.lang.Object. Neste momento, apenas para este capítulo até este ponto, ignore os dois primeiros parâmetros, nós os veremos com um detalhamento bem maior mais a frente neste guia.

Esta função deve ser lida assim: dado o objeto que lhe passei como valor, qual seria a melhor forma de representá-lo como uma string?. Nosso papel aqui será fornecer esta representação, no caso, como sendo o "id" do objeto Curso fornecido como parâmetro.

Como sei que um objeto do tipo Curso está sendo fornecido como valor?

Você informou o JSF a respeito no momento em que incluiu a anotação @FacesConverter, lembra?

@FacesConverter(forClass=Curso.class)
public class ConversorCurso implements Converter {

Isto não quer dizer que você não receberá um valor nulo como valor, leve isto em consideração, afinal de contas o tipo selecionado pelo JSF será aquele definido no seu managed bean.

Este retorno no formato textual é muito importante. Lembra de como escrevemos o nosso formulário? Voltemos ao trecho que nos interessa:

<h:selectOneMenu value="#{aluno.curso}">
   	<f:selectItems
       value="#{cursosDAO.cursos}"
       itemLabel={curso.nome}"
       itemValue="#{curso}" var="curso"/>
</h:selectOneMenu>

O componente <f:selectItems> deverá renderizar no navegador do usuário tags do tipo <option> para que sejam compreensíveis. Como seria este HTML gerado?

<select name="j_idt3:j_idt9" size="1">	<option value="1">JSF</option>
	<option value="2">Grails</option>
	<option value="3">Spring</option>
	<option value="4">Node.js</option>
</select>

O valor fornecido ao atributo value nada mais é que o retorno da função getAsString do nosso conversor, por que ao passarmos o valor \#{curso} ao componente <f:selectItems>, por baixo dos panos é verificado o tipo daquela variável (Curso) e, na sequência, realiza-se a seleção do conversor apropriado (ConversorCurso).

Agora que estamos com 50% do caminho andado, vamos entender o funcionamento da segunda função implementada pelo nosso conversor: getAsObject:

@Override
	public Object getAsObject(FacesContext context,
                              UIComponent component,
                               String value) {
	try {
		Integer id = Integer.parseInt(value);
		return dao.findById(id);
	} catch (NumberFormatException t) {
		// ocorreu algum erro durante a conversao
		return null;
	}
}

Temos aqui o caminho contrário e você deve interpretá-la como: no atributo do managed bean que irei popular identifiquei o tipo Curso, converta o texto que recebi para o objeto apropriado.

Visto que nós mesmos implementamos este conversor, sabemos que iremos receber ali um texto que representa um identificador. Nosso trabalho será apenas convertê-lo para o tipo correto e, na sequência, retornar o registro relacionado usando nosso DAO.

Voilá, temos o fluxo completo de conversão agora:

  • getAsString - é usado na renderização das nossas páginas XHTML para representar instâncias de objetos do tipo Curso.
  • getAsObject - é usado no momento de submissão dos nossos formulários. O JSF identifica que está lidando com o data binding de um atributo do tipo Curso, recebe o valor textual via HTTP e, na sequência, o converte para o tipo apropriado.

Alguns exercícios

O código fonte deste exemplo está presente na pasta jsflabs-bean-conversores. Use-o para os exercícios aqui propostos ou, melhor ainda, implemente seu próprio conversor para que possa ter uma experiência mais rica.

  • Reescreva o exemplo de seleção múltipla que vimos na seção 4.6 usando o seu conversor.
  • Modifique o modo como a representação textual do curso é retornada e interpretada pelo conversor. Que tal se ao invés de simplesmente termos o id retornado, tenhamos um padrão, tal como curso-[id] (curso-1, curso-2, curso-3). Como você faria esta implementação?

Resumindo

Apesar deste capítulo ser de atividades práticas não houve como fugir aqui de um aprofundamento do conceito de conversores e mesmo do protocolo HTTP. Saiba que aqui tratamos apenas do mais básico quando falamos de conversores.

Há mais pontos importantes a serem levados em consideração aqui: você futuramente precisará lidar com conversores para datas (algo extremamente comum) no futuro. Nossa sugestão: pesquise sobre o DateTimeConverter fornecido pelo JSF.

Dica de leitura

No blog da AlgaWorks existe um texto excelente sobre este assunto. Segue o link: https://blog.algaworks.com/conversores-jsf/

4.8 Injeção de dependências no JSF e escopos

Assim como o exemplo que acabamos de desenvolver na seção 4.7 era uma evolução daquele que criamos na 4.6, aqui entrará em ação mais uma evolução. No caso, o ponto de desconforto pode ser visto no código fonte do nosso conversor, mais especificamente nestas linhas:

@FacesConverter(forClass=Curso.class)
public class ConversorCurso implements Converter {

	private final CursosDAO dao = new CursosDAO(); (1)
1 Mas CursosDAO não é um managed bean?

Voltemos ao conceito de managed bean: é um objeto cujo ciclo de vida é inteiramente gerenciado pelo framework, não pelo programador, ou seja, nós não deveríamos estar instanciando manualmente objetos do tipo CursosDAO.

E indo um pouco além, vamos apenas imaginar neste momento que CursosDAO acesse um banco de dados real. Há uma série de pontos a serem levados em consideração:

  • Provavelmente é usado um pool de conexões, que é um objeto caro de ser construído.
  • Talvez estejamos usando JPA, e o EntityManagerFactory é também bastante caro de ser construído.
  • A cada instanciação estamos criando um novo pool de conexões ou um EntityManagerFactory?
  • Quantas vezes o nosso DAO está sendo instanciado? Há realmente a necessidade de criarmos uma instância do DAO a todo momento?
  • Será que ter um monte de instâncias do CursosDAO em memória ao mesmo tempo é um bom negócio?

Aproveitamos então este exemplo para introduzir além do modo como as dependências são injetadas em nossos managed beans pelo JSF também o conceito de escopos, que ditam quanto tempo um bean tem de vida.

Mas e o CDI?

Até este ponto você deve ignorar completamente o CDI, que é uma solução muito mais robusta e sofisticada para gerenciarmos a inversão de controle e injeção de dependências no Java EE.

Nosso objetivo até agora é o de compreender o JSF isoladamente para que, mais à frente, quando tratarmos o CDI, a integração entre os dois se torne bem mais fácil de ser compreendida por você.

Sendo assim neste capítulo teremos uma visão mais "raíz" (e eu diria até mesmo que tosca) para, mais tarde, entendermos o real valor do CDI ao adotarmos uma abordagem bem mais eficiente e recomendada.

O que é injeção de dependências e inversão de controle?

Foge do escopo deste guia detalhar estes conceitos, mas você pode aprender bastante a respeito lendo o nosso guia Injeção de Dependências com Spring Framework 3 que pode ser baixado gratuitamente neste link: https://www.itexto.com.br/guias/?guia=injecao-de-dependencias-com-spring-framework-3

O guia é sobre Spring, mas o que falamos sobre injeção de dependências e inversão de controle neste texto se aplica a qualquer situação independente da tecnologia.

Tá com preguiça de acessar o link? Ok, incluí um Apêndice neste guia só sobre este assunto.

Injetando dependências em Managed Beans - @ManagedProperty

Na aplicação que desenvolvemos no exemplo anterior (4.6) listavamos os cursos usando um managed bean dedicado a interagir com o banco de dados, nosso DAO CursosDAO. No formulário de matricula este era usado tal como apresentado no detalhe a seguir:

<h:selectOneMenu value="#{aluno.curso}">
   	<f:selectItems
       value="#{cursosDAO.cursos}"  (1)
       itemLabel="#{curso.nome}"
       itemValue="#{curso}" var="curso"/>
</h:selectOneMenu>
1 A aplicação do managed bean CursosDAO

Para ilustrar a injeção de dependências vamos simplificar o nosso modelo. Ao invés da página acima acessar dois managed beans (Aluno e CursosDAO), ela irá acessar um único: Aluno.

Tudo o que precisamos fazer é mudar o código fonte desta classe para que fique tal como no exemplo a seguir:

package br.com.itexto.jsf;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty; (1)

@ManagedBean
public class Aluno {

	private String nome;

	private String sobrenome;

	private Curso curso;

	@ManagedProperty("#{cursosDAO}") (2)
	private CursosDAO cursosDAO;

    // getters e setters omitidos

}
1 Referência à anotação ManagedProperty no pacote javax.faces.bean.
2 Aplicação da anotação. Atenção especial para o valor passado como parâmetro.

Ao aplicarmos a anotação sobre as propriedades que referenciam outros beans, antes do managed bean ser disponibilizado à nossa página (ou a outros beans) a dependência será resolvida, isto é, o próprio JSF se preocupará em instanciar o objeto, resolver suas dependências e, na sequência, injetá-lo neste ponto.

Atenção especial ao valor que passamos para a anotação @ManagedProperty: é uma expressão EL, na qual incluimos o nome do bean que desejamos injetar, isto é, uma instância de cursosDAO.

Nota: tenha também implementado um método setter para a dependência. Dependendo da versão do JSF este pode ser um requisito obrigatório.

Por que @ManagedProperty está marcada como deprecated no Eclipse?

A partir do JSF 2.3, tal como ocorre com a anotação @ManagedBean, a especificação padrão do JavaEE recomenda o uso do CDI para gerenciar a injeção de dependências e inversão de controle.

Neste guia até este momento não estamos trabalhando com CDI. Vai funcionar na versão 8 do JEE, mas não há garantias de que funcione no futuro.

Atualizado nosso bean Aluno basta modificar o código fonte da página para que fique tal como no exemplo a seguir:

<h:selectOneMenu value="#{aluno.curso}">
   	<f:selectItems
       value="#{aluno.cursosDAO.cursos}"  (1)
       itemLabel="#{curso.nome}"
       itemValue="#{curso}" var="curso"/>
</h:selectOneMenu>

1 A mudança: referenciamos agora o atributo cursosDAO de usuario e não mais o managed bean cursosDAO diretamente.

Injeção de dependências no conversor e introdução ao FacesContext

Não sei se você se lembra, mas na implementação dos nossos conversores precisamos implementar a interface javax.faces.convert.Converter que possui a interface apresentada a seguir:

package javax.faces.convert;

public interface Converter<T> {
    public T getAsObject(FacesContext context,
                         UIComponent component,
                         String value);

    public String getAsString(FacesContext context,
                              UIComponent component,
                              T value);
}

Tá vendo o primeiro atributo, FacesContext? Vamos vê-lo agora. E lembra quando disse que neste capítulo disse que teríamos apenas uma visão superficial do JSF? Pois é, eu menti.

A classe FacesContext é usada para nos fornecer todo o estado de uma requisição que encontre-se em processamento pelo JSF em um dado momento. E por todo o estado, temos aqui não apenas os parâmetros que foram passados, mas também quais managed beans são usados.

E vamos inclusive um pouco além, na realidade podemos inclusive pedir instâncias de managed beans com ele.

Lembra do Spring?

Se já tiver trabalhado com Spring Framework, pense no FacesContext como o container de inversão de controle e injeção de dependências do Spring (o ApplicationContext).

Por "pedir instâncias" ao contexto JSF você deve entender que estamos solicitando o retorno de beans já existentes ou que o próprio JSF instancie estes beans e, na sequência, já lhes injete todas as dependências necessárias para o seu funcionamento.

Infelizmente não é possível injetar managed beans diretamente em conversores (até a versão 2.3 do JSF), sendo assim faremos uso de uma "estratégia técnica" (aka gambiarra) que nos pemitirá obter um bean do tipo CursosDAO totalmente gerenciado pelo JSF.

Vejamos como nossa estratégia técnica foi implementada na classe ConversorCurso cujos termos realmente interessantes são expostos a seguir:

package br.com.itexto.jsf;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

@FacesConverter(forClass=Curso.class)
public class ConversorCurso implements Converter {

private CursosDAO getDAO(FacesContext context) { (1)
	try {
		return (CursosDAO) context.getApplication()
                            .evaluateExpressionGet(
                                context,
                                "#{cursosDAO}",
                                CursosDAO.class);
	} catch (Throwable t) {
		return null;
	}
}

	@Override
	public Object getAsObject(FacesContext context,
                              UIComponent component,
                              String value) {
		try {

			Integer id = Integer.parseInt(value);
			return getDAO(context).findById(id); (2)
		} catch (NumberFormatException t) {
			// ocorreu algum erro durante a conversao
			return null;
		}
	}
    // restante do código omitido
}
1 Nossa estratégia técnica em ação.
2 Agora sim usando um managed bean verdadeiramente gerenciado.

O método que realmente nos interessa neste primeiro ponto é getDAO. Observe que ele recebe como parâmetro um objeto do tipo FacesContext, valor este que nosso conversor recebe naturalmente a partir do JSF quando a função getAsObject é invocada pelo framework.

O contexto JSF realmente nos fornece acesso a todas as informações de tempo de execução do projeto. Dentre elas o executor de expressões (EL) do JSF, o que nos permite fornecer expressões e obter o resultado de sua execução. É exatamente isto o que fizemos na função getDAO, tal como pode ser verificado no detalhe a seguir explicado em seus mínimos detalhes:

return (CursosDAO) context.getApplication() (1)
                            .evaluateExpressionGet( (2)
                                context,
                                "#{cursosDAO}", (3)
                                CursosDAO.class); (4)
1 getApplication() nos retorna um objeto do tipo javax.faces.application.Application, um singleton que contém informações globais do projeto em execução, inclusive o interpretador de expressões (EL) do JSF.
2 evaluateExpressionGet - a função recebe três parâmetros: o primeiro deles é a instância do FacesContext que recebemos (feio, né? Avisei que era uma estratégia técnica!).
3 A expressão que queremos executar. O JSF irá verificar se existe uma instância pronta para uso do bean CursosDAO: existindo, nos retornará este objeto. Caso contrário, o instanciará, injetará neste todas as suas dependências e tornará o objeto pronto para uso.
4 O tipo de resultado que esperamos obter da execução, no caso, um objeto do tipo CursosDAO.

Resumindo: demos um uso alterantivo ao interpretador de EL do JSF. Ao invés deste ser usado em páginas XHTML, tal como vimos até agora, o usamos como motor para a instanciação de beans.

A vantagem desta abordagem é que temos um bean totalmente gerenciado, isto é, o JSF irá executar as seguintes tarefas para nós:

  • Buscará todas as dependências necessárias para a execução do bean, as preparará e, na sequência, injetará no bean para que este esteja pronto para ser usado.
  • O próprio JSF saberá quando o managed bean deve ser destruído, não mais o desenvolvedor. Resumindo: você não precisa mais se preocupar com o ciclo de vida deste objeto.

Atenção para as dependências

Até este momento no guia a única dependência incluida foi o próprio JSF. Indiretamente, entretanto, é necessário a inclusão de mais uma dependência para que possamos acessar o interpretador de EL do framework. Inclua-a na seção <dependencies> do arquivo pom.xml tal como apresentado a seguir:

<dependency>
    <groupId>javaee</groupId>
	<artifactId>javaee-api</artifactId>
	<version>5</version>
</dependency>
Exercício

Como você escreveria uma função que retornasse não apenas o bean CursosDAO, mas sim qualquer outro bean gerenciado pelo JSF usando como base o código que aplicamos em nosso conversor?

Entendendo os escopos

A primeira parte do problema já foi resolvida: sabemos como injetar dependências em nossos managed beans. Agora entra o final: quanto tempo um bean vive e, ainda mais importante, quem tem acesso a uma instância específica de um bean gerenciado?

Ao usarmos o termo escopo duas perguntas são respondidas:

  • Quanto tempo o bean deverá existir?
  • Quem tem acesso ao bean.

No final das contas ficará nítido qual o problema que realmente precisamos resolver: concorrência.

Antes de iniciarmos a nossa apresentação dos escopos é fundamental ter em mente o conceito de estado. Quando alguém diz algo como o estado de um bean esta pessoa está se referindo ao valor armazenado nas variáveis internas deste objeto.

Vejamos o managed bean Aluno, ele tem três atributos tal como pode ser visto na listagem a seguir: nome, sobrenome e curso.

class Aluno {
    private String nome;
    private String sobrenome;
    private Curso curso;
}

E este estado diz respeito ao valor de uma instância deste objeto. Quando submetemos nosso formulário de matricula o que estamos de fato realizando é a definição do estado interno deste managed bean.

Os escopos do JSF
Por requisição - @RequestScoped

De acordo com este escopo o bean será criado a cada requisição que realizemos à nossa aplicação.

Lembra quando mencionei que o real problema resolvido por escopos é o da concorrência? No caso do JavaEE temos um modelo no qual para cada requisição abre-se uma thread que será a responsável pelo processamento da mesma.

Toda aplicação web é, em sua essência, uma aplicação concorrente, isto é, que irá atender múltiplos usuários simultâneamente. De acordo com este escopo o bean nascerá durante a requisição e será destruído durante sua finalização. Suas informações estarão visíveis apenas à thread responsável por realizar seu processamento.

Este é o escopo padrão de todo managed bean do JSF, não sendo portanto necesário que você realize qualquer mudança no nosso código fonte. Mas caso queira deixar o escopo explícito (o que muitos consideram uma boa prática) basta anotar a classe do seu managed bean tal como no exemplo a seguir:

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped; (1)

@RequestScoped (2)
@ManagedBean
public class Aluno {
  // conteúdo da classe omitido
}
1 Qual classe importar.
2 Aplicação do escopo.

Quanto tempo vive o bean? Uma requisição.

Quem tem acesso ao bean? Apenas a thread responsável por processar sua requisição.

Por sessão do usuário - @SessionScoped

No caso de aplicações JSF este é um dos escopos mais populares e também mais perigosos. Quando um bean é anotado com esta requisição, este será criado e destruído junto com a sessão do usuário.

Seu caso de uso mais comum é o do carrinho de compras em sites de eCommerce, no qual o usuário vai inserindo os produtos que deseja comprar e, ao final, realiza o checkout pagando pelos mesmos.

Outro caso de uso bastante comum ocorre quando precisamos construir interfaces do tipo wizard, nas quais guiamos o usuário por uma sequência de passos para que atinja seu objetivo ao final.

Resumindo: você irá usar este escopo quando quiser manter um estado que é necessário para todas as futuras requisições de um usuário específico enquanto sua sessão for mantida no servidor.

A seguir podemos ver como aplicar este escopo em um managed bean fictício:

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped; (1)

@SessionScoped (2)
@ManagedBean
public class Aluno {
  // conteúdo da classe omitido
}
1 Qual classe importar.
2 Aplicação do escopo.

Quanto tempo vive o bean? Enquanto a sessão do usuário existir.

Quem tem acesso ao bean? O usuário da sessão e todas as requisições realizadas dentro desta sessão.

Por aplicação - @ApplicationScoped

Provavelmente o mais perigoso dos escopos, pois uma vez aplicado a um managed bean implicará que uma única instância deste será compartilhada por todos os usuários da aplicação.

Se é um escopo tão perigoso, então por que não é considerado uma má prática? Por que você precisará dele, e muito.

Usamos este tipo de escopo quando há a necessidade real de termos uma única instância do bean compartilhada por toda a aplicação. Alguns exemplos foram dados no início desta seção, mas vale à pena relembrar:

  • Quando lidamos com a criação de objetos muito caros, tais como pool de conexões, instâncias de objetos caríssimos de serem construídos a cada requisição como o EntityManagerFactory do JPA.
  • Para reduzirmos o consumo de memória no caso de managed beans que não possuam estado compartilhado.

O exemplo mais óbvio é o da gestão de objetos caros de serem instanciados. Imagine que o nosso bean CursosDAO não tenha todo o banco de dados em memória, mas sim seja também o responsável por gerenciar o pool de conexões da aplicação.

Se seu escopo for do tipo @RequestScoped, a cada requisição o pool será iniciado e, consequentemente, o tempo de resposta do usuário final será ordens de magnitude maior que o necessário.

Outro exemplo: podemos ter managed beans que sirvam apenas para conter algoritmos e não disponibilizem um estado compartilhado. Pra quê ficar criando novas instâncias a cada requisição se a mesma pode ser usada de forma concorrente por todos os nossos usuários?

Há também casos nos quais o bean possui um estado interno, mas este é necessário para fins de otimização (pool de conexões é um bom exemplo). É interessante que este estado (não compartilhado) seja mantido por todas as requisições.

Usaremos a aplicação de exemplo desta seção para ilustrar o uso do escopo de aplicação. Veja como é feito seu uso na listagem a seguir:

package br.com.itexto.jsf;

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

import javax.faces.bean.ApplicationScoped; (1)
import javax.faces.bean.ManagedBean;

@ApplicationScoped (2)
@ManagedBean
public class CursosDAO {

	private List<Curso> cursos;
1 Qual classe importar.
2 Aplicação do escopo.

Quanto tempo vive o bean? Enquanto a aplicação estiver em execução.

Quem tem acesso ao bean? Todas as requisições do sistema e portanto usuários.

E ainda mais escopos

Os três escopos mais usados em aplicações JSF são estes que foram apresentados, entretanto há outros:

  • @ViewScoped
  • @CustomScoped
  • @NoneScoped

Veremos o @ViewScoped mais à frente neste guia quando nos aprofundarmos no JSF, entretanto fica como exercício para você descobrir o que os outros dois significam.

Exercício

Você foi chamado para dar manutenção em um sistema de eCommerce de uma empresa que está começando a escalar seu número de compradores.

Os investidores desta empresa te telefonaram às 2 da manhã e relataram a seguinte situação:

Uma senhora comprou uma Biblia e recebeu um vibrador na entrega, já outra comprou um vibrador e recebeu exatamente o que havia pedido.

Esta consumidora está muito nervosa e está nos processando por causa do constrangimento, dado que abriu o embrulho em seu encontro dominical na igreja que frequenta!

É uma aplicação baseada em JSF. O que você acha que ocorreu? #paz

5. Os segundos passos

O capítulo anterior serviu para que você pudesse experimentar o JSF: nele vimos como os managed beans funcionam em sua essência. Alguns conceitos já devem estar pelo menos começando a ficar mais claros em sua mente e o funcionamento do JSF encontra-se instintivamente em sua memória. Mas havia uma limitação naquele texto: tínhamos apenas exemplos que, apesar de conectados, eram desconectados de casos de uso real.

Agora a história muda de figura: usando aquilo que aprendemos no capítulo anterior vamos começar o desenvolvimento de uma aplicação real, o ERP da itexto, totalmente voltado ao nosso cadastro de cursos.

Resolveremos agora problemas mais práticos:

  • Como criar uma identidade visual compartilhada por todas as nossas páginas usando Facelets.
  • Veremos também uma organização de Managed Beans melhor, que facilite a manutenção de sistemas no futuro.
  • Entenderemos como funciona o mecanismo de validação de formulários do JSF.
  • Renderização condicional: controlaremos aquilo que pode ou não ser renderizado no cliente de acordo com o fato deste estar autenticado ou não.
  • E por falar em autenticação, vamos implementar um mecanismo de autenticação/autorização bastante rudimentar, mas que nos ajudará a nos aprofundarmos um pouco mais no framework.

5.1 O projeto deste capítulo

O projeto deste capítulo iniciará de uma forma muito simples. Nosso ERP será composto por essencialmente uma página de cadastro de cursos (incluindo listagem, edição, criação e remoção de registros), uma página inicial e um formulário de autenticação.

No primeiro acesso do usuário ao sistema este irá se deparar com nossa página de autenticação na qual deverá fornecer seu login e senha:

Fornecendo as credenciais corretas, nosso usuário será direcionado para a página inicial, a partir da qual poderá escolher uma das opções disponibilizadas no menu lateral:

Caso clique sobre o link Cursos, será direcionado para a página de listagem, na qual poderá ver os cursos já cadastrados e, na sequência, editar, criar ou remover cursos que estejam em nossa base de dados fictícia:

O formulário de criação de cursos e edição é essencialmente o mesmo, tal como pode ser visto na imagem a seguir, em que estamos exemplificando a edição de um registro:

Naturalmente, você deve ter observado o link Sair, que aparece em quase todas as páginas apresentadas. Quando o usuário clicar sobre este link, iremos invalidar sua sessão e direcioná-lo para a página de login.

A aplicação é mais complexa que todos os exemplos que vimos até então neste guia, o que quer dizer que iremos nos aprofundar bastante no JSF neste capítulo. Tá pronto?

5.2 Identidade visual com Facelets

Você deve ter notado na seção anterior que a qualidade gráfica do nosso projeto está anos luz à frente da que vimos no capítulo 4 (Primeiros passos com JSF). Também deve ter observado que a identidade visual se mantém essencialmente a mesma em todas as páginas, tal como pode ser visto no esquema a seguir:

Essencialmente os mesmos elementos se apresentam em todas as páginas:

  • Um menu de navegação é exposto do lado esquerdo, apresentando todas as opções que iremos expor ao usuário estando ele autenticado ou não.
  • E do lado direito temos o conteúdo variável, ou seja, a parte do sistema que irá mudar de acordo com a página que acessamos em nosso sistema.

Um programador ingênuo poderia pensar em simplesmente copiar o código do menu em todas as páginas para que tenhamos este visual uniforme (ou mesmo criar seu próprio componente, tal como poderemos ver mais à frente neste guia), entretanto esta não é uma boa ideia. Basta se imaginar tendo de alterar todas as páginas caso precise trocar algo no menu de navegação.

Uma solução bem mais interessante é a aplicação de Facelets: esta tecnologia JSF que nos permite reaproveitar layouts de forma extremamente simples, reduzindo significativamente a quantidade de código que precisamos digitar não apenas no template, mas sim em todas as páginas.

Veremos o essencial dos Facelets nesta seção.

Conceitos fundamentais

O template

O conceito fundamental por trás dos Facelets é o de template. Pense nele como aquilo que se mantém comum em diferentes páginas do nosso sistema.

Em nosso projeto o template se encontra na pasta src/main/webapp/templates/template.xhtml. É nele que incluímos uma série de informações que irão se repetir em todas as páginas:

  • Os menus de navegação.
  • Quais os arquivos CSS e JavaScript essenciais que serão compartilhados por todas as páginas (estamos usando o Material Design Lite como base, https://getmdl.io).
  • O layout essencial das páginas (menu à esquerda, conteudo à direita).

A seguir você pode ver a versão simplificada deste código fonte, que foi reduzida para que pudesse ser melhor exposta neste texto:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ui="http://java.sun.com/jsf/facelets" (1)
	xmlns:f="http://java.sun.com/jsf/core">
<h:head>
	<link rel="stylesheet" (2)
		href="https://fonts.googleapis.com/icon?family=Material+Icons" />
	<link rel="stylesheet"
		href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css" />
	<script defer="true" src="https://code.getmdl.io/1.3.0/material.min.js"></script>

	<title><ui:insert name="titulo">ERP da itexto</ui:insert></title> (3)
</h:head>
<h:body>

	<div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer">
		<div class="mdl-layout__drawer">
			<span class="mdl-layout-title">Nosso ERP</span>
			<nav class="mdl-navigation">
				<h:form rendered="#{authController.usuarioCorrente != null}"> (4)
					<h:commandLink action="/home">Home</h:commandLink>
					<h:commandLink action="/curso/index">Cursos</h:commandLink>
					<hr />
					<h:commandLink action="#{authController.logout()}">Sair</h:commandLink>
				</h:form>
			</nav>
		</div>
		<main class="mdl-layout__content">
		<div class="page-content" style="padding-left: 2.0em;">

			<ui:insert name="conteudo"> (5)

			</ui:insert>

		</div>
		</main>
	</div>

</h:body>
</html>
1 Atenção para o novo namespace: esta URL nos fornece acesso a todos os componentes Facelets que precisaremos para trabalhar.
2 Carregamos na tag <head> os recursos CSS e JavaScript que o Material Design Lite irá precisar na definição dos estilos aplicados em nossos componentes.
3 Atenção para esta tag Facelet: <ui:insert>. Observe que estamos incluindo aqui inclusive conteúdo padrão caso nada seja fornecido: o texto ERP da itexto.
4 A definição do nosso menu lateral (ignore neste momento o atributo rendered: voltaremos a ele mais tarde quando você aprender a lidar com renderização condicional (é bem fácil e só de ter batido o olho neste exemplo talvez já tenha aprendido).
5 O ponto no qual iremos incluir conteúdo em nosso template.

No código fonte do nosso template você deve ter observado a presença da tag <ui:insert>. Ela serve como um ponto de preenchimento do nosso template. Esta tag essencialmente nos diz: aqui estará incluído conteúdo no futuro.

Antes de expor a aplicação de conteúdo a estes pontos de preenchimento, seria legal se você se lembrasse daqueles jogos de encaixe que você tinha quando era criança. Lembra? Não? Então a imagem a seguir talvez refresque a sua memória.

Você tem essencialmente uma moldura sobre a qual encaixa peças geométricas nos espaços que possuem a mesma forma e tamanho disponibilizados sobre esta. Em nosso template há apenas dois locais de encaixe, que chamamos, apenas por conveniência, de titulo e conteudo, e que podem ser vistos rápidamente na listagem a seguir:

<title><ui:insert name="titulo">ERP da itexto</ui:insert></title>
...
<ui:insert name="conteudo">

</ui:insert>

Observe a primeira aplicação: está dentro da tag <title> que usamos no HTML para representar o título das nossas páginas. Observe que há um conteúdo no interior de <ui:insert> também: o texto "ERP da itexto". Se não fornecermos nada, este será o título das nossas páginas.

Agora observe a segunda aplicação: não há nada ali para ser exposto caso nenhum conteúdo seja fornecido, ou seja, a página final será renderizada, caso nada seja fornecido, apenas uma área vazia.

O cliente do template

Para que a aplicação dos template se torne clara, veja como fica a renderização da nossa página inicial após termos nos autenticado:

Você vê claramente os dois componentes essenciais do template sendo renderizados: menu lateral e conteúdo customizado. Esta página é o que chamamos de cliente do template, ou seja, aquela que o usará para que possamos aplicar a identidade visual essencial do nosso projeto.

A melhor forma de entender como é implementado um cliente é ler o código fonte do arquivo home.xhtml do nosso projeto:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets" (1)
	xmlns:f="http://java.sun.com/jsf/core">


<ui:composition template="/templates/template.xhtml"> (2)
	<ui:define name="titulo">Home</ui:define> (3)

	<ui:define name="conteudo"> (4)
		<h1>ERP da itexto</h1>
	</ui:define>
</ui:composition>

</html>
1 O namespace ui usado para que possamos aplicar os componentes Facelets.
2 O componente <ui:composition> é usado para que possamos dizer qual template será usado em nossa página.
3 O preenchimento da primeira ára titulo com o texto que será apresentado no título da página.
4 O conteúdo HTML que será apresentado como conteúdo corrente das páginas navegadas.

No cliente o elemento essencial é o compnente <ui:composition>. Este é o ponto a partir do qual informamos qual template deverá ser aplicado em nossa página.

Dentro da tag <ui:composition> iremos inserir apenas tags do tipo <ui:define>, que são as responsáveis por definir (trocadilho irresistível) o conteúdo que será renderizado em cada um dos pontos de preenchimento do template.

Observe o parâmetro template de <ui:composition>: é fornecido como valor o caminho absoluto do arquivo de template: /templates/template.xml. Adote sempre esta prática em seus projetos, ou seja, nas páginas que irão adotar um template, sempre coloque o caminho absoluto que leva aos templates, pois isto lhe possibilitará ter maior liberdade na organização de diretórios que será adotada para organizar as páginas XHTML em seu projeto.

Preste atenção também no conteúdo que inserimos nas tags <ui:define>: tanto faz se você irá inserir apenas texto, como na primeira aplicação, quanto outras tags, tal como fizemos no segundo caso. O fundamental é que sempre tenhamos ao final um documento que seja um arquivo XML válido, pois estamos lidando aqui com XHTML.

Talvez a melhor parte você ainda não tenha notado: não precisamos incluir as tags <head> ou <body> em nossa página cliente. Este conteúdo já foi definido no template, ou seja, você enquanto programador precisará digitar muito menos código, o que é ótimo!

Exercício

Modifique o código fonte do projeto que acompanha este capítulo para que seja incluído um terceiro ponto de preenchimento, sendo este o responsável pelo rodapé das páginas.

Modifique seu código fonte para que o preenchimento deste terceiro ponto de preenchimento seja opcional pelos clientes.

5.3 Validações

Se existe uma coisa para a qual JSF é uma tecnologia realmente muito boa é a construção de formulários, especialmente formulários mais complexos. Não é por acaso que é uma solução extremamente popular no ambiente corporativo.

Nesta seção entenderemos como são realizadas as validações usando JSF. Vamos começar com um exemplo bastante simples: a nossa página de login e, na sequência, partiremos para exemplos bem mais complexos, implementando o nosso próprio validador.

Antes, porém, uma pergunta deve ser levantada: o que entendemos por validação? Parece óbvio, mas não é. Validar implica em verificar se o conteúdo que fornecemos em nossos formulários é ou não válido. Esta validação pode se dar essencialmente de duas formas:

  • Estritamente formal - validamos se campos obrigatórios foram preenchidos, se o tamanho máximo do texto foi respeitado, se é um valor numérico, etc.
  • Semântico - uma validação semântica vai além: levamos em consideração o significado do que foi preenchido em nossos formulários. Varia de acordo com o caso, mas um exemplo muito comum é o de unicidade: imagine o cadastro de usuários, por exemplo, não deveríam existir dois registros de usuários com mesmo e-mail.

Mais do que a mera validação de valores fornecidos, a validação também deve ser vista como uma ferramenta que nos permite obter duas vantagens interessantes: aumentar a segurança de nossos sistemas e também seu desempenho.

Primeiro vamos pensar em segurança: talvez você já tenha ouvido falar de falhas de segurança como SQL Injection (https://pt.wikipedia.org/wiki/Inje%C3%A7%C3%A3o_de_SQL) ou comportamentos inesperados de sistemas com base em entradas equivocadas. Tal como Michael Howard e David LeBlanc muito em expõe em seu livro Escrevendo Código Seguro, "toda entrada é maliciosa".

Você, enquanto responsável pelo desenvolvimento dos seus sistemas deve pensar a segurança não como um recurso a ser inserido posteriormente, mas sim como uma funcionalidade pulverizada por todo o seu trabalho, o que inclui a validação obrigatória de todos os seus formulários. A primeira linha de defesa, aliás, é esta: a validação das entradas.

Em segundo lugar devemos pensar em desempenho, mas como uma consequência direta da segurança. Normalmente os formulários são a porta de entrada para processamento que pode ser pesado. Imagine a execução de rotinas complexas todas as vezes em que um formulário for submetido: há processamento desnecessário ocorrendo aqui se as entradas são inválidas. E a validação formal, bastante barata do ponto de vista computacional, pode também ser pensada como uma estratégia de otimização.

5.3.1 Validações formais

O formulário de autenticação do nosso ERP é um bom ponto de partida para as validações mais simples providas pelo JSF. Começaremos pelo nosso formulário de autenticação do ERP, no qual veremos como aplicar as seguintes validações:

  • Campos de preenchimento obrigatório.
  • Tamanho do texto digitado.
  • Checagem de padrões usando expressões regulares.
5.3.1.1 Preenchimento obrigatório

Se o usuário irá se autenticar no sistema, é essencial que tanto o login quanto a senha nos sejam fornecidas no formulário de autenticação. Se este não for o caso, uma resposta visual similar à apresentada a seguir deverá ser apresentada ao usuário.

Não fique triste com a pobre apresentação das nossas mensagens de validação, iremos melhorar isto adiante. Neste primeiro momento você deve se preocupar apenas como aplicamos este tipo de validação. Na realidade é bastante simples, preste atenção no código fonte do nosso formulário.

<h:form>
	<h2>Identifique-se!</h2>
	<h:panelGrid columns="2">
		<h:outputText value="Login"/>
		<h:inputText
			 required="true"  (1)
			 requiredMessage="O campo login é obrigatório" (2)
			 name="login"
			 styleClass="mdl-textfield__input"
			 value="#{authController.credenciais.login}"/>

		<h:outputText value="Senha"/>
		<h:inputSecret
			required="true"
			requiredMessage="Autenticação sem senha? Duvido." (3)
			name="senha" styleClass="mdl-textfield__input"
			value="#{authController.credenciais.senha}"/>

		<h:commandButton
			value="Entrar"
			action="#{authController.autenticar()}"/>
	</h:panelGrid>

			<h:messages /> (4)
		</h:form>
1 O atributo required é que nos informa que um campo tem seu preenchimento obrigatório quando fornecemos o valor true.
2 O atributo requiredMessage nos permite customizar a mensagem de erro ao ser apresentada ao usuário quando o campo não for preenchido.
3 Quem disse que mensagens de validação precisam ser chatas? :)
4 E o componente <h:messages/> nos permite renderizar todas as mensagens de erro que foram encontradas no momento em que erros de validação foram encontrados.

Percebeu que lindo? Nâo foi preciso escrever uma linha sequer de código Java para que esta validação fosse realizada. Temos um formulário padrão aqui, sem novidade alguma, é inclusive um formulário um pouco chato se você prestar atenção.

5.3.1.2 Tamanho do texto digitado

Você também vai querer validar o tamanho daquilo que é digitado por nossos usuários. Sei que não é uma boa ideia termos limitação do tamanho daquilo que é digitado em formulários de autenticação, mas se for para fins estritamente didáticos, por que não?

Imagine que o campo login possa ter no máximo 16 caracteres. Como você faria? Exatamente como deveria proceder se estivesse trabalhando com campos de entrada HTML padrão, ou seja, usando o atributo maxlength, tal como no exemplo a seguir:

<h:inputText
	required="true"
	maxlength="16" (1)
	 requiredMessage="O campo login é obrigatório"
	 name="login"
	 value="#{authController.credenciais.login}"/>
1 O mesmo atributo maxlength que você provavelmente já conhecia no HTML.

Sim, é simples assim: não há uma mensagem customizada para este caso. O usuário simplesmente não irá conseguir digitar um texto maior que 16 caracteres no campo login do nosso formulário.

Mas esta solução é simples demais. E se quisermos definir um tamanho mínimo para um campo. Digamos que seja de nosso interesse termos um login com no mínimo 8 caracteres. Como você faria? Entra em ação as tags de validação do JSF, a primeira que veremos é <f:validateMessage/>. Veja como aplicá-la no exemplo a seguir:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:facelets="http://xmlns.jcp.org/jsf/facelets"
	xmlns:f="http://java.sun.com/jsf/core"> (1)

<!-- Vamos direto ao trecho que interessa? -->
<h:inputText required="true"
	requiredMessage="O campo login é obrigatório"
	name="login"
	maxlength="16"
	styleClass="mdl-textfield__input"
	validatorMessage="O login deve ter no mínimo 8 caracteres"  (2)
	value="#{authController.credenciais.login}">
	<f:validateLength minimum="8" maximum="16" /> (3)
</h:inputText>
1 Atenção para o namespace que iremos importar em noss apágina, os componentes Core do JSF.
2 A mensagem de validação customizada que iremos incluir na validação do nosso campo.
3 A tag <f:validateLength> em toda a sua glória. Você só precisa conhecer estes dois parâmetros: minimum e maximum que, respectivamente, definem o número mínimo e máximo de caracteres que um campo do tipo texto deve possuir.

Observe que <f:validateLength> só faz sentido quando precisamos definir o tamanho máximo de um campo ou se desejamos expor uma mensagem de validação caso o usuário venha a submeter o formulário. Caso apenas o tamanho máximo a ser apresentado deva ser validado, a primeria opção - o uso do atributo maxlength - é a alternativa recomendada, por que evita a submissão do formulário e ainda por cima é um padrão HTML.

5.3.1.3 Expressões regulares

Também é possível validar nossas entradas aplicando expressões regulares. Vamos complicar um pouco mais nosso exemplo: imagine que agora também desejamos que o login do usuário siga um padrão e este seja o de que o texto digitado sempre seja um e-mail da itexto.

Se o usuário nos fornecer um login como kicolobo, figurinha, juca@terra.com.br não devemos aceitar. Será aceito apenas o login que bata com o seguinte padrão: .*@itexto.com.br, ou seja, kico@itexto.com.br, bolinha@itexto.com.br e juc@itexto.com.br serão tidos como logins válidos.

Se o usuário nos fornecer um valor diferente a seguinte mensagem será apresentada:

O que é uma expressão regular?

É algo que você, enquanto pessoa desenvolvedora de software, obrigatóriamente deve ter em sua caixa de ferramentas. Expressões regulares nos permitem verificar se o texto bate com um determinado padrão e também extrair conteúdo textual.

Foge do escopo deste livro lhe explicar tudo sobre expressões regulares, no entanto posso lhe dar ao menos alguns caminhos para que, caso ainda não conheça esta ferramenta, possa ao menos dar seus primerios passos.

Se quiser se aprofundar, recomendo a leitura do livro Mastering Regular Expressions, de Jefrrey Friedl, publicado pela editora O’Reilly. É o melhor livro que conheço sobre o assunto.

Agora, se quiser só ter uma noção do que as expressões regulares podem fazer, recomendo a leitura do texto sobre expressões regulares (em português!) que você pode ler na MDN: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Regular_Expressions

Mais uma tag de validação entra em ação: <f:validateRegex> e você pode vê-la em ação no trecho a seguir:

<h:inputText required="true"
	requiredMessage="O campo login é obrigatório"
	name="login"
	maxlength="64"
	styleClass="mdl-textfield__input"
	validatorMessage="O login deve ter no mínimo 8 caracteres e o padrão .*@itexto.com.br"  (1)
	value="#{authController.credenciais.login}">
		<f:validateLength minimum="8" maximum="64" /> (2)
		<f:validateRegex pattern=".*@itexto.com.br"/> (3)
</h:inputText>
1 A mensagem de erro a ser apresentada ao usuário.
2 A tag <f:validateLength> que você já conhece.
3 A tag <f:validateRegex> que você está conhecendo agora.

Observe que <f:validateRegex> recebe apenas um atributo, pattern, que usamos para digitar nossa expressão regular. Note também a evolução do campo login, cujo tamanho foi aumentado agora para 64 caracteres.

Outro ponto importantíssimo a ser observado: não há como, de forma simples, termos uma mensagem de validação para erros de validação de tamanho e outra para expressões regulares. Sendo assim precisamos incluir no atributo validatorMessage do nosso componente textual uma mensagem que possa ser aplicada a todos os casos de validação para os quais as tags de valiação possam ser aplicadas.

Note também que você pode ter quantas tags de validação quiser no interior de <h:inputText> (e qualquer outro componente de entrada do JSF), o que nos permite excelente flexibilidade na definição de validações.

5.3.1.4 Intervalos numéricos

Nem todo input é textual, você também tem situações nas quais precisará lidar com campos do tipo numérico (com e sem ponto flutuante). É interessante portanto mencionar aqui duas tags que também são bastante úteis para validar intervalor numéricos.

Você usará duas tags de validação: <f:validateLongRange> e <f:validateDoubleRange> usadas, respectivamente, para verificar intervalos numéricos para valores inteiros ou com pontos flutuantes.

Nos dois casos há os mesmos parâmetros: minimum e maximum, veja os exemplos de aplicação a seguir:

<h:inputText type="number" name="filhos">
  <f:validateLongRange minimum="0" maximum="100"/> (1)
</h:inputText

<h:inputText type="number" name="taxa">
  <f:validateDoubleRange minimum="0.5" maximum="100.12"/> (2)
</h:inputText>
1 Validando um campo do tipo inteiro.
2 Validando um campo do tipo ponto flutuante.

5.3.2 Validações customizadas

Vimos os validadores padrão fornecidos pelo JSF, mas naturalmente estes não irão atender a todas as necessidades do nosso projeto. Há situações nas quais você precisará de validações específicas para o seu caso de uso. Um exemplo interessante de validação customizada podemos ver em formulários de cadastro que exigem que nossas senhas sigam algumas regras para que sejam mais difíceis de serem descobertas, tal como no exemplo a seguir:

Vamos então implementar um validador que verifique se uma senha segue as nossas próprias regras de complexidade. Apenas para simplificar, exigieremos uma única regra: a senha deve ter pelo menos quatro caracteres. Se tiver menos que isto, será considerada uma senha fraca e, portanto, não poderá ser usada no cadastro de usuários.

Sendo assim, para fins estritamente didáticos vamos implementar um formulário que valide a complexidade de nossa senha. Se esta não passar por uma de nossas regras, exporemos uma mensagem de erro ao usuário, tal como apresentado na imagem a seguir:

Nosso primeiro passo consistirá na implementação do nosso validador customizado. Para implementar um só é preciso escrever uma classe que satisfaça estas duas condições:

  • Implementar a interfacae javax.faces.validator.Validator.
  • Possuir a anotação javax.faces.validator.FacesValidator.

Nosso validador customizado respeita estas duas regras e seu código fonte pode ser visto a seguir:

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

@FacesValidator("passwordValidator") (1)
public class SenhaValidador implements Validator {

	@Override
	public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { (2)

		String senha = value != null ? value.toString() : null;
		if (senha == null) {
			context.addMessage(component.getClientId(), new FacesMessage("Nenhuma senha foi fornecida"));
		} else {
			if (senha.trim().length() < 4) {
				context.addMessage(component.getClientId(), new FacesMessage("Senha inválida. Tem de ter pelo menos 4 caracteres!"));
			}
		}


	}

}
1 Todo validador deve possuir um nome. Se indefinido, o nome será o da classe.
2 O único método da interface que precisa ser validado.

Nossa atenção deve se voltar neste momento para a assinatura do método que devemos implementar (validate). Observe que ele recebe três parâmetros:

  • Uma instância de FacesContext, que já vimos anteriormente neste livro.
  • Uma instância de UIComponent, que representa o componente cujo conteúdo iremos validar.
  • O valor a ser validado, do tipo Object.

Neste momento não nos interessa o segundo argumento, veremos com mais detalhes como funcionam os componentes do JSF mais a frente neste livro. Para nossa validação a única coisa que realmente nos interessa agora são o primeiro e o terceiro parâmetros.

Usaremos a instância de FacesContext para que, sendo encontrados erros, nós os reportemos ao JSF. Fazemos isto adicionando novas instâncias de objetos do tipo javax.faces.application.FacesMessage ao contexto usando o método addMessage.

Em nosso exemplo usamos o construtor mais simples possível deste componente, aquele que apenas recebe uma string representando o erro encontrado. Entretanto há outras variações que veremos adiante neste livro que nos permitem identificar as mensagnes por código e, portanto, nos facilitam a construção de aplicações internacionalizáveis.

E o funcionamento do validador pode ser visto em nossa implementação do método validate: o valor passa pelo teste de validação se, e somente se, não inserirmos nenhuma mensagem de erro na instância de FacesContext. Bem simples, né?

Implementado o nosso validador customizado, temos 50% do trabalho concluído. O próximo passo consiste em aplicar o validador customizado em nosso formulário, o que é bastante simples. Basta usarmos a tag <f:validator>, tal como você pode conferir no código a seguir:

<h:form>
	<h2>Teste sua senha</h2>
	<h:panelGrid columns="2">
		<h:outputText value="Senha"/>
			<h:inputSecret required="true"
					requiredMessage="Autenticação sem senha? Duvido."
					name="senha" styleClass="mdl-textfield__input"
					value="#{authController.credenciais.senha}">
					<f:validator validatorId="passwordValidator" /> (1)
			</h:inputSecret>
			<h:outputText value=" " />
			<h:commandButton value="Testar" action="#{authController.testeSenha()}"/>
	</h:panelGrid>
	<h:messages/> (2)
</h:form>
1 Observe que passamos ao atributo validatorId o nome que demos ao nosso validador customizado usando a anotação @FacesValidator.
2 A apresentação das nossas mensagens de validação.

Você deve estar se questionando a respeito do código que escrevemos para o método testeSenha do nosso managed bean. Quer ver?

public String testeSenha() {
	return null;
}

Sim, é só isto: o método sequer será executado, dado que os validadores serão chamados antes do managed bean ser sequer tocado? Lembra lá no início desta seção quando mencionei que validadores servem para aumentar a segurança e desempenho dos nossos sistemas? Aqui está um exemplo: se o teste de senha fosse uma operação complexa ou que pudesse gerar algum risco de segurança ao nosso sistema, esta sequer seria executada.

Exercício

Vamos melhorar este nosso validador customizado? A sua implementação encontra-se na classe SenhaValidator que se encontra no projeto jsf-tabelas.

Seu papel consistirá em ampliá-lo com novas regras que tornem as senhas ainda mais fortes:

  • Pelo menos uma letra deve ser maiúscula.
  • Deve ter pelo menos 8 caracteres.
  • Pelo menos um caractere numérico deve estar presente.
  • Pelo menos um caractere especial, tais como *,/,^,~,etc deverá estar presente na senha.

Para cada uma destas regras, caso não seja satisfeita, uma mensagem de erro específica deverá ser adicionada.

5.3.3 Customizando a apresentação das mensagens de erro

Até este momento as mensagens de erro são bem feias. Cheogu a hora de você aprender a customizá-las. Há duas maneiras das mensagens de erro serem apresentadas:

  • Todas as mensagens do formulário no mesmo componente (agrupadas) - tag <h:messages/>.
  • Próximas ao componente de entrada que originou o erro de validação (contextualizadas) - tag <h:message/>.

Que mensagens de erro?

São as instâncias de objetos do tipo FacesMessage que você adiciona à instância de FacesContext, seja no seu validador ou em outros pontos da sua aplicação.

Observe portanto que ao usarmos o termo mensagens, não necessáriamente estamos falando de mensagens de erro. Podemos estar também falando aqui de mensagens de status que apresentamos ao usuário tais como, por exemplo, de que a operação solicitada foi realizada com sucesso. Pense nisto.

Em ambos os casos a customização das mensagens de erro seguirá sempre as mesmas regras e usarão os mesmos atributos.

Em primeiro lugar os erros por padrão serão renderizados como listas HTML não ordenadas, tal como no exemplo a seguir:

<ul> (1)
  <li>Primeira mensagem de erro</li> (2)
  <li>Segunda mensagem de erro</li>
  <li>n-ésima mensagem de erro</li>
</ul>
1 O container HTML que irá agrupar todas as mensagens de erro.
2 Como as mensagens de erro são renderizadas.

Em segundo lugar, leve em consideração os parâmetros que poderão ser usados:

  • errorClass - qual classe (ou classes) serão inseridas em cada erro (<li>).
  • layout - qual o layout que será usado na renderização as mensagens de erro. Valores possíveis: list (padrão) ou table.
  • globalOnly - serão expostas apenas as mensagens que não estão associadas a nenhum identificador de componente (mais sobre isto adiante).
  • errorStyle - você também pode fornecer o código CSS que será usado na renderização de cada um dos erros renderizados. Para facilitar a manutenção do seu código, sempre dê preferência ao uso do atributo errorClass ao invés deste.
5.3.3.1 Mensagens de erro agrupadas

Se você usar a tag <h:messages/> sem definir o atributo globalOnly, todas as mensagens de erro serão apresentadas por padrão. Neste momento a pergunta surge: como especificar qual o componente relacionado a uma mensagem?

Prestou atenção no código de exemplo que usamos na implementação do nosso validador customizado? Preste atenção no trecho a seguir:

public void validate(FacesContext context, UIComponent component, Object value)
	throws ValidatorException {

	String senha = value != null ? value.toString() : null;
	if (senha == null) {
		context.addMessage(component.getClientId(), new FacesMessage("Nenhuma senha foi fornecida")); (1)
	} else {
		if (senha.trim().length() < 4) {
			context.addMessage(component.getClientId(), new FacesMessage("Senha inválida. Tem de ter pelo menos 4 caracteres!")); (2)
		}
	}
	}
1 O primeiro parâmetro que passamos à função addMessage é o identificador do componente, o segundo parâmetro esperado pela função validate.
2 Aqui, de novo, usando a mesma abordagem.

A seguir você pode ver um exemplo de customização na apresentação das mensagens agrupadas:

E aqui está o código de exemplo no qual customizamos este visual usando classes:

  <h:messages errorClass="erros"/>
5.3.3.2 Mensagens de erro contextualizadas

Expor todas as mensagens em um único bloco é uma péssima ideia: o ideal é que o usuário possa ver o erro próximo de onde ocorreu. Se minha senha não foi fornecida, devo ver a mensagem próxima do meu campo senha, não no topo da página.

O ideal é que possamos ter um resultado final tal como o apresentado na imagem a seguir:

Entra em ação agora a tag <h:message>. Tal como você já deve esperar, esta opera de forma muito similar à que vimos com <h:messages>. A diferença está no atributo for, que usamos para definir quais as mensagens que deverão ser apresentadas, isto é, aquelas relacionadas ao componente que as originou.

A melhor forma de mostrar seu funcionamento é com código. Sendo assim, veja como ficou o código final do nosso formulário de autenticação:

<h:form>
	<h2>Identifique-se!</h2>
	<h:panelGrid columns="2">
		<h:outputText value="Login"/>
			<h:panelGrid columns="1">
				<h:inputText required="true"
					requiredMessage="O campo login é obrigatório"
					id="login" (1)
					validatorMessage="Login for ado padrão..."
					value="#{authController.credenciais.login}">
						<f:validateLength minimum="8" maximum="64" />
						<f:validateRegex pattern=".*@itexto.com.br"/>
				</h:inputText>
				<h:message for="login" /> (2)
				</h:panelGrid>
				<h:outputText value="Senha"/>
				<h:panelGrid columns="1">
					<h:inputSecret required="true"
						requiredMessage="Autenticação sem senha? Duvido."
						id="senha" (3)
						value="#{authController.credenciais.senha}">
						<f:validator validatorId="passwordValidator" />
					</h:inputSecret>
					<h:message for="senha"/> (4)
				</h:panelGrid>
		<h:outputText value=" " />
		<h:commandButton value="Entrar" action="#{authController.autenticar()}"/>
	</h:panelGrid>
</h:form>
1 Seu componente deve ter um id bem definido.
2 Atenção para o atributo for, este aponta para o id que você definiu acima.
3 O mesmo que 1.
4 O mesmo que 2.

5.4 Tabelas

A ESCREVER...

E nunca terminei. Talvez nunca termine. Quando cheguei nesta parte da escrita a equipe já sabia o suficiente para seguir com as próprias pernas. O tempo foi passando e nisto acabei me esquecendo deste projeto de livro, que agora chegou a você.

Não vou te deixar na mão: segue alguns tópicos para você publicar a respeito caso queira se aprofundar no assunto:

  • O ciclo de vida dos componentes do JSF - vai te ajudar a ter um conhecimento profundo sobre o framework.
  • Como renderizar tabelas (era o conteúdo deste capítulo que não escrevi). Aqui tá um dos recursos mais bacanas do JSF: você pode criar modelos de tabelas de uma forma quase declarativa que é muito, muito produtiva.
  • A biblioteca de componentes Prime Faces. Vai dar um boom na sua produtividade, acredite.
  • Os mapas de navegação.
  • Como a inversão de controle e injeção de dependências é feita no JSF

Mas não fique triste: pelo menos você já sabe o básico do JSF pra poder prosseguir daqui pra frente, certo?

Mantido por itexto Consultoria