Primeiras aulas do curso Java e JSF I: Sua aplicação web com JSF2

Java e JSF I: Sua aplicação web com JSF2

Introdução ao desenvolvimento web com JSF - Introdução ao desenvolvimento web com JSF

Introdução ao JavaServer Faces

Os usuários habituaram-se com aplicações Desktop. Este tipo de aplicação é instalada no computador local e acessa diretamente um banco de dados ou gerenciador de arquivos.

Para o desenvolvedor, a aplicação Desktop é construída com uma série de componentes que a plataforma de desenvolvimento oferece para cada sistema operacional. Esses componentes ricos e muitas vezes sofisticados estão associados a eventos ou procedimentos que executam lógicas de negócio.

Problemas de validação dos dados são indicados na própria tela sem que qualquer informação do formulário seja perdida. De uma forma natural, esses componentes lembram-se dos dados do usuário, inclusive entre telas e ações diferentes.

Nesse tipo de desenvolvimento são utilizados diversos componentes ricos, como por exemplo, calendários, menus diversos ou componentes drag & drop (arrastar e soltar). Eles ficam associados à eventos/ações e guardam automaticamente seu estado, pois mantém os valores digitados pelo usuário.

Essa é uma boa prática no desenvolvimento orientado a objetos e ganhou o nome de Desenvolvimento Rápido de Aplicações, ou simplesmente RAD, onde o ambiente de desenvolvimento e os componentes reutilizáveis favorecem a criação rápida de aplicações.

O cliente gordo e o desenvolvimento Desktop

Existem algumas desvantagens nessa abordagem, visto que cada usuário possui uma cópia, muitas das vezes integral, dessa aplicação. Qualquer alteração precisaria ser propagada para todas as outras máquinas. Estamos usando um "cliente gordo", com muita responsabilidade no lado do cliente.

Para piorar, as regras de negócio rodam no computador do usuário, sendo muito difícil depurar a aplicação. Em geral, enfrentamos problemas de manutenção e gerenciabilidade.

O desenvolvimento Web e o protocolo HTTP

Para resolver problemas como esse, surgiram as aplicações baseadas na web. Nessa abordagem há um servidor central, onde a aplicação é executada e processada, e todos os clientes podem acessá-la através do protocolo HTTP.

O usuário precisa basicamente instalar um navegador web, como Firefox ou Internet Explorer, que receberá o HTML, o CSS e o JavaScript, que são afinal tecnologias que ele entende.

Entre cada requisição (request), trafega o HTML do lado servidor (Server Side) para o computador do cliente (Client Side). Em nenhum momento a aplicação está salva no cliente. Todas as regras da aplicação estão sendo processadas no lado do servidor. Por isso, essa abordagem também foi chamada de "cliente magro".

Isso facilita bastante a manutenção e a gerenciabilidade, pois temos um lugar - central -, onde a aplicação é executada, mas ainda é preciso conhecer bastante de HTML, CSS e JavaScript para definir a interface com o usuário. Também não há mais eventos, mas sim um modelo bem diferente orientado a requisição e resposta. Além disso, ainda é preciso conhecer o protocolo HTTP. Assim, toda essa responsabilidade fica a cargo do desenvolvedor.

Comparando as duas abordagens, podemos ver vantagens e desvantagens em ambas. No lado da aplicação puramente Desktop, temos um estilo de desenvolvimento orientado ao evento, usando componentes ricos, porém com problemas de manutenção e gerenciamento. Do outro lado, as aplicações web são mais fáceis de gerenciar e manter, mas precisamos lidar com HTML e conhecer o protocolo HTTP, e seguir o modelo request-response (requisição-resposta).

Mesclar desenvolvimento Desktop e Web

O ideal seria mesclar os dois estilos, aproveitando as vantagens de cada um. Seria um desenvolvimento Desktop para WEB central e com componentes ricos. Isso é justamente a ideia dos frameworks web baseados em componentes.

Frameworks Web baseados em componentes

No mundo Java há algumas opções como JavaServer Faces (JSF), Apache Wicket, Vaadin, Tapestry ou GWT, do Google. Todos eles são frameworks web baseados em componentes.

Analisando um pouco melhor o JSF, percebemos que ele é na verdade um padrão ou especificação que faz parte do Java Enterprise Edition (Java EE). Por ser uma especificação, ou Java Specification Request (JSR), ele é mantido dentro do Java Community Process (JCP).

Vamos procurar então o JSF no site da JCP. Digitando 314 na busca das JSRs (buscar das especificações), é mostrado como resultado a última versão do JSF. Navegando no resultado, podemos ver todos os documentos disponíveis para os interessados na implementação dessa especificação JSF.

