Você está na página 1de 24

NetBeans Visual Web JSF

Integrado com Spring 2.5, JPA e Hibernate

Criando uma aplicação passo a passo com Visual Web JavaServer Faces,
Spring 2.5 e Hibernate utilizando JPA

O Visual Web JavaServer Faces é um editor visual de páginas JavaServer Faces, no


estilo WYSIWYG (What You See Is What You Get), baseado no Java Studio
Creator IDE, da Sun Microsystems. Adaptado como pacote para o NetBeans IDE
5.5, ao qual podia ser instalado separadamente, foi incorporado na versão 6.0 do
NetBeans IDE, tornando-se parte de seu assistente de criação de páginas Web.
Como seu desenvolvimento é baseado em componentes visuais arrastáveis, com
pouco código, o desenvolvedor pode criar páginas totalmente funcionais, integradas
com banco de dados através do uso de JDBC.
Embora o Visual Web JSF possa ser utilizado para desenvolver aplicações
integradas a outros frameworks, não há assistentes ou componentes visuais que o
façam até o momento. Neste artigo vamos usar esta ferramenta, examinando
alguns de seus recursos, guiando o leitor na construção de uma aplicação integrada
ao Spring Framework 2.5, Java Persistence API e Hibernate.

Visual Web JavaServer Faces na prática


O projeto utilizado neste artigo está baseado em apenas uma entidade, que é o
suficiente para ilustrar como integrar o Visual Web JSF com os demais frameworks.
Esta aplicação fará um CRUD (Create, Read, Update and Delete) de uma tabela
proposta de contatos e seu resultado final, em execução, será similar a Figura 1.

Figura 1. Tela do exemplo em funcionamento


Preparando o ambiente de desenvolvimento
Para acompanhar este artigo, será necessário a instalação do NetBeans (6.0 ou
superior) em conjunto com um servidor suportado de aplicações Web Java. O
NetBeans pode ser baixado em seu pacote específico para o desenvolvimento Web
(Web & Java EE), ao qual já inclui o GlassFish V2 e o Apache Tomcat 6, os quais
são pré-configurados na instalação.
Outros servidores poderão ser usados, desde que sejam suportados pelo NetBeans.
Neste caso, será preciso adicioná-lo manualmente, através do menu
Tools>Servers>Add Server. Para o exemplo, será utilizado o Apache Tomcat que já
vem integrado ao programa.
Os plugins do Spring Framework e Hibernate para o NetBeans
O NetBeans possui um plugin para trabalhar com o Spring Framework,
automatizando tarefas como a geração dos arquivos e a adição das bibliotecas
exigidas pelo Spring.
No NetBeans 6.0, Através do menu Tools>Plugins selecione “Spring Framework
Support” em Available Plugins e clique em Install (Figura 2). Após a instalação,
poderá ser necessário reiniciar o NetBeans.
No NetBeans 6.1 não é preciso fazer nada: o suporte ao Spring já vem instalado
por padrão, sendo que o plugin mudou de nome para “Spring Web MVC Support”.

Figura 2. Seleção do plugin Spring Framework Support para instalação

Criando o projeto e adicionando suporte ao Spring


Com o NetBeans aberto, selecione File>New Project>Web>Web Application.
Preencha o Project Name, ex.: “VisualWebJM”. Altere Server para Apache Tomcat
6.0.14, conforme a Figura 3.
Figura 3. Criando o projeto de exemplo

Na terceira etapa, conforme ilustrado na Figura 4, selecione o framework Visual


Web JavaServer Faces. Altere o nome do pacote em Default Java Package e, em
Servlet URL Mapping, mude para “*.faces”.

Figura 4. Seleção dos frameworks que serão usados no projeto


Após a criação do projeto, adicione o suporte ao Spring Framework através do
botão direito do mouse sobre Libraries, em Add Library>spring-framework-2.5>Add
Library. O plugin que fora instalado possui as bibliotecas do Hibernate e do Spring.
Algumas bibliotecas podem estar faltando. Para adicioná-las, acesse
Tools>Libraries>Libraries e selecione spring-framework-2.5. Clique no botão Add
JAR/Folder e selecione as bibliotecas faltantes. No momento em que escrevo, foi
preciso adicionar as bibliotecas do Hibernate, que estão separadas em três
downloads diferentes: jboss-archive-browsing.jar, hibernate-validator.jar
(Hibernate EntityManager 3.3.1) e javassist.jar (Hibernate Core 3.2.5), que devem
ser baixadas no site oficial do Hibernate (veja a seção “Links”)
No NetBeans IDE 6.1, foram separadas as bibliotecas, sendo necessário instalar os
plugins Hibernate Support e Hibernate 3.2.5 Library. Além dos plugins, será
necessário adicionar as bibliotecas citadas anteriormente.

