NetBeans Visual Web JSF

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

Transcript of NetBeans Visual Web JSF

Page 1: NetBeans Visual Web JSF

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

Page 2: NetBeans Visual Web JSF

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.

Page 3: NetBeans Visual Web JSF

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

Page 4: NetBeans Visual Web JSF

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).

Page 5: NetBeans Visual Web JSF

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.

Page 6: NetBeans Visual Web JSF

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.

Page 7: NetBeans Visual Web JSF

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" />

Page 8: NetBeans Visual Web JSF

<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);

Page 9: NetBeans Visual Web JSF

}

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.

Page 10: NetBeans Visual Web JSF

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"

Page 11: NetBeans Visual Web JSF

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">

Page 12: NetBeans Visual Web JSF

</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

">

Page 13: NetBeans Visual Web JSF

...

</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;

Page 14: NetBeans Visual Web JSF

}

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>

Page 15: NetBeans Visual Web JSF

<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

Page 16: NetBeans Visual Web JSF

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;

}

Page 17: NetBeans Visual Web JSF

//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.

Page 18: NetBeans Visual Web JSF

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.

Page 19: NetBeans Visual Web JSF

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.

Page 20: NetBeans Visual Web JSF

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

Page 21: NetBeans Visual Web JSF

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];

Page 22: NetBeans Visual Web JSF

//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

Page 23: NetBeans Visual Web JSF

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();

}

Page 24: NetBeans Visual Web JSF

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.