Baseado nesta especificação, há várias implementações. A mais famosa, e também implementação referencial (RI), é a Oracle Mojarra, aquela que mostra como o JSF deveria se comportar. Outra implementação famosa é da Apache Software Foundation, e se chama MyFaces.

Neste caso baixaremos a implementação Mojarra no link indicado para utilizá-lo depois em nosso projeto. Acessando o site javaserverfaces.java.net, na parte de downloads, podemos encontrar o link para baixar o JAR do Mojarra.

Introdução ao JSF com Mojarra e PrimeFaces

Como dito antes, nosso projeto utilizará a implementação Mojarra do JSF. Ela já define o modelo de desenvolvimento e oferece alguns componentes bem básicos. Nada além de inputs, botões e ComboBox simples. Não há componentes sofisticados dentro da especificação. Isto é proposital, pois o mundo web evolui rápido (principalmente na questão das interfaces gráficas).

Para atender a demanda dos desenvolvedores por componentes mais sofisticados, existem várias extensões do JSF que seguem o mesmo ciclo e modelo da especificação. São exemplos dessas bibliotecas: PrimeFaces, RichFaces ou IceFaces.

Todos eles oferecem ShowCases na web para mostrar seus componentes e suas funcionalidades. Daremos uma olhada no PrimeFaces, acessando o site primefaces.org.

link para baixar o JAR do PrimeFaces usado na aula.

Podemos ver no demo online uma lista de componentes disponíveis. Vamos dar uma olhada em alguns dos componentes, começando com o calendário, que claro, não poderia faltar. Outro componente simples é o carousel, que apresenta os dados em painéis fáceis de navegar. Já mais sofisticada é a agenda onde podemos cadastrar eventos. Por último não pode faltar os componentes Drag and Drop.

Para este treinamento usaremos Mojarra com o PrimeFaces.


O primeiro projeto e os componentes poderosos do Primefaces

Para mostrar a simplicidade dos componentes ricos, preparamos para você um projeto base no Eclipse. Nos próximos vídeos veremos em detalhes a configuração desse projeto. Queremos com ele mostrar a simplicidade do desenvolvimento de interfaces ricas para web (Rich Internet Application) com componentes JSF.

As bibliotecas necessárias (JARs) já estão disponíveis na pasta lib e também temos uma página inicial criada, a olamundo.xhtml, como primeiro exemplo. Ela já está pronta para os componentes do PrimeFaces e tem um corpo que mostra um simples cabeçalho HTML.

Podemos iniciar o servidor e chamar a página no navegador http://localhost:8080/jsf/olamundo.xhtml. Aparecerá a nossa página de exemplo.

De volta ao Eclipse, vamos experimentar alguns componentes do PrimeFaces para ilustrar o uso. O primeiro será o calendário. Na página olamundo.xhtml, que está dentro da pasta WebContent do projeto jsf vamos digitar <calendar /> logo após o <br /> para referenciar o componente.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

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

<h:head>
     <title>Primeiro Exemplo usando JSF - olamundo.xhtml</title>
</h:head>

<h:body>
     <h2>Exemplo Ola Mundo com JSF 2.0 e PrimeFaces</h2>
     <br />
     <p:calendar />
</h:body>
</html>

Agora é só salvar e está pronto para testar no navegador. Temos então um input que renderiza automaticamente um calendário.

Como próximo componente vamos experimentar um Panel. Novamente, super simples de usar. Basta colocar p:panel e definir um cabeçalho e um corpo. Ao testar aparece o panel, mas ele está fixo na página, e não pode ser arrastado. Vamos voltar ao Eclipse e ativar essa funcionalidade com o componentes p:draggable. Aqui é preciso criar uma ligação entre panel e draggable pela ID do componente.

<!-- código omitido -->

     <p:panel id="panel"  header="JSF - Componentes para Web">
         arraste-me!
     </p:panel>
     <p:draggable for="panel" />

<!-- código omitido -->

Novamente vamos testar no navegador e agora sim podemos arrastar o panel livremente. Repare que em nenhum momento nos preocupamos com JavaScript, CSS ou HTML. Usamos apenas componentes para definir uma interface bastante agradável.

Por último, como vimos a agenda no showcase do PrimeFaces. Vamos testar esse componente também. Ele se chama p:schedule e também é de simples utilização.

     <p:schedule />

Ao atualizar no navegador, aparece a agenda sofisticada.

Configuração do ambiente e os primeiros passos com JSF - Configuração do ambiente e os primeiros passos com JSF