O banco de dados utilizado e seu driver JDBC


Utilizaremos como banco de dados o MySQL, que já possui o driver JDBC pré-
configurado com o NetBeans IDE (versão 6.0 ou superior). A Listagem 1 mostra o
script para a criação da tabela que será usada no exemplo.

Listagem 1. Script da criação da tabela no MySQL


CREATE TABLE contato(
id int NOT NULL auto_increment,
nome varchar(50),
email varchar(50),
nascimento date,
telefone varchar(20),
PRIMARY KEY id_contato(id)
);

Após criar o banco de dados no MySQL e sua respectiva tabela (veja o quadro
“Executando instruções SQL pelo NetBeans”), volte ao NetBeans, na janela
Services, e com o botão direito do mouse sobre Databases selecione New
Connection. Em Basic setting>Name selecione MySQL (Connector/J driver).
Preencha Database URL com o acesso ao seu banco de dados e, em seguida, com o
nome de usuário e senha (veja Figura 5).
Figura 5. Criação de uma nova conexão com o banco de dados

Executando instruções SQL pelo NetBeans


É possível gerar a tabela pelo NetBeans executando o script da Listagem 1. Para
isso, siga os passos descritos a seguir:
1. Através da janela Services, em Databases, vá com o direito do mouse sobre
a conexão criada e selecione Connect;
2. Com o direito do mouse sobre Tables>Execute Command, digite o script da
tabela na janela SQL Command 1 e clique no botão Run SQL(Ctrl+Shift+E);
3. Verifique a saída na janela Output>SQL Command 1 Execution;
4. Para exibir a tabela criada em Services>“Sua conexão”>Tables, clique
novamente com o direito e selecione Refresh.

Por fim, será necessário adicionar o driver JDBC do MySQL ao projeto. Com o botão
direito do mouse em Libraries, selecione Add Library>MySQL JDBC Driver>Add
Library.
Criando a entidade Contato
Sem aprofundar na JPA, para o exemplo, teremos apenas uma entidade, chamada
de Contato, que será criada por um assistente do NetBeans. Acesse File>New
File>Persistence>Entity Classes from Database e, na segunda etapa do assistente,
selecione New Data Source, em Data Source. A caixa de diálogo será semelhante à
Figura 6. Dê um nome qualquer em JNDI Name, uma vez que mais adiante esta
informação será substituída. Selecione a conexão que foi criada anteriormente em
Database Connection e confirme.

Figura 6. Criação de um novo Data Source

Retornando ao assistente, teremos a tabela contato sendo exibida na coluna


Available Tables. Selecione-a e clique em Add > para colocá-la em Selected Tables
para avançar. Na última etapa do assistente, ilustrada pela Figura 7, observe que
em Class Names>Class Name há o nome da classe que será criada, que no caso é
Contato. Altere o nome do pacote, ex.: javamagazine.entity.
Figura 7. Criando uma entidade persistente

Por ser a primeira entidade persistente do projeto, o assistente exibe o botão


Create Persistence Unit. Acione este botão, ao qual exibirá a caixa de diálogo da
Figura 8.

Figura 8. Criando uma Unidade de Persistência

Uma Persistence Unit (Unidade de Persistência) é um conjunto de configurações de


persistência da JPA; toda entidade deve pertencer a uma P.U. Você pode
determinar qual nome quer dar à sua unidade de persistência, ex.: JavaMagazine.
O provedor JPA utilizado será o Hibernate, que já está selecionado graças ao plugin
Spring Framework, que adicionou suas bibliotecas ao projeto. Para o Data Source,
mantenha o criado para o exemplo e confirme no botão Create.
A Listagem 2 exibe o POJO, incluindo a anotação @GeneratedValue, que não é
adicionado pelo assistente. Incluímos manualmente esta anotação, pois desejamos
que o valor da chave-primária seja criado de forma automática.
Listagem 2. Código da entidade Contato
package javamagazine.entity;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;

@Entity
@Table(name = "contato")
public class Contato implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;
@Column(name = "nome")
private String nome;
@Column(name = "email")
private String email;
@Column(name = "nascimento")
@Temporal(TemporalType.DATE)
private Date nascimento;
@Column(name = "telefone")
private String telefone;

//getters and setters


}

Ao criar a entidade, o NetBeans também adicionou o arquivo de configuração da


persistência ao seu projeto em Configuration Files>persistence.xml. Altere-o como
mostrado na Listagem 3.

Listagem 3. Configuração do arquivo persistence.xml


<?xml version="1.0" encoding="UTF-8"?>
<persistence ...>
<persistence-unit name="JavaMagazine">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.archive.autodetection"
value="class, hbm" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQLInnoDBDialect"/>
<property name="hibernate.connection.driver_class"
value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost/javamagazine" />
<property name="hibernate.connection.username"
value="root" />
<property name="hibernate.connection.password"
value="" />
</properties>
</persistence-unit>
</persistence>