Apresentação do ambiente de desenvolvimento

Nessa vídeo-aula começaremos a desenvolver uma aplicação web com JSF. Já temos um ambiente de desenvolvimento pré-configurado baseado no Java SE 7 e utilizaremos como IDE o Eclipse IDE for Java EE Developers. Nosso Servlet Container será o Apache Tomcat na versão 7 - todos disponíveis nos links indicados.

Além disso precisaremos o JAR da implementação referencial do JSF (Mojarra): aqui

Entendendo o domínio da aplicação

O nosso projeto web facilitará o trabalho em uma Livraria, onde o usuário poderá cadastrar livros e autores. Trabalharemos com objetos do tipo Livro associados a autores. Trata-se de um relacionamento muitos-para-muitos. Antes de modelarmos as classes, vamos criar e configurar o projeto.

Atenção na importação

Ao importar o projeto o Eclipse automaticamente fará uma validação rígida dos arquivos. Nesse caso, o Eclipse acusa a assinatura de alguns métodos do projeto. Para desabilitar essa validação basta acessar:

Menu Preferences -> Item Validation:

Tire:

1) Facelet HTML Validator

2 ) JSF View Application Configuration Validator

3) JSF View Validator

Isto é necessário pois o Eclipse quer que todos os métodos associados ao atributo action do componente h:commandButton devolvam obrigatoriamente um String (que não é preciso).

Configurando o servidor web

A IDE Eclipse já está rodando, mas é preciso fechar a janela de "boas-vindas" para ver a perspectiva padrão. Durante o treinamento, utilizaremos a perspectiva Java EE, mas podemos trocar a qualquer momento essa perspectiva por meio do botão "+" no lado superior direito do Eclipse.

O primeiro passo é configurar o Servlet Container Tomcat dentro do Eclipse. Para tal, utilizaremos a aba (view) Server. Caso essa janela tenha sido fechada, podemos reabri-la através do atalho Ctrl + 3 e digitando server.

Vamos então preparar o Tomcat definindo uma nova configuração do servidor. Na caixa de diálogo New server, escolheremos Apache Tomcat v7.0 Server, em seguida, apertando next, definimos o lugar onde o Tomcat foi instalado (ou descompactado). No nosso caso, como já temos uma distribuição do Tomcat baixada e extraída, vamos apontar para ela. Ao finalizar aparecerá o Tomcat na view Server.

Criação do projeto JSF

O próximo passo é criar o projeto web. Vamos no menu File -> New -> Dynamic Web Project. Chamaremos o projeto de jsf-livraria. É preciso verificar se o Tomcat está escolhido como servidor, inclusive se o module version encontra-se na versão 3.0.

No combo box Configuration, escolhemos Java Server Faces. Confirmaremos as duas próximas telas até chegar na tela JSF Capabilities.

Aqui configuraremos de onde vem a biblioteca JSF. Para este projeto, copiaremos o JAR após a criação do projeto. Ou seja, desabilitamos o uso de qualquer biblioteca fornecida pelo Eclipse.

Um pouco mais abaixo há a configuração do servlet que representa o controlador. Usaremos praticamente a mesma configuração. Apenas o mapeamento será alterado. Queremos que qualquer requisição que termine com *.xhtml seja processada pelo FacesServlet.

Ao confirmar, será gerado o novo projeto, visível ao lado esquerdo, no view project-explorer. Vamos arrastar o projeto ao servidor Tomcat para simplificar o deploy da aplicação.

Ao abrir o projeto, veremos a estrutura básica com as classes Java dentro da pasta src e todos os arquivos Web dentro da pasta WebContent.

Dentro do WebContent encontramos uma pasta WEB-INF com dois arquivos de configuração. O primeiro, web.xml, é relacionado com a especificação servlet. Ele contém a declaração do FacesServlet, com aquela configuração que alteramos na criação do projeto.

O segundo XML é o arquivo de configuração relacionado com o mundo JSF. Como o JSF na versão dois encoraja o uso de anotações, este arquivo torna-se pouco usado, sendo muito mais importante na primeira versão do JSF.

Como vimos no web.xml, há a configuração do FacesServlet. Essa classe faz parte da implementação JSF e deve estar presente. É preciso copiar o JAR do Mojarra para o nosso projeto.

Já baixamos a biblioteca e como se trata de um projeto web, o JAR deve ser copiado para a pasta WEB-INF/lib e assim fará parte do buildpath do projeto.

Começando a implementar nossa livraria

Tudo pronto para desenvolver com JSF. No projeto, vamos começar com o cadastro de livros. O objetivo é criar um formulário com os componentes da especificação.

Vamos selecionar a pasta WebContent, clicar com o botão direito, New HTML File. O arquivo se chama livro.xhtml. Cuidado com a extensão que deve ser XHTML. Ao apertar next, podemos escolher um template. Usaremos xhtml 1.0 transitional.

No arquivo apagaremos tudo que está dentro das tags HTML, pois utilizaremos os componentes JSF. Para declará-los é preciso adicionar um XML namespace na abertura da tag HTML.

Para tal, digitamos xmlns:h, onde o "h" é o apelido do namespace para a uri "http://java.sun.com/jsf/html". Ctrl + Espaço ajuda a auto-completar. Atenção para não confundir com o namespace JSTL.

<? xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://java.sun.com/jsf/html">

</html>

A partir da definição no cabeçalho, podemos usar o apelido "h" para declarar os componentes JSF. O primeiro componente que usaremos é o h:body que define o corpo da página. Dentro do body vamos declarar o formulário através da tag h:form. Repare que aqui, diferente da tag form do HTML, o componente JSF não possui um atributo action.

<!-- cabeçalho omitido -->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
    <h:body>
        <h:form>
        </h:form>
    </h:body>
</html>

No formulário, usaremos o primeiro componente que captura uma entrada do usuário, o h:inputText. Além do inputText, vamos utilizar um botão para executar uma ação. A especificação define comandos para isto. Nesse caso, um h:commandButton. Com o atributo value definimos "Gravar", que aparecerá na tela.

<!-- cabeçalho omitido -->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
    <h:body>
        <h:form>
            <h:inputText />
            <h:commandButton value="Gravar" />
        </h:form>
    </h:body>
</html>

Com o Tomcat rodando já podemos testar a página pelo navegador, accessando http://localhost:8080/jsf-livraria/livro.xhtml. O formulário aparecerá.

Controlador e Visão no JSF

Parece que chamamos diretamente a página livro.xhtml, mas isso não é verdade. Lembrando que no web.xml teremos o FacesServlet mapeado para receber qualquer requisição que termina com xhtml. Acontece que ao enviar a requisição, o Tomcat delega o fluxo para o servlet da nossa aplicação jsf-livraria. O servlet recebe a chamada e decide qual página chamará. É ele que está no controle do fluxo, e por isso também é chamado controlador.

O controlador lê o xhtml e instancia os componentes declarados. No final ele pede aos componentes a apresentação HTML e devolve o HTML como resposta para o navegador.

Podemos provar isso também no navegador. Ao visualizar o código fonte da página, aparece o HTML puro. Esse HTML é bem diferente da página xhtml.

Completando o formulário

Vamos continuar e completar o formulário. Primeiro utilizaremos o componente h:outputLabel para associar um label com o input. A ligação é feita pela id da componente inputText e o atributo for do outputLabel. Ao testar no navegador aparece o label na frente do input.

<!-- cabeçalho omitido -->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
    <h:body>
        <h:form>
            <h:outputText value="Titulo: " for="titulo"/>
            <h:inputText id="titulo"/>
            <h:commandButton value="Gravar" />
        </h:form>
    </h:body>
</html>

Mesmo usando componentes JSF, podemos aproveitar as tags do mundo HTML. Vamos definir um cabeçalho na página usando a tag h1. Além disso, usaremos um fieldset para agrupar os elementos do formulário com um título indicado pela tag legend. Visualizando mais uma vez no navegador, podemos perceber que o formulário já está mais organizado.

<!-- cabeçalho omitido -->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
<h:body>
        <h1>Novo Livro</h1>
        <h:form>
            <fieldset>
                <legend>Dados do Livro</legend>
                <h:outputLabel value="Titulo:" for="titulo" />
                <h:inputText id="titulo" />
            </fieldset>
        </h:form>
    </h:body>

Falta criar os componentes para o ISBN, preço e data de lançamento do Livro. Copiaremos o outputLabel e inputText para facilitar o trabalho. Primeiro para ISBN, segundo o preço e terceiro a data de lançamento. Visualizaremos mais uma vez o resultado no navegador.

<!-- cabeçalho omitido -->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
    <h:body>
        <h1>Novo Livro</h1>
        <h:form>
            <fieldset>
                <legend>Dados do Livro</legend>
                    <h:outputLabel value="Titulo:" for="titulo" />
                    <h:inputText id="titulo" />
                    <h:outputLabel value="ISBN:" for="isbn" />
                    <h:inputText id="isbn" />
                    <h:outputLabel value="Preço:" for="preco" />
                    <h:inputText id="preco" />
                    <h:outputLabel value="Data de Lançamento:" for="dataLancamento" />
                    <h:inputText id="dataLancamento" />
                    <h:commandButton value="Gravar" />
            </fieldset>
        </h:form>
    </h:body>