Acessando os dados
Embora o Spring sempre tenha suportado o trabalho com persistência de dados por
outras tecnologias de mapeamento objeto-relacional (ORM), tal tarefa sempre
necessitou do conhecimento específico da biblioteca de persistência em questão. A
JPA melhora a portabilidade das aplicações, pois várias ferramentas ORM
implementam sua API padronizada. Além disso, a injeção de dependências permite
implementar o padrão DAO sem a necessidade de muitas classes, evitando o uso de
“fábricas” de objetos para isolar as implementações das interfaces.
Sobre o projeto, com o direito selecione New>Java Class. Preencha o nome da
classe ContatoDaoImp e o pacote javamagazine.dao. Altere a classe como
mostra a Listagem 4.

Listagem 4. A classe DAO


package javamagazine.dao;

import java.util.List;
import javamagazine.entity.Contato;
import javax.persistence.*;
import org.springframework.transaction.annotation.*;

@Transactional(readOnly = true)
public class ContatoDaoImp {

private EntityManager entityManager;

@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}

protected EntityManager getEntityManager() {


return entityManager;
}

@Transactional(readOnly = false)
public Contato save(Contato contato) {
this.entityManager.persist(contato);
return (Contato) contato;
}

@Transactional(readOnly = false)
public void delete(Contato contato) {
if (!this.entityManager.contains(contato)) {
contato = this.entityManager.merge(contato);
}
this.entityManager.remove(contato);
}

@Transactional(readOnly = false)
public void update(Contato contato) {
this.entityManager.merge(contato);
}

public List<Contato> findAll() {


Query q = this.entityManager.createQuery("SELECT c FROM Contato c");
return q.getResultList();
}
}

Após a alteração da classe, com o direito sobre ela, acione Refactor>Extract


Interface. Selecione as opções mostradas na Figura 9 e clique no botão Refactor.

Figura 9. Extraindo a interface da classe ContatoDaoImp

A Listagem 3 contém o código do nosso DAO, com a adição das anotações


referentes ao Spring Framework. Com @Transactional, a classe fará o controle
transacional, e com o elemento <tx:annotation-driven /> no contexto da
aplicação, o Spring examinará todos os beans que contenham esta anotação.
Declarar a transação com o atributo readOnly=true (somente leitura) indica que
esta só fará leituras de dados. O atributo propagation indica o tipo de propagação
da transação.
Com a anotação @PersistenceContext, o Spring injeta um EntityManager no
serviço quando for instanciado. Esta anotação pode ser colocada no atributo ou
método setter. Graças a esta injeção, você possui um comportamento similar ao
oferecido pelo EJB 3, incluindo transações, só que sem a necessidade de um
contêiner EJB para isso. Capacitado pelo Spring de efetuar commit ou rollback nas
transações de forma transparente e no momento adequado, a aplicação adquire
uma das grandes vantagens que um EJB tem, só que rodando num contêiner web
simples e leve como o Tomcat.
Configurando o Spring
Com a criação do DAO, o Spring precisará ser configurado para que o acesso a
dados se apóie nos recursos do framework.
Com o botão direito sobre WEB-INF, em Projects, acesse New>Other. Selecione
Spring Framework>Spring Beans Context file e prossiga. Altere para
applicationContext em File Name na segunda etapa. Na terceira etapa do
assistente, selecione o Namespace exibido na Figura 10 e confirme.

Figura 10. Seleção do namespace do arquivo de configuração do Spring


Framework

O assistente adicionará automaticamente os Namespaces utilizados pelo Spring em


seu arquivo de configuração. Resta configurar os beans que serão utilizados para
que o Spring possa gerir as transações e informá-lo da classe que será usada para
a injeção de dependências.
Para a execução em ambientes Java EE, utilizamos a factory
org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean:

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="JavaMagazine" />
</bean>

Com a propriedade de LocalContainerEntityManagerFactoryBean especificamos


o nome da persistence unit do arquivo persistence.xml. É neste arquivo que temos
as configurações de acesso ao banco de dados pela JPA para realizar as operações
de persistência.
Para a configuração do controle transacional em uma aplicação baseada no Spring,
é necessário declarar um gerenciador. Neste caso, a classe
org.springframework.orm.jpa.JpaTransactionManager é utilizada para
trabalhar com a JPA, independente de provedor. A declaração da classe é ilustrada
no trecho a seguir:

<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

JpaTransactionManager precisa de qualquer implementação de