</html>

Todos os componentes foram renderizados para HTML. Um após o outro, ocupando todo espaço horizontal da tela. Para melhorar o layout, utilizaremos o componente h:panelGrid, que funciona como um simples layoutmanager, organizando os componentes verticais.

Também podemos definir a quantidade de colunas no grid. Para tal, usamos o atributo columns do componente h:panelGrid para criar duas colunas:

<!-- cabeçalho omitido -->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
    <h:body>
        <h1>Novo Livro</h1>
        <h:form>
            <fieldset>
                <legend>Dados do Livro</legend>
                <h:panelGrid columns="2">
                    <!-- inputs omitido -->
                    <h:commandButton value="Gravar" />
                </h:panelGrid>
            </fieldset>
        </h:form>
    </h:body>
</html>

Ligando Managed Beans a componentes visuais

Conseguimos criar a tela, mas também queremos executar uma ação para gravar o livro. Ou seja, quando o usuário apertar o botão "Gravar" no navegador, este componente disparará a execução de um método no lado do servidor. Para isso vamos criar uma classe, associando-a com o componente.

Cada componente possui atributos especiais para criar uma ligação com uma classe. No caso do commandButton, usaremos o atributo action. Nele definiremos a classe e o metódo a executar, mas primeiro é preciso criar esta classe.

Clique com o botão direito na pasta src, em seguinda, New -> Class. Podemos utilizar qualquer nome da classe. Em nosso caso, vamos chamá-la de LivroBean, dentro do package br.com.caelum.livraria.bean:

package br.com.caelum.livraria.bean;

public class LivroBean {
}

Na classe criaremos o método gravar(), que imprime apenas uma informação no console. Além disso, é preciso indicar que a classe será gerenciada pelo JSF. Isso é feito através da anotação @ManagedBean:

package br.com.caelum.livraria.bean;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class LivroBean {

    public void gravar() {
        System.out.println("Gravando livro ");
    }
}

Voltando ao formulário, podemos agora ligar o comando ao método gravar(). Essa ligação (ou binding) é feita com uma linguagem de expressão (Expression Language). Uma expressão sempre começa com #{ e termina com }, dentro dela usaremos o nome da classe, "ponto (.)" seguido do nome do método:

    <h:commandButton value="Gravar" action="#{livroBean.gravar}"/>

Antes de testar no navegador é preciso reiniciar o Tomcat. Ao atualizar o formulário no navegador e clicar no botão, podemos observar a saída no console do Eclipse.

Capturando dados do formulário com a classe LivroBean

O próximo passo é capturar os dados do formulário com a classe LivroBean. Para isso definiremos, para cada componente de input, um atributo no LivroBean. Primeiro o titulo e isbn, ambos do tipo String, depois preco do tipo double e a dataLancamento novamente do tipo String. Mais para frente veremos como trabalhar com datas do tipo Date ou Calendar. Por enquanto vamos deixar a data como String.

Além disso, é preciso gerar os getters e setters para cada atributo. Para isso, pressione Ctrl + 3, digitando GGAS. Selecione Generate Getters e Setters e, na janela, todos os atributos para confirmar. Vamos também formatar a classe usando o atalho Ctrl+Shift+F.

package br.com.caelum.livraria.bean;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class LivroBean {

    private String titulo;
    private String isbn;
    private double preco;
    private String dataLancamento;

    public void gravar() {
        System.out.println("Gravando livro ");
    }

    //getters e setters
}

Voltando ao livro.xhtml, ligaremos cada input com o atributo ou propriedade da classe LivroBean. Nos componentes de input usaremos o atributo value, pois queremos receber o valor desse componente, mas novamente através de Expression Language. No primeiro input: #{livroBean.titulo}. Faremos a mesma coisa para os demais inputs isbn, depois o preco e no final, a dataLancamento - sempre usando Expression Language:

<!-- cabeçalho omitido -->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">

    <h:body>
        <h1>Novo Livro</h1>
        <h:form>
            <fieldset>
                <legend>Dados do Livro</legend>
                <h:panelGrid columns="2">
                    <h:outputLabel value="Titulo:" for="titulo" />
                    <h:inputText id="titulo" value="#{livroBean.titulo}"/>
                    <h:outputLabel value="ISBN:" for="isbn" />
                    <h:inputText id="isbn" value="#{livroBean.isbn}"/>
                    <h:outputLabel value="Preço:" for="preco" />
                    <h:inputText id="preco" value="#{livroBean.preco}"/>
                    <h:outputLabel value="Data de Lançamento:" for="dataLancamento" />
                    <h:inputText id="dataLancamento" value="#{livroBean.dataLancamento}"/>
                    <h:commandButton value="Gravar" action="#{livroBean.gravar}"/>
                </h:panelGrid>
            </fieldset>
        </h:form>
    </h:body>

</html>

Falta mostrar no método gravar() algum valor do livro que está sendo gravado para podermos verificar o recebimento dos valores. Vamos concatenar o título na saída.

package br.com.caelum.livraria.bean;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class LivroBean {

    private String titulo;
    //outros atributos

    public void gravar() {
        System.out.println("Gravando livro " + this.titulo);
    }

    //getters e setters
}

É uma boa prática reiniciar o servidor para ter certeza que as alterações foram publicadas. Também é boa prática chamar o formulário de novo (ou seja, enviando um novo request) para garantir que todos os componentes foram atualizados. Ao atualizar podemos ver uma pequena mudança no formulário: o campo Preço já vem preenchido. Vamos inserir os dados e apertar em Gravar.

O Eclipse mostra Gravando livro com o título no console. No nosso caso, "Fausto". Tudo funcionando. Recebemos os dados do formulário no LivroBean.

Refatoração do ManagedBean para popular o domínio

Ao observar a classe LivroBean podemos criticar vários atributos "soltos". Muito provavelmente precisaremos deles em outras classes a medida que a aplicação crescer, pois eles representam um livro. Faz todo sentido separar a responsabilidade de cadastrar o livro da responsabilidade de ser um livro. Por isso, selecionaremos os atributos e extrairemos uma nova classe que representa um Livro.

Ainda usando o Eclipse, no menu Refactor, selecione Extract Class. Chamaremos a classe de Livro e geraremos os getters e setters. No LivroBean, criaremos um único atributo chamado livro. O Eclipse gerou um nova classe Livro com os atributos e getters/setters.

package br.com.caelum.livraria.bean;

public class Livro {
    private String titulo;
    private String isbn;
    private double preco;
    private String dataLancamento;

    //getters e setters
}

Na classe LivroBean podemos apagar todos os getters. Repare que sobrou apenas um atributo privado que necessita de um getter. Esse getter é utilizado pelos componentes para popular o livro:

@ManagedBean
public class LivroBean {

    private Livro livro = new Livro();

    public Livro getLivro() {
        return livro;
    }

    public void gravar() {
        System.out.println("Gravando livro " + this.livro.getTitulo());
    }
}

Após reiniciar o Tomcat, vamos testar novamente no navegador. Ao chamar o formulário recebemos uma exceção. Há algum problema na página livro.xhtml, na linha 13, com a expressão #{livroBean.titulo}. Ao analisar percebemos que não existe o atributo titulo no LivroBean.

Esse atributo está na classe Livro, mas não atualizamos o livro.xhtml. Na página é preciso alterar as expressões de cada input e declarar o caminho correto. Para o titulo usaremos agora: #{livroBean.livro.titulo}.

<!-- cabeçalho omitido -->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">

    <h:body>
        <h1>Novo Livro</h1>
        <h:form>
            <fieldset>
                <legend>Dados do Livro</legend>
                <h:panelGrid columns="2">
                    <h:outputLabel value="Titulo:" for="titulo" />
                    <h:inputText id="titulo" value="#{livroBean.livro.titulo}"/>
                    <h:outputLabel value="ISBN:" for="isbn" />
                    <h:inputText id="isbn" value="#{livroBean.livro.isbn}"/>
                    <h:outputLabel value="Preço:" for="preco" />
                    <h:inputText id="preco" value="#{livroBean.livro.preco}"/>
                    <h:outputLabel value="Data de Lançamento:" for="dataLancamento" />
                    <h:inputText id="dataLancamento" value="#{livroBean.livro.dataLancamento}"/>
                    <h:commandButton value="Gravar" action="#{livroBean.gravar}"/>
                </h:panelGrid>
            </fieldset>
        </h:form>
    </h:body>

</html>

Por fim, testaremos mais uma vez. Como alteramos apenas o formulário, não é preciso reiniciar o servidor. Vamos atualizar o formulário e inserir os dados. Ao gravar, nenhuma exceção foi lançada.

Entendendo MVC e integrando o banco de dados com JPA 2 - Entendendo MVC e integrando o banco de dados com JPA 2

Downloads