javax.persistence.EntityManagerFactory para colaborar com EntityManager
produzido pela fábrica, para conduzir transações. O JpaTransactionManager é
recomendado para aplicações que utilizam apenas uma EntityManager.
Para que não tenhamos que fazer injeção de dependência do EntityManager em
todos os nossos DAOs, utilizamos a classe
org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProc
essor, que procura todas as classes anotadas com @PersistenceContext e faz a
injeção de dependência automaticamente:

<bean

class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProces
sor" />

A Listagem 5 exibe o arquivo de configuração do Spring que será utilizado pela


aplicação. Note que o bean contatoDao não contém referência ao bean
entityManagerFactory. O elemento <tx:annotation-driven> foi utilizado porque
configuramos as transações no DAO com a anotação @Transactional.

Listagem 5. Configuração do Spring para o exemplo


<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<!-- Responsavel pela gestao das entidades -->
<bean id="entityManagerFactory"

class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="JavaMagazine" />
</bean>

<!-- Responsavel pela injecao do EntityManager nas classes


que usam a anotacao @PersistenceContext -->
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProces
sor" />

<!-- Responsavel pela gestao das transacoes -->


<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<!-- Marcacao de transacoes atraves de anotacoes -->


<tx:annotation-driven />

<bean id="contatoDao"
class="javamagazine.dao.ContatoDaoImp">
</bean>

</beans>

Para iniciar o Spring com a aplicação, o arquivo applicationContext.xml deverá ser


registrado por um listener em web.xml:

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

Para trabalhar com JPA, o Spring também fornece mais configurações. Caso queira
expandir mais adiante o exemplo, criando relacionamentos para outras entidades, é
importante entender que, como estamos trabalhando com o Hibernate, em alguns
casos você poderá utilizar a estratégia Lazy. Quando a aplicação termina de ler os
dados desta estratégia, a sessão é fechada, lançando uma exceção do tipo
LazyInitializationException caso alguma associação da entidade seja lida
posteriormente. Isso significa que temos de deixar a sessão do Hibernate aberta ou
inicializar todos os relacionamentos antes de renderizar a página. Ambas opções
podem causar problemas importantes de consumo de recursos do SGBD (como
conexões) ou de desempenho. Para evitar estes problemas, no Hibernate,
utilizamos um padrão chamado de "Open Session in View". Quando um servidor
web recebe uma requisição, esta é automaticamente filtrada pelo
Interceptador/Filtro, podendo executar qualquer código antes e depois da mesma.
Embora o exemplo deste artigo não trate de relacionamentos, muito menos sobre a
estratégia Lazy, é importante comentar que, no uso de JPA, teríamos que criar um
padrão semelhante para EntityManager1[1]. O Spring possui um filtro que
trabalha sobre este conceito, criando um padrão "Open EntityManager in View",
que deve ser configurado em web.xml, conforme o trecho mostrado:

<filter>
<filter-name>openEntityManager</filter-name>
<filter-class>
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
</filter-class>
</filter>

Como alguns desenvolvedores podem não gostar do uso de Filtros para esta tarefa,
o Spring também possui um interceptador que faz o mesmo processo. A diferença
entre os dois é que o interceptador roda no contêiner Spring e é configurado em
applicationContext.xml, conforme o trecho mostrado:

<bean name="openEntityManagerInViewInterceptor"

class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor
">
...
</bean>

Para este artigo, iremos utilizar o Filtro, como exemplo, onde na Listagem 6 é
exibida toda a configuração que deve ser adicionada em web.xml.

Listagem 6. Configurando o Spring Framework em web.xml


<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>

<filter>
<filter-name>openEntityManager</filter-name>
<filter-class>
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
</filter-class>
</filter>

<filter-mapping>
<filter-name>openEntityManager</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

O controle de acesso
O Facade ContatoController (veja Listagem 7) é a classe responsável pela lógica
de negócios, delegando chamadas à camada de acesso a dados e controle
transacional. Este controle de transações será administrado pelo Spring, através da
injeção no atributo contatoDao. Esta classe terá a injeção do Spring no managed
bean para trabalhar com o JavaServer Faces.

Listagem 7. A classe ContatoController


package javamagazine.controller;

import java.util.List;
import javamagazine.dao.ContatoDao;
import javamagazine.entity.Contato;

public class ContatoController {

private ContatoDao contatoDao;

public ContatoDao getContatoDao() {


return contatoDao;
}

public void setContatoDao(ContatoDao contatoDao) {


this.contatoDao = contatoDao;
}

public void atualizar(Contato contato) {


contatoDao.update(contato);
}

public void salvar(Contato contato) {


contatoDao.save(contato);
}

public void excluir(Contato contato) {


contatoDao.delete(contato);
}

public List todos() {


return contatoDao.findAll();
}
}

Integrando o Visual Web JSF ao Spring


Para configurar o Spring de modo que ele possibilite se integrar ao JavaServer
Faces, é necessário adicionar o elemento variable-resolver, no arquivo faces-
config.xml, para chamar a classe DelegatingVariableResolver do framework:

<application>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
</application>

A classe DelegatingVariableResolver é capaz de resolver beans declarados no


Spring e injetá-los no managed bean de forma transparente. Esta injeção é
indicada com a sintaxe #{bean nomeado no Spring}, a mesma utilizada pelo
JSF para injetar dependências nos managed beans. Isso indica que nosso managed
bean deixa de ser responsável por instanciar o objeto que irá utilizar e passa a
recebê-lo do Spring. A Listagem 8 mostra o managed bean ContatoController
configurado em faces-config.xml.

Listagem 8. Configuração da integração do JSF com o Spring


<faces-config ...>
<application>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
</application>
<managed-bean>
<managed-bean-name>ContatoController</managed-bean-name>
<managed-bean-class>
javamagazine.controller.ContatoController
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>contatoDao</property-name>
<value>#{contatoDao}</value>
</managed-property>
</managed-bean>
<managed-bean>
<managed-bean-name>SessionBean1</managed-bean-name>
<managed-bean-class>javamagazine.SessionBean1</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>Page1</managed-bean-name>
<managed-bean-class>javamagazine.Page1</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>ApplicationBean1</managed-bean-name>
<managed-bean-class>javamagazine.ApplicationBean1</managed-bean-
class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>RequestBean1</managed-bean-name>
<managed-bean-class>javamagazine.RequestBean1</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>

Acessando o Facade pelo Visual Web JSF


Para acessarmos a classe ContatoController, e seus métodos através do Design
do Visual Web JSF, serão necessários alguns passos a mais do que comumente
seria se estivéssemos trabalhando com instruções SQL diretamente, através do uso
direto de JDBC disponível pela ferramenta. Como o padrão do Visual Web JSF é
trafegar em um escopo de sessão (veja no quadro “Os escopos de uma aplicação
com Visual Web JSF”), vamos abrir a classe SessionBean1 para fazer esta
integração.
Através do arquivo Page1.jsp, em Design, dê um duplo clique em
Navigation>SessionBean1. Como estamos usando JPA, e não acesso direto ao
banco de dados, será preciso converter os dados para que estes se tornem
acessíveis visualmente pelo Visual Web JSF. Para o caso, os dados foram
convertidos em Array, tornando-os acessíveis ao componente Table visualmente. O
acesso à classe ContatoController será feito através do método getBean(), de
com.sun.rave.web.ui.appbase.FacesBean, uma classe da biblioteca do Visual
Web. Este método retorna qualquer atributo armazenado em um escopo de sessão
sob o nome especificado. Desta forma, será possível manipular os métodos
existentes na classe determinada, como no caso de ContatoController.
Como temos apenas um formulário para manipular os contatos (cadastro e
alteração), haverá a necessidade de armazenar a identificação do contato
selecionado no componente Table. Claro que o campo escolhido é o id do contato,
que será armazenado em sessão para resgatarmos no momento de salvarmos os
dados alterados.
Para finalizar, nas alterações desta classe, adicione no método void init() uma
chamada ao método todosContatos(). O método init() inicializa o que houver em
seu escopo antes do carregamento do aplicativo e antes de componentes
gerenciados serem inicializados (ver Listagem 9). Em outras palavras, a página do
aplicativo obterá os dados encontrados no banco, podendo preencher a tabela com
os contatos existentes antes desta ser renderizada. Ao salvar as alterações, vá ao
menu Build>Build Main Project para compilar as classes. Esse passo é importante
para que torne essas alterações na classe acessíveis visualmente pelo Design.

Listagem 9. Alterações na classe SessionBean1


package javamagazine;

import com.sun.rave.web.ui.appbase.AbstractSessionBean;
import javamagazine.controller.ContatoController;
import javamagazine.entity.Contato;
import javax.faces.FacesException;

public class SessionBean1 extends AbstractSessionBean {

// omitidos por não haver alterações...

public void init() {


// omitidos por não haver alterações...

todosContatos();
}

// omitidos por não haver alterações...

protected ContatoController getContatoController() {


return (ContatoController) getBean("ContatoController");
}

//array de Contato
private Contato[] contatos;

public Contato[] getContatos() {


return contatos;
}

public void setContatos(Contato[] contatos) {


this.contatos = contatos;
}
//carrega todos os contatos
public void todosContatos() {
contatos = (Contato[]) getContatoController().
todos().toArray(new Contato[0]);
}

//transporta em sessão o ID selecionado para atualização


private Integer id = null;

public Integer getId() {


return id;
}

public void setId(Integer id) {


this.id = id;
}
}

Os escopos de uma aplicação com Visual Web JSF