Segue o link do projeto utilizado nessa aula: Projeto livraria a importar no Eclipse

Introdução

Na última aula criamos o projeto web e utilizamos os componentes da especificação JSF. Aprendemos como definir um formulário dentro de um arquivo xhtml. Os componentes foram associados com um ManagedBean, uma classe gerenciadada pelo JSF. O ManagedBean, por sua vez, utilizou o modelo para passar os valores.

Modelo arquitetural MVC: Model-View-Controller

Seguimos um modelo arquitetural de separação em três camadas na qual cada camada possui uma responsabilidade bem definida. A primeira camada é a do controlador, que recebe a requisição e decide qual página chamar. A segunda é a da visão (a definição da interface gráfica). E por último, temos o nosso modelo (que representa o domínio da aplicação). O ManagedBean é um intermediário e sua responsabilidade pode variar. Este modelo arquitetural é chamado Model-View-Controller ou MVC.

Utilizando o JPA para persistência

Para esta aula, continuaremos com o projeto livraria, mas agora com um banco de dados para realmente persistir e recuperar os dados. Utilizaremos JPA para a persistência. Como JPA não é o foco deste treinamento, já preparamos um projeto que importaremos no Eclipse:

Projeto livraria a importar no Eclipse

Para importar o projeto, vamos no menu File->Import. No item General, escolhemos Existing project into workspace. Na próxima tela escolheremos o arquivo livraria-capitulo3.zip, que estará disponível para download. Após a confirmação, o Eclipse criará um novo projeto importando os arquivos do ZIP.

O projeto é igual ao projeto da aula anterior. Temos os arquivos livro.xhtml e autor.xhtml, que fazem parte do exercício. Ambos com um formulário para cadastrar o modelo, o livro ou autor, respectivamente.

Na pasta src, encontramos os ManagedBeans, um para cada tela. O LivroBean usa a classe Livro como modelo. Ao abrir o Livro, podemos ver uma novidade relacionada com a persistência. Mapeamos o Livro para uma tabela usando as anotações do JPA como por exemplo @Entity e @Id.

@Entity
public class Livro {

    @Id @GeneratedValue
    private Integer id;

    private String titulo;
    private String isbn;
    private double preco;
    private String dataLancamento;

    @ManyToMany 
    private List<Autor> autores = new ArrayList<Autor>();

    //getters e setters omitidos
}

A tela do autor é semelhante, temos um AutorBean que usa o Autor. Dentro do método gravar(), em cada ManagedBean, já estamos usando o JPA através de um DAO. Podemos ver que a última linha do método instancia um DAO e chama o método adicionar para salvar o modelo.

@ManagedBean
public class LivroBean {

    //outros códigos omitidos

    public void gravar() {
        System.out.println("Gravando livro " + this.livro.getTitulo());

        if(livro.getAutores().isEmpty()) {
            throw new RuntimeException("Livro deve ter pelo menos um Autor");
        }

        new DAO<Livro>(Livro.class).adiciona(this.livro);
    }

    //outros códigos omitidos
}

Vamos dar uma olhada no DAO também. Nele utilizamos JPA. Ou seja, o EntityManager, que é responsável pela persistência de entidades dentro de uma transação. A classe EntityManager se encontra nos JARs que vieram com o projeto importado.

public class DAO<T> {
    private final Class<T> classe;

    public DAO(Class<T> classe) {
        this.classe = classe;
    }

    public void adiciona(T t) {
        //consegue a entity manager
        EntityManager em = new JPAUtil().getEntityManager();
        //abre transacao
        em.getTransaction().begin();

        //persiste o objeto
        em.persist(t);

        //commita a transacao
        em.getTransaction().commit();

        //fecha a entity manager
        em.close();
    }

    //outros métodos omitidos

}

Estamos usando JPA com Hibernate, isso significa que a maioria dos JARs são do projeto Hibernate. Além dos JARs do Hibernate, também temos na pasta lib, o JAR do JSF e o driver do banco MySQL.

Configurando o banco de dados

A configuração do banco está dentro da pasta src/META-INF com o nome persistence.xml. Ao abrí-lo vemos algumas configurações. Primeiro a declaração das entidades, Autor e Livro, segundo os dados da configuração do banco como login e senha, e por fim as propriedades do Hibernate.
<persistence ...>

    <persistence-unit name="livraria" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <class>br.com.caelum.livraria.modelo.Livro</class>
        <class>br.com.caelum.livraria.modelo.Autor</class>

        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/livrariadb" />
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="" />

            <property name="hibernate.hbm2ddl.auto" value="update" /><!-- create -->
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
        </properties>
    </persistence-unit>