Ao criar um projeto com o framework Visual Web JSF, dentro do pacote padrão, são
colocadas três classes que representam os escopos da aplicação. Quando a
aplicação é executada em um servidor, esta consiste de vários objetos cujos ciclos
de vida dependem do escopo. Um exemplo comum é uma página, que possui
escopo de requisição. Entretanto, há casos que precisamos de um tempo maior,
onde há uma comunicação com o servidor para que este possa saber que o usuário
ainda permanece naquele estado. Este é um caso de um carrinho de compras, por
exemplo. Enquanto o usuário permanecer na página comprando, haverá o
preenchimento do carrinho até que seja esvaziado ou a página seja fechada. Este é
um escopo de sessão, que dura enquanto a “sessão” estiver aberta (ou o
navegador). Por padrão, a menos que seja alterado nas configurações do NetBeans,
os dados trafegam em um escopo de sessão. É evidente que isso pode ser alterado,
utilizando um escopo de requisição através da classe RequestBean1.
A classe ApplicationBean1 possui uma estrutura parecida com SessionBean1,
contendo objetos com um escopo de aplicação.

Desenvolvendo a página
O Visual Web JSF possui diversos componentes que podem ser acessados através
da janela Palette. Se você já trabalhou com ferramentas visuais como Delphi, Visual
Studio .NET ou até mesmo com o próprio editor visual de aplicações Swing do
NetBeans, perceberá que o Visual Web JSF é semelhante. A Figura 11 representa
o resultado final do desenho da página, cuja criação explicamos passo a passo a
seguir.
Figura 11. Desenho da aplicação

1. Arraste da janela Palette o componente Static Text para o Design da página.


Posicione-o e digite “Cadastro de Contatos”;
2. Insira quatro componentes Label na página, um abaixo do outro e os alinhe.
Na janela Properties, digite em text os seguintes rótulos: “Nome:”, “E-mail:”,
“Telefone:” e “Nascimento:”;
3. Arraste quatro componentes Text Field, ao lado de cada um dos rótulos
inseridos. Altere a propriedade id na seqüência: “nome”, “email”, “telefone” e
“nascimento”;
4. Pressionando <Shift>, selecione com um clique cada, os componentes:
“nome” e “email”. Na janela Properties altere columns para 40;
5. Selecione o Text Field “nascimento” e em Properties altere Converter>(New
DateTimeConverter)2[2];
6. Na janela Navigator expanda Page1 e selecione dateTimeConverter1. Altere
timezone para o seu fuso horário, ex.: America/Sao_Paulo;
7. Adicione o componente Button na página e altere sua propriedade id para
“btSalvar” e text para “Salvar”;
8. Para finalizar, adicione o componente Message Group logo abaixo do
formulário.

Exibindo os contatos
Para exibir os contatos, utilizaremos o componente Table, que será arrastado para
a página abaixo do formulário criado, conforme a Figura 11.
Com o botão direito do mouse, selecione Table Layout no menu de contexto. Na
caixa de diálogo (veja Figura 12), altere para contatos em Get Data From. Caso
esta opção não esteja sendo exibida, faça o “build” na classe SessionBean1.
Figura 12. Definindo o layout da tabela

Na caixa Selected surgirão os campos de Contato. Selecione cada um e alterando


sempre em Column Detail>Header Text o rótulo do cabeçalho que representa cada
coluna na tabela. Mude a ordem das colunas conforme a Figura 11, utilizando os
botões Up e Down.
Adicione duas novas colunas através do botão New. Altere Header Text e Value
Expression do primeiro para “Editar” e do segundo para “Excluir”. Em Component
Type mude para Hyperlink. As colunas adicionadas serão links que executarão
comandos. As demais existentes são componentes estáticos (Static Text).
Na guia Options altere Title para “Lista de Contatos”. Confirme as mudanças
clicando em OK.
Na tabela, selecione o texto estático da coluna “Nascimento” e altere a propriedade
Converter>dateTimeConverter1, conforme aponta a Figura 13. Perceba que este
conversor é o mesmo utilizado para o campo Text Field “nascimento” do formulário.
Este conversor tornará a representação da data pelo browser diferente da forma
original encontrada no objeto java.util.Date.
Figura 13. Texto estático da coluna nascimento selecionado e alteração do
converter

Você poderá dimensionar a largura da coluna arrastando, bastando somente


selecionar o título da mesma. A propriedade width poderá ser usada caso queira
maior precisão.

Adicionando código aos componentes


Agora que temos a parte visual definida, nos resta adicionar a lógica para fazê-la
funcionar. Dê um duplo clique no link Editar da tabela de sua página. Ao fazer esta
ação, perceba que o Visual Web JSF o colocou em Java, na classe Page1.java, que
é o bean de Page1.jsp. Automaticamente foi gerado um código, que representa o
método que será invocado pelo link:

public String hyperlink1_action(){


return null;
}

Ao mesmo tempo, se colocar em JSP, verá que também foi adicionado o atributo
actionExpression="#{Expressão}" em <webuijsf:hyperlink>. Isso significa
que ao clicar no link Editar, automaticamente você invocará os eventos
determinados no método hyperlink1_action(). No Design, podemos ver em
Properties>Events>action.
No NetBeans 6.1, alguns passos a mais serão necessários para trabalhar com os
componentes que estamos utilizando neste exemplo. Clique com o direito do
mouse, na janela Navigator, em table1>tableRowGroup1 e selecione Add Binding
Attribute no menu de contexto. O mesmo deverá ser feito para os TextFields:
nome, email, telefone e nascimento.
Retornando para Java, adicione o código da Listagem 10 para o link Editar do
componente Table.

Listagem 10. Código do link Editar


//link Editar do componente Table
public String hyperlink1_action() {
//pega a linha selecionada
RowKey rowKey = getTableRowGroup1().getRowKey();
//armazena o id do contato
getSessionBean1().setId(Integer.parseInt(rowKey.getRowId()));
//retorna null por não haver navegação
return null;
}

Retorne para o Design e dê um duplo clique agora sobre o link Excluir da tabela.
Adicione o código da Listagem 11. Em seguida, faça o mesmo procedimento com
o botão Salvar do formulário e altere como na Listagem 12.

Listagem 11. Código do link Excluir


//link Excluir do componente Table
public String hyperlink2_action() {
try {
//captura a linha atual do link de exclusão clicado
RowKey rowKey = getTableRowGroup1().getRowKey();
if (rowKey != null) {
Contato[] contatos = getSessionBean1().getContatos();
Integer id = Integer.parseInt(rowKey.getRowId());
//seleciona somente o contato que será removido
Contato contato = contatos[id];
//chama o controller para excluir o contato selecionado
getSessionBean1().getContatoController().excluir(contato);
//limpa o ID de SessionBean1 caso esteja com valor
getSessionBean1().setId(null);
}
//limpa os campos existentes
//caso esteja preenchidos
nome.setText(null);
email.setText(null);
nascimento.setText(null);
telefone.setText(null);
//informa ao usuário a exclusão
info("Contato excluído!");
} catch (Exception ex) {
//exibe o erro ao usuário
info("Erro encontrado: " + ex);
}
//retorna nulo por não mudar de página
return null;
}

Listagem 12. Código do botão Salvar


//botão Salvar do formulário
public String btSalvar_action() {
Integer id = getSessionBean1().getId();
//se houver algo em edição
if (id != null) {
Contato[] contatos = getSessionBean1().getContatos();
//seleciona somente o contato que será editado
Contato contato = contatos[id];
//altera seus valores em Contato
contato.setNome(nome.getText().toString());
contato.setEmail(email.getText().toString());
contato.setNascimento((java.util.Date) nascimento.getText());
contato.setTelefone(telefone.getText().toString());
//chama a atualização de ContatoController
getSessionBean1().getContatoController().atualizar(contato);
//limpa o ID de SessionBean1 caso esteja com valor
getSessionBean1().setId(null);
//informa que foi atualizado ao usuário
info("Contato atualizado!");
} else { //caso seja um novo registro
//cria um novo Contato
Contato contato = new Contato();
//atribui a este contato os valores definidos
//nos campos do formulário da página
contato.setNome(nome.getText().toString());
contato.setEmail(email.getText().toString());
contato.setNascimento((java.util.Date) nascimento.getText());
contato.setTelefone(telefone.getText().toString());
//salva pelo método de ContatoController
getSessionBean1().getContatoController().salvar(contato);
//informa que foi salvo ao usuário
info("Contato salvo!");
}
//limpa os campos existentes
//caso esteja preenchidos
nome.setText(null);
email.setText(null);
nascimento.setText(null);
telefone.setText(null);

return null;
}

Para manipular um componente Table, o Visual Web JSF utiliza a classe