</persistence>

Analisando a URL de conexão, vemos o banco livrariadb, que precisa ser criado no MySQL. Já temos o MySQL rodando nessa maquina e nos conectamos através do comando mysql -u root. No prompt do MySQL criaremos o banco pelo comando: create database livrariadb.

Populando o banco de dados através do Hibernate

Ao voltar para o Eclipse, já temos uma classe pronta que ajuda a popular o banco. A classe PopulaBanco apenas insere alguns livros e autores. Além disso, o Hibernate automaticamente gera as tabelas caso não existam. Vamos executar a classe e verificar o resultado no MySQL.

No prompt do MySQL, digitamos use livrariadb;, e para selecionar o banco e show tables;, para mostrar as tabelas. Foram criadas as tabelas Autor, Livro e o relacionamento entre os dois. Selecionaremos uma vez todos os dados do Autor e do Livro, como também os dados da tabela de relacionamento.

Testando nosso formulário

Com o banco configurado e populado, associaremos a aplicação ao Tomcat iniciando-o logo em seguida. Com o navegador aberto, testaremos o formulário do livro. Cuidado, pois o nome da aplicação mudou para livraria.

Vamos testar também o formulário do Autor. Os dados aparecem como esperado.

Já que fizemos a integração com o banco MySQL, inseriremos uma vez um autor pelo formulário. Ao digitar o nome do Autor e submeter o formulário, podemos verificar o resultado no banco. Selecionaremos novamente os dados - o Autor aparece!

Voltando ao navegador, percebemos que o formulário continua preenchido mesmo após ter enviado a requisição. Para entender isso melhor, vamos entrar um pouco mais a fundo no ciclo de vida dos componentes JSF.

O ciclo de vida básico dos componentes JSF

Primeiramente chamamos o autor.xhtml pelo navegador e no lado do servidor, o controlador lê o XHTML. Como já dissemos antes, o controlador instancia os componentes declarados. O resultado é uma árvore de componentes. Nossa tela organiza-se numa estrutura hierárquica. No final, o componente body possui um form que possui um input e assim para frente.

É importante saber que esta árvore de componentes é criada só na primeira requisição (no primeiro GET) e depois fica guardada no sessão HTTP do usuário. O controlador pede dessa árvore em memória e devolve HTML para o navegador.

No próximo passo digitamos o nome do autor e submetemos o formulário. Agora a requisição é do tipo POST e o controlador recuperará apenas a árvore de componentes. Como digitamos o nome do autor no formulario, o controlador passa esse parâmetro da requisição para o componente correspondente. Ou seja, para o inputText. Quando o controlador pede o HTML no final, o componente também devolve o valor dele. Ou seja, o formulário continua preenchido.

Limpando o nosso formulário

Agora o nosso objetivo é limpar o formulário. Faz todo sentido limpar os inputs após a inserção do autor. Aqui é importante lembrar que ligamos o input ao modelo pela expression language. Quando usamos a expressão, o input passa o valor recebido para o modelo e chama o setter da classe Autor. Mas o input não só passa o valor, como também pede o valor do modelo antes de renderizar o HTML. A ligação é bidirecional.

Podemos provar esta ligação através do getter do modelo. Vamos abrir a classe Autor e sempre concatenar um String no getter.

Após reiniciar o servidor, e recarregar a página no navegador, percebemos que esse String já aparece na tela. Ou seja, o componente chamou o getter do modelo.

Para limpar o formulário então, podemos limpar o nosso modelo, mas antes vamos desfazer a alteração no getter. Para limpar o modelo instanciamos um novo autor no método gravar() da classe AutorBean. Assim o input recebe um novo autor sem nenhum valor. Novamente vamos testar no navegador. Ao preencher e submeter o formulário, o input fica vazio.

No próximo capítulo vamos completar o formulário do Livro para associar o Livro com autores.

Sobre o curso Java e JSF I: Sua aplicação web com JSF2

O curso Java e JSF I: Sua aplicação web com JSF2 possui 189 minutos de vídeos, em um total de 133 atividades. Gostou? Conheça nossos outros cursos de Java em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Java acessando integralmente esse e outros cursos, comece hoje!

  • 1241 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

Premium

  • 1241 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$75
à vista R$900
Matricule-se

Premium Plus

  • 1241 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$100
à vista R$1.200
Matricule-se

Max

  • 1241 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$120
à vista R$1.440
Matricule-se
Procurando planos para empresas?

Acesso por 1 ano

Estude 24h/dia onde e quando quiser

Novos cursos todas as semanas