TableDataProvider, um provedor de dados próprio, que fornece acesso a um
conjunto de informações organizadas por linhas-chaves. Uma estratégia utilizada
por TableDataProvider é armazenar a chave primária da fonte de dados dentro
de um objeto RowKey. Nas Listagens 10 e 11 temos a manipulação do objeto
com.sun.data.provider.RowKey, que é um índice em uma linha de dados de um
componente Table.
Muitos dos métodos para manipular a linha de dados, fornecida pela tabela, usam
RowKey para sua identificação. Para conseguir a linha selecionada, chamamos o
método getRowKey(), do objeto tableRowGroup1 (o nome do grupo do
componente Table inserido na página), através de getTableRowGroup1(), onde
obtemos o RowKey.
Com o método String getRowId(), obtemos o valor de identificação da linha,
necessário para identificar qual contato será excluído ou editado. Para a exclusão, o
array contatos, encontrado em SessionBean1, é utilizado para retornar somente
um objeto Contato, que é transmitido ao método excluir() de
ContatoController.
No caso da edição, este valor é transmitido pela classe SessionBean1, através do
atributo id, para que o mesmo possa ser recuperado durante o ciclo de exibição dos
dados no formulário e sua conseqüente submissão para alteração.
Já no botão Salvar, temos duas tarefas a cumprir na submissão do formulário:
atualizar ou adicionar dados. O método btSalvar_action(), chamado pelo botão,
fará uma verificação se há em sessão o id do contato que será atualizado. Se
houver, transmite os valores do formulário para Contato e chama o método
atualizar() de ContatoController. No caso de salvar, simplesmente é criado um
novo objeto Contato, que receberá os valores do formulário e seqüencialmente
será transmitido para salvar() de ContatoController.
Para a manipulação dos campos do formulário, perceba que utilizamos o método
getText(), que retorna java.lang.Object, para recuperar os dados encontrados
em cada um dos componentes Text Field. O método setText() fora utilizado para
transmitir valores nulos com o intuito de limpar os campos após sua utilização.
O componente Message Group é chamado, através do método info(), nas
operações de salvar, excluir e atualizar, para informar ao usuário se a operação foi
executada com sucesso.
Para finalizar, na edição dos dados, precisamos antes preencher o formulário. Note
que o link Editar da tabela possui apenas algumas linhas, transmitindo o id apenas
do contato selecionado. Para que o formulário funcione para edição, teremos que
captar este valor antes da página ser renderizada e transmiti-lo, através de
Contato, preenchendo cada campo separadamente. É exatamente este o papel do
método “Callback” prerender(), exibido na Listagem 13, com o código necessário
para tal operação. Além do papel fundamental que o método prerender() tem
para a edição dos dados, este também será responsável por sincronizar o
componente Table com os dados encontrados no banco de dados, sempre que
houver uma operação sobre os mesmos. Isso será feito chamando o método
todosContatos() de SessionBean1.

Listagem 13. Código do método prerender()


public void prerender() {
//capta o id armazenado em SessionBean1
Integer id = getSessionBean1().getId();
//se não for nulo, é porque está em edição
if (id != null) {
//capta os contatos
Contato[] contatos = getSessionBean1().getContatos();
//filtra somente o selecionado para edição
Contato contato = contatos[id];
//preenche os campos do formulário
nome.setText(contato.getNome());
email.setText(contato.getEmail());
nascimento.setText(contato.getNascimento());
telefone.setText(contato.getTelefone());
}
//atualiza todos os contatos
//para o componente Table
getSessionBean1().todosContatos();
}
Customizando a saída na janela Output
A biblioteca de logging Log4j permite gerar uma saída organizada do que está
acontecendo com a aplicação. Para fazê-lo, com o direito sobre Source Packages
selecione New>Other. Em New File>Other>Properties File, clique no botão Next.
Preencha com log4j em File Name e confirme. A Listagem 14 exibe o arquivo
log4j.properties. Ao executarmos a aplicação dentro do NetBeans, os logs serão
exibidos pela janela Output.

Listagem 14. Arquivo log4j.properties


log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L
- %m%n
log4j.rootLogger=debug, stdout
log4j.logger.org.hibernate=debug
log4j.logger.org.hibernate.hql=on
log4j.logger.org.springframework = info

Conclusões
Neste artigo foi mostrado que o Visual Web JSF possui flexibilidade para trabalhar
com outros frameworks, através de um exemplo prático utilizando o Spring, o
Hibernate e a JPA.
Aprendemos também que o Spring Framework, suportado mais facilmente pelo
NetBeans através de um plugin, simplificou seu desenvolvimento com anotações,
integrando suavemente com a JPA, com pouca escrita em arquivo XML.
Um fator importante no trabalho com Visual Web JSF é sua facilidade de desenhar
aplicações JavaServer Faces, com componentes arrastáveis no estilo WYSIWYG, o
que poupa muito trabalho do desenvolvedor. Embora suas configurações sejam
visuais, compreender a estrutura do JavaServer Faces para trabalhar com o Visual
Web JSF é importantíssimo, mesmo tendo a grande maioria de seus componentes
específicos à ferramenta.
Vimos também que é simples integrar o Visual Web a outras tecnologias, mesmo as
que carecem de suporte direto. Assim, você não fica limitado a usar componentes,
bibliotecas ou frameworks que sejam suportados “de fábrica” pelo Visual Web –
mesmo o desenvolvimento visual pode ser habilitado para componentes de
terceiros.