Você está na página 1de 37

Desenvolvendo um CRUD para Web com Java, PostgreSQL e Netbeans

Bom, neste tpico iremos direto ao assunto. Meu objetivo demonstrar a criao de um CRUD em poucos passos, utilizando Java com recursos de JPA, JSF na arquitetura MVC. Por que construir um CRUD? Em termos de desenvolvimento, um CRUD estabelece os procedimentos bsicos operacionais para um componente de um sistema. Por componente, utilizando orientao a objetos, entendemos como um objeto pertencente ao modelo (um Cliente, um Produto, por exemplo). Por procedimentos bsicos, entendemos como as operaes de incluso (create), seleo (read), atualizao (update) e excluso (destroy) associadas a um desses objetos. Todo sistema possui seus CRUDs. Ao mostrar um exemplo de criao de CRUD, temos base para a criao de vrias etapas de um sistema. Mais detalhes podem ser vistos em: http://pt.wikipedia.org/wiki/CRUD Por que utilizar a linguagem Java? Hoje, em grande maioria, quando se fala em sistemas, se fale em desenvolvimento web. Com a Web 2.0 o desenvolvimento de sistemas para Web se intensificou ao ponto de chegarmos a detalhes de produo e qualidade muito prximos aos sistemas cliente-servidor. Dentre as linguagens atuais, o Java se destaca pelo conjunto de Frameworks que oferecem um desenvolvimento sustentvel, com muitas facilidades de manuteno. O .Net (com o C#) tambm excelente para grandes projetos. O PHP tambm no pode ser esquecido, porm sua manuteno no to favorecida. Enfim, Java tambm livre e aberto, dando um ponto forte para minha escolha. Voc poder baixar o Java em: http://www.sun.com/ Por que utilizar JPA? O JPA, na verso 3 do EJB, indiscutivelmente o Framework mais poderoso da atualidade (em minha singela opinio). Atravs das diversas possibilidades oferecidas pelo JPA, utilizaremos um pequeno, mas fantstico escopo de persistncia. Em essncia, trabalha-se com anotaes JPA, integradas aos Beans. Essas caractersticas sero melhores discutidas nos exemplos apresentados. Mais detalhes em: http://java.sun.com/developer/technicalArticles/J2EE/jpa/ Por que trabalhar com JSF? O Java ServerFaces uma das mais atuais alternativas para se construir a camada view da aplicao web. Ela permite ao desenvolvedor utilizar tags especficas, sem nenhuma codificao nativa em Java (scriptles) no arquivo jsp. As pginas dinmicas ficam ligadas diretamente aos Beans. A produtividade favorecida e a manuteno facilitada, como veremos. Veja mais detalhes em: http://java.sun.com/javaee/javaserverfaces/ Por que utilizar a arquitetura MVC? A arquitetura MVC (tambm estendida para MVCP, sendo o P de persistence) amplamente utilizada como padro de desenvolvimento. O model (M) define o comportamento do sistema, implementando os Beans, tambm conhecidos como Pojo (Plain Old Java Object). O view (V) define a camada de visualizao (onde utilizaremos o JSF). O controller (C) define as regras de negcio da aplicao pode-se utilizar os Beans de Sesso fornecidos pelo EjB3. No trabalharemos com esses tpicos neste estudo. Vamos utilizar uma camada isolada do modelo e da apresentao.

Referncia: http://pt.wikipedia.org/wiki/MVC Por que utilizar o Netbeans? Deve-se atentar para a seguinte questo: Netbeans, Eclipse, JBuilder, JCompany, entre outras, so excelentes IDEs de desenvolvimento para aplicaes Java, mas a grande jogada no so as IDEs, e sim o Java. O que quero dizer o seguinte: cada desenvolvedor trabalha com a IDE que mais se adaptar, ou o que for estabelecido em sua empresa. Todos so bons, porm, possvel chegar aos mesmos resultados em todos eles. Uns fornecem algumas facilidades, mas podemos produzir os mesmos resultados com qualquer um deles. Escolhi o Netbeans neste estudo por sua facilidade em relao ao Java. No precisaremos instalar plugins. Alm do fato dele ser livre. Portanto, no tome esse tutorial como um modelo de produo onipresente. Podemos produzir o mesmo resultado na unha configurando os diretrios no container, bibliotecas e arquivos Java nos comandos do prompt, se a necessidade de ficarmos associados a nenhuma IDE. Pode-se baixar o Netbeans em: http://www.netbeans.org/ Por que utilizar o PostgreSQL? Todos os bancos livres so bons. Cada um com suas qualidades prprias. Fique vontade para trabalhar com outros bancos. O fato de se trabalhar com o JPA facilita ainda mais a transio de um banco para o outro. Precisamos apenas alterar a JAR e o arquivo de configurao persistence.xml. O SQL apresentado poder tambm ser facilmente adaptado, pois mantive uma certa flexibilidade no cdigo. Baixe o PostgreSQL em: http://www.postgresql.org/ Modelo a ser exemplificado Abaixo temos o modelo que ser abordado:

Faremos o sistema para Manter Telefones. A nica classe do modelo ser essa. Outras classes sero necessrias para compor a arquitetura. Ao final do desenvolvimento, teremos as classes de modelo (essa), as classes Data Access Object (para persistncia), as classes Business Object (para as regras de negcio) e as classes View (Beans para controle da interface com usurio e sesso). Entre elas, sero necessrias algumas interfaces Java para padres de projeto adequados ao exemplo. Para a criao deste diagrama, utilizei o Jude (http://jude.change-vision.com/judeweb/index.html ), que alm de facilitar a criao grfica do modelo, gera cdigo Java. Obs. Desconsidere a modelagem apresentada, pois o ideal seria termos um objeto Cliente relacionado com Telefone, mas como este um simples exemplo acadmico, temos s Telefone. Criao do banco de dados Os recursos de persistncia implementados pelo Toplink, oferecem um recurso de gerao automtica, porm, prefiro manter a implementao do banco manual. Desta forma, no futuro, quando mudarmos a linguagem, o paradigma, nosso banco estar ntegro. Em alguns casos, o modelo referencial gerado automaticamente no fica, digamos, totalmente relacional.

Abaixo temos o SQL de gerao da tabela. O nome do banco mycrud e a codificao UTF8.
create table telefones ( id integer not null, ddd char(2) not null, numero char(8) not null, nome varchar(40) not null, constraint pk_telefones primary key (id) );

Observe que, por opo, no criaremos um auto-incremento no banco. Isto ser gerenciado pelo prprio Toplink. Portanto, ser necessria a criao da tabela e insero abaixo.
CREATE TABLE SEQUENCE (SEQ_NAME VARCHAR(50) NOT NULL, SEQ_COUNT DECIMAL(38), PRIMARY KEY (SEQ_NAME)); INSERT INTO SEQUENCE(SEQ_NAME, SEQ_COUNT) values ('SEQ_GEN', 1);

Essa tabela utilizada para controlar o auto-incremento, independente do banco. Criada essas duas tabelas, poderemos partir para o desenvolvimento. Alguns detalhes importantes so: o usurio e senha do meu banco so, respectivamente, pgadmin e pgadmin vamos precisar dessa informao para a criao do arquivo persistence.xml. Utilizei a ferramenta phpPgAdmin para a criao do banco e gerao das tabelas (http://phppgadmin.sourceforge.net/). Criao do Projeto no Netbeans Detalhes: Estamos trabalhando com a verso 6.1 do Netbeans, o container Tomcat 6.0.16 e o JEE 5. Em primeiro lugar, recomendo que todos os outros projetos que estejam abertos no Netbeans sejam fechados s por questo de organizao. Abaixo temos os passos necessrios para a criao do projeto.
1. Clique em Arquivo, Novo Projeto... 2. Na janela Novo Projeto, dentro da aba Categorias, selecione a opo Web. Na aba Projetos, 3. 4. 5. 6. 7. 8. 9.

selecione a opo Aplicao Web Clique em Prximo Em Nome do projeto, defina o valor mycrud Clique em Prximo Em Servidor, selecione a opo Apache Tomcat 6.0.16 Clique em Prximo Na aba Frameworks, marque apenas a opo JavaServer Faces Clique em Finalizar

Neste ponto, teremos nosso projeto Web criado. Vamos acrescentar a opo de persistncia de dados JPA com a sequncia abaixo.
1. Na aba Projetos ( esquerda da interface do Netbeans), clique com o boto direito no nome 2. 3. 4. 5. 6. 7. 8.

do projeto (mycrud), selecione a opo Novo, e o submenu Outro... Na aba Categorias, selecione Persistence Na aba Tipos de arquivos selecione a opo Unidade de persistncia Clique em Prximo Defina o valor de Nome da unidade de persistncia como default Em Conexo de banco de dados, selecione a opo Nova conexo com banco de dados... Em Nome, selecione a opo PostgreSQL Em URL do banco de dados, defina o valor jdbc:postgresql://localhost:5432/mycrud

9. Em Nome do usurio e Senha, defina respectivamente, pgadmin e pgadmin. Lembre-se que 10. 11. 12. 13. 14. 15.

meu banco est configurado com esse usurio. Faa suas adaptaes, se necessrio. Marque a opo Lembrar senha Clique em OK Em Selecione um esquema, selecione public Clique em OK Em Estratgia de gerao de tabela, marque a opo Nenhum Clique em Finalizar

Neste momento, o arquivo persistence.xml ser criado. Por enquanto, podemos fech-lo. Feche tambm o arquivo welcomeJSF.jsp. Posteriormente vamos exclu-lo. Vamos agora adicionar a biblioteca de conexo com o PostgreSQL.
1. 2. 3. 4.

Na aba Projetos, clique com o boto direito em Bibliotecas Selecione a opo Adicionar biblioteca... Selecione a opo PostgreSQL JDBC Driver Clique em Adicionar biblioteca

Vamos agora criar os pacotes Java.


1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19.

Na aba Projetos, clique com o boto direito em Pacotes de cdigos-fonte Clique na opo Novo, e no submenu Outro... Na aba Categorias, selecione a opo Java Na aba Tipos de arquivos, selecione a opo Pacote Java Clique em Prximo Em Nome do pacote, defina o valor model Clique em Finalizar Repita a sequncia de 1 ao 5 Em Nome do pacote, defina o valor persistence Clique em Finalizar Repita a sequncia de 1 ao 5 Em Nome do pacote, defina o valor controller Clique em Finalizar Repita a sequncia de 1 ao 5 Em Nome do pacote, defina o valor view Clique em Finalizar Repita a sequncia de 1 ao 5 Em Nome do pacote, defina o valor util Clique em Finalizar

Observe que criamos cada uma das camadas do padro MVCP model, view, controller e persistence. Neste ponto, estamos prontos para comear a codificao Java (enfim...). Criao do Modelo camada Model O primeiro passo criar uma Inteface que ser implementada em todos os Pojos. Essa interface, alm de garantir a correta utilizao dos objetos nas prximas camadas, seria usado na gerao de componentes ComboBox. Neste projeto no criaremos nenhum, mas atravs dessa Interface isso seria possvel e facilitado (quem sabe em outros futuros artigos veremos tais detalhes...).
1. Na aba Projetos, clique com o boto direito em Pacotes de cdigos-fonte 2. Clique na opo Novo, e no submenu Outro...

3. 4. 5. 6. 7. 8.

Na aba Categorias, selecione a opo Java Na aba Tipos de arquivos, selecione a opo Interface Java Clique em Prximo Em Nome da classe, digite InterfacePojo Em Pacote, selecione a opo model Clique em Finalizar

Substitua todo o contedo do arquivo pelo cdigo abaixo:


// InterfacePojo.java

package model;
public interface InterfacePojo { public int getCode(); public void setCode(int code); public String getDescribe(); public void setDescribe(String describe); }

Lembre-se sempre de salvar as alteraes (menu Arquivo, opo Salvar todos). Vamos agora criar o Pojo (model) do objeto Telefone.
1. 2. 3. 4. 5. 6. 7. 8.

Na aba Projetos, clique com o boto direito em Pacotes de cdigos-fonte Clique na opo Novo, e no submenu Outro... Na aba Categorias, selecione a opo Java Na aba Tipos de arquivos, selecione a opo Classe Java Clique em Prximo Em Nome da classe, digite Telefone Em Pacote, selecione a opo model Clique em Finalizar

Substitua o contedo do arquivo pelo cdigo abaixo:


// Telefone.java package model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; @Entity(name = "Telefone") @Table(name = "telefones") @NamedQueries( { @NamedQuery( name="selectTelefone", query = "select obj from Telefone obj" ) } ) public class Telefone implements Serializable, InterfacePojo {

private static final long serialVersionUID = 1L; @Id @GeneratedValue @Column(name = "id") private int id; @Column(name = "ddd", nullable = false, length = 2) private String ddd; @Column(name = "numero", nullable = false, length = 8) private String numero; @Column(name = "nome", nullable = false, length = 40) private String nome; public void setId(int id) { this.id = id; } public int getId() { return id; } public String getDdd() { return ddd; } public String getNome() { return nome; } public String getNumero() { return numero; } public void setDdd(String ddd) { this.ddd = ddd; } public void setNome(String nome) { this.nome = nome; } public void setNumero(String numero) { this.numero = numero; } // Mtodos da InterfacePojo @Override public int getCode() { return this.getId(); } @Override public void setCode(int code) { this.setId( code ); } @Override public String getDescribe() { return this.getNome(); } @Override public void setDescribe(String describe) { this.setNome( describe ); } // Mtodos da InterfacePojo // Mtodos de formatao public String getNumeroFormatado() { return "(" + this.getDdd() + ") " + this.getNumero(); } // Mtodos de formatao }

Neste cdigo, devemos nos atentar nas anotaes EJB 3: @Entity usado para definir a entidade @Table usado para definir o nome da tabela no banco de dados @NamedQueries e @NamedQuery so usadas para definir a linguagem JPQL (Java Persistence Query Language) de acesso aos dados do banco. Observe que muito similar SQL, porm, aqui se trabalha com Orientao a Objetos. @Id Usado para definir que o atributo em questo, ser a chave primria na tabela @GeneratedValue Usado para definir automaticamente o valor do campo em questo @Column Usado para definir o nome do campo da tabela no qual este atributo est relacionado. Observe que existem as diretivas length e nullable que servem, respectivamente, para definir o tamanho mximo do campo e se o mesmo pode ser nulo.

@Override esta anotao usada para mostrar ao compilador que este mtodo dever ser utilizado ao invs do mtodo da Interface. Neste caso, obvio que estes mtodos sero usados (pois somos obrigados a implement-los por conta da InterfacePojo), mas mesmo assim, boa prtica de programao colocar o @Override nos casos em que um mtodo sobrescrito (polimorfismo). Atravs destes cdigos, o Objeto poder ser manipulado no banco pelo Toplink. O caso do @Override indiferente para o servio de persistncia. Observe tambm que, por se tratar de um Pojo, simples getters e setters so suficientes (e por padro, necessrios) para o cdigo. O modelo definido com classes neste design. O fato de o objeto ser Serializable e possuir o atributo serialVersionUID permite sua migrao entre Container's, com a aplicao de JNDI. No trabalharemos com esse recurso neste material. Veja mais em http://www.jspbrasil.com.br/mostrar/27 Salve as alteraes. Vamos agora alterar o arquivo de persistncia para que o objeto Telefone possa ser manipulado.
1. Na aba Projetos, no item Arquivos de configurao 2. D um duplo clique em persistence.xml 3. Insira o cdigo <class model.Telefone</class entre as tags </provider e <properties

O cdigo do arquivo ficar igual ao mostrado abaixo:


<?xml version="1.0" encoding="UT F-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="default" transaction-type="RESOURCE_LOCAL"> <provider>oracle.toplink.essentials.PersistenceProvider</provider> <class>model.T elefone</class> <properties> <property name="toplink.jdbc.user" value="pgadmin"/> <property name="toplink.jdbc.password" value="pgadmin"/> <property name="toplink.jdbc.url" value="jdbc:postgresql://localhost:5432/mycrud"/> <property name="toplink.jdbc.driver" value="org.postgresql.Driver"/> </properties> </persistence-unit> </persistence>

O cdigo deste arquivo mostra ao Toplink como trabalhar com o banco de dados. Mostra tambm, quais classes podero ser manipuladas. Neste caso, s a classe Telefone. Salve as alteraes e vamos prosseguir para a camada de persistncia. Criao da Persistncia camada Persistence A camada de persistncia consiste em um Data Access Object (DAO) geral que implementa os procedimentos do CRUD (insero, alterao, excluso e seleo). Ele ser responsvel pela captura das Exceptions de persistncia que, quando encontradas, sero jogadas para a camada acima atravs de uma PersistenceException. Em geral, iremos passar um objeto para os mtodos dessa camada e ele executar (atravs dos recursos do EJB 3) todos os procedimentos sozinho. Deve-se tambm atentar para a necessidade de criar um Singleton do DAO. O que um Singleton? Trata-se de uma classe com mtodos estticos criados para manter um nico objeto DAO para todas as classes que precisarem dele. Observando o cdigo da classe, ser mais fcil entender a

filosofia. Vamos criar o arquivo DAO.


1. 2. 3. 4. 5. 6. 7. 8.

Na aba Projetos, clique com o boto direito em Pacotes de cdigos-fonte Clique na opo Novo, e no submenu Outro... Na aba Categorias, selecione a opo Java Na aba Tipos de arquivos, selecione a opo Classe Java Clique em Prximo Em Nome da classe, digite Dao Em Pacote, selecione a opo persistence Clique em Finalizar

Substitua o contedo do arquivo pelo cdigo abaixo.


// Dao.java package persistence; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.PersistenceException; import javax.persistence.PersistenceUnit; import javax.persistence.Query; @PersistenceUnit public class Dao { private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("default"); private static EntityManager em = emf.createEntityManager(); private static Dao dao; public Dao() {} public static Dao getDataAccessObject() { if ( dao == null ) dao = new Dao(); return dao; } public void create(Object object) throws PersistenceException { try { em.getTransaction().begin(); em.persist( object ); em.getTransaction().commit(); em.clear(); } catch (Exception e) { throw new PersistenceException( "No foi possvel criar o objeto!" ); } } public List<?> read(String namedQuery) throws PersistenceException { try { Query query = em.createNamedQuery( namedQuery ); List<?> collection = query.getResultList(); em.clear(); return collection; } catch (Exception e) { throw new PersistenceException( "No foi possvel realizar a consulta!" );

} } public List<?> executeQuery(String ejbQL, String parameter[]) throws PersistenceException { try { Query query = em.createQuery( ejbQL ); if ( parameter != null ) { for (int i = 0; i < parameter.length; i++) query.setParameter( (i+1) , parameter[ i ] ); } List<?> collection = query.getResultList(); em.clear(); return collection; } catch (Exception e) { throw new PersistenceException( "No foi possvel realizar a consulta!" ); } } public void update(Object object) throws PersistenceException { try { em.getTransaction().begin(); em.merge( object ); em.getTransaction().commit(); em.clear(); } catch (Exception e) { throw new PersistenceException( "No foi possvel alterar o objeto!" ); } } public void destroy(Object object) throws PersistenceException { try { em.getTransaction().begin(); em.remove( em.merge( object ) ); em.getTransaction().commit(); em.clear(); } catch (Exception e) { throw new PersistenceException( "No foi possvel excluir o objeto!" ); } } @SuppressWarnings("unchecked") public Object searchObjectByCode(Class objectClass, Object objectId) throws PersistenceException { try { Object object = em.find( objectClass , objectId ); em.clear(); return object; } catch (Exception e) { throw new PersistenceException( "No foi possvel obter o objeto!" ); } } }

A funcionalidade Singleton foi introduzida atravs do mtodo getDataAccessObject(). O objeto Dao ser criado nas outras camadas atravs deste mtodo, que retorna uma nova referncia ou a referncia j utilizada por outra sesso. Observe que os Exceptions gerados pelo banco no sero detalhadamente filtrados, devido simplicidade mostrada neste exemplo. Em todos os casos, somente uma mensagem ser liberada. Observe tambm que foi criado um mtodo chamado

executeQuery(), utilizado para executar namedQuery com parmetros. Esse recurso ser muito til para validaes e regras realizadas no Bo. Criao das classes de apoio pacote util Algumas classes sero criadas para apoiar o funcionamento geral do sistema. A primeira delas ser a MyCrudException utilizada como exceo para as regras de negcio.
1. 2. 3. 4. 5. 6. 7. 8.

Na aba Projetos, clique com o boto direito em Pacotes de cdigos-fonte Clique na opo Novo, e no submenu Outro... Na aba Categorias, selecione a opo Java Na aba Tipos de arquivos, selecione a opo Classe Java Clique em Prximo Em Nome da classe, digite MyCrudException Em Pacote, selecione a opo util Clique em Finalizar

O cdigo desta classe, muito simples, alis, mostrado abaixo.


// MyCrudException.java package util; public class MyCrudException extends Exception { public MyCrudException() { super(); } public MyCrudException(String message) { super( message ); } }

O prximo objeto responsvel pela criao de um componente de validao de nmeros. Voc pde observar que nosso Pojo telefone possui campos ddd e nmero do tipo String. Mas na realidade estes valores so apenas numricos. Neste objeto faremos tal verificao. Optei em no criar um mtodo esttico que seria usado. Isso depende da preferncia do desenvolvedor. Para a criao deste novo arquivo, realize os procedimentos abaixo:
1. 2. 3. 4. 5. 6. 7. 8.

Na aba Projetos, clique com o boto direito em Pacotes de cdigos-fonte Clique na opo Novo, e no submenu Outro... Na aba Categorias, selecione a opo Java Na aba Tipos de arquivos, selecione a opo Classe Java Clique em Prximo Em Nome da classe, digite Number Em Pacote, selecione a opo util Clique em Finalizar

Abaixo temos o cdigo desta classe:


// Number.java package util; public class Number { private int length; private String value; public Number() { this( 1 ); } public Number(int length) { this( length , "0" ); } public Number(int length, String value) {

this.setLength(length); this.setValue(value); } public void setLength( int length ) { this.length = ( length > 0 ) ? length : 1; } public void setValue(String value) { this.value = value; } public int getLength() { return this.length; } public String getValue() { return this.value; } public boolean validate() { if ( this.value == null ) return false; if ( this.value.length() != this.length ) return false; for ( int i = 0; i < this.length; i++ ) { if ( "0123456789".indexOf( this.value.charAt( i ) ) == -1 ) return false; } return true; } }

Este objeto faz a verificao necessria para nosso sistema. Essas duas classes compem no pacote util. Agora vamos para a implementao mais importante do projeto: as regras do negcio. Criao das Regras de Negcio camada Controller A filosofia ser similar ao da camada de persistncia. Haver uma classe geral chamada Bo. Aqui, porm, precisaremos de uma classe de BO especfica para o Telefone onde sero criadas as regras de negcio. Haver tambm uma Interface que definir os procedimentos padres de camada de Business Object. Abaixo temos o procedimento para a criao das classes e interfaces.
1. 2. 3. 4. 5. 6. 7. 8.

Na aba Projetos, clique com o boto direito em Pacotes de cdigos-fonte Clique na opo Novo, e no submenu Outro... Na aba Categorias, selecione a opo Java Na aba Tipos de arquivos, selecione a opo Interface Java Clique em Prximo Em Nome da classe, digite InterfaceBo Em Pacote, selecione a opo controller Clique em Finalizar

Substitua o arquivo pelo cdigo abaixo:


// InterfaceBo.java package controller; import java.util.List; import model.InterfacePojo; import util.MyCrudException; public interface InterfaceBo { public void create(InterfacePojo pojo) throws MyCrudException; public List<?> read() throws MyCrudException; public List<?> executeQuery(String ejbQL, String parameter[]) throws MyCrudException; public void update(InterfacePojo pojo) throws MyCrudException;

public void destroy(InterfacePojo pojo) throws MyCrudException; public Object searchObjectByCode(Class objectClass, Object id) throws MyCrudException; public void validate(InterfacePojo pojo) throws MyCrudException; }

Agora ser implementada a classe BO geral. Execute o procedimento abaixo:


1. Aps expandir o item Pacotes de cdigos-fonte da aba Projetos, clique com o boto direito

sobre o pacote controller 2. Selecione a opo Novo e o submenu Classe java... 3. Em Nome da classe digite Bo 4. Clique em Finalizar Substitua o contedo do arquivo Bo pelo cdigo abaixo:
// Bo.java package controller; import java.util.List; import javax.persistence.PersistenceException; import model.InterfacePojo; import persistence.Dao; import util.MyCrudException; public class Bo implements InterfaceBo { private String namedQuery; public Bo(String namedQuery) { this.namedQuery = namedQuery; }

@Override public void create(InterfacePojo pojo) throws MyCrudException { try { validate( pojo ); Dao.getDataAccessObject().create( pojo ); } catch (PersistenceException e) { throw new MyCrudException( e.getMessage() ); } } @Override public List<?> read() throws MyCrudException { try { return Dao.getDataAccessObject().read( this.namedQuery ); } catch (PersistenceException e) { throw new MyCrudException( e.getMessage() ); } } @Override public List<?> executeQuery(String ejbQL, String parameter[]) throws MyCrudException { try { return Dao.getDataAccessObject().executeQuery(ejbQL, parameter); } catch (Exception e) { throw new MyCrudException( e.getMessage() ); } }

@Override public void update(InterfacePojo pojo) throws MyCrudException { try { validate( pojo ); Dao.getDataAccessObject().update( pojo ); } catch (PersistenceException e) { throw new MyCrudException( e.getMessage() ); } } @Override public void destroy(InterfacePojo pojo) throws MyCrudException { try { Dao.getDataAccessObject().destroy( pojo ); } catch (PersistenceException e) { throw new MyCrudException( e.getMessage() ); } } @Override public Object searchObjectByCode(Class objectClass, Object id) throws MyCrudException { try { return Dao.getDataAccessObject().searchObjectByCode( objectClass , id ); } catch (PersistenceException e) { throw new MyCrudException( e.getMessage() ); } } @Override public void validate(InterfacePojo pojo) throws MyCrudException {} }

Este cdigo implementa a captura das Exceptions geradas pelo DAO, alm de implementar um mtodo de validao (ainda sem qualquer procedimento). O prximo objeto a ser implementado ser o objeto mais importante do cdigo, pois ser atravs dele que as regras de negcio sero implementadas. Se voc observou o cdigo at o momento, pode reparar que foram utilizadas poucas condies (if). Dentro do possvel controlamos as regras de desenvolvimento com opes de orientao a objetos. A grande massa de condies estruturadas ocorrer no cdigo de regras de negcio. A princpio, vamos implementar apenas os cdigos bsicos de validao campos em branco ou com valor no compatvel com o banco. Vamos colocar outras regras de negcio no final deste estudo, para mostrar simulaes mais prticas.
1. Aps expandir o item Pacotes de cdigos-fonte da aba Projetos, clique com o boto direito

sobre o pacote controller 2. Selecione a opo Novo e o submenu Classe java... 3. Em Nome da classe digite TelefoneBo 4. Clique em Finalizar

Substitua a implementao default do Netbeans do arquivo criado pelo cdigo abaixo:


// TelefoneBo.java package controller; import model.InterfacePojo; import model.Telefone; import util.Number; import util.MyCrudException;

public class TelefoneBo extends Bo { public TelefoneBo() { super( "selectTelefone" ); } @Override public void validate(InterfacePojo pojo) throws MyCrudException { Telefone telefone = (Telefone) pojo; // Validao do DDD Number ddd = new Number( 2 , telefone.getDdd() ); if ( !ddd.validate() ) throw new MyCrudException( "Valor do DDD invlido!" ); // Validao do DDD // Validao do N mero Number numero = new Number( 8 , telefone.getNumero() ); if ( !numero.validate() ) throw new MyCrudException( "Valor do N mero invlido!" ); // Validao do N mero // Validao do Nome if ( telefone.getNome() == null ) throw new MyCrudException( "Valor do Nome invlido!" ); if ( ( telefone.getNome().length() < 1 ) || ( telefone.getNome().length() > 40 ) ) throw new MyCrudException( "Valor do Nome invlido!" ); // Validao do Nome } }

Vamos observar alguns fatores: como voc observou, a maior parte da programao ocorre no objeto Bo. Essas funes sero herdadas pelo TelefoneBo, sendo que, como sobrescrevemos o mtodo validate (e inclumos o @Override), quando um TelefoneBo estiver no Run Time, o mtodo sobrescrito ser utilizado no lugar do escrito no Bo. Isso significa que, quando for utilizada o mtodo create (por exemplo), sua chamada validate far referncia ao mtodo de TelefoneBo. No final deste projeto, mostraremos outras validaes. Agora entraremos na ltima camada. Criao da interface com Usurio camada View A camada View ter alguns detalhes a serem descritos. Durante a apresentao das classes e dos JSP's, falaremos mais sobre o desenvolvimento. O primeiro passo ser implementar o objeto ViewManager, responsvel pelo gerenciamento da tela. Ele simplesmente controlar o desenvolvimento dos processos realizados pelo usurio.
1. Aps expandir o item Pacotes de cdigos-fonte da aba Projetos, clique com o boto direito 2. Selecione a opo Novo e o submenu Classe java... 3. Em Nome da classe digite ViewManager 4. Clique em Finalizar

sobre o pacote view

Substitua o cdigo pelo fragmento abaixo:

// ViewM anager.java package view; import import import import import javax.faces.application.FacesM essage; javax.faces.application.FacesM essage.Severity; javax.faces.context.FacesContext; javax.faces.event.ActionEvent; model.InterfacePojo;

public abstract class ViewM anager { private boolean formView; private boolean formCreate; private boolean formRead; private boolean formUpdate; private boolean formDestroy; private String titleForm; public ViewM anager(String titleForm) { this.titleForm = ( titleForm == null ) ? "CRUD" : titleForm; this.clearForm(); this.formRead = true; } public String getTitleForm() { if ( this.formView ) return titleForm + " - Visualizar"; if ( this.formCreate ) return titleForm + " - Inserir"; if ( this.formRead ) return titleForm + " - Consultar"; if ( this.formUpdate ) return titleForm + " - Atualizar"; if ( this.formDestroy ) return titleForm + " - Excluir"; return titleForm; } public boolean isFormView() { return this.formView; } public boolean isFormCreate() { return this.formCreate; } public boolean isFormRead() { return this.formRead; } public boolean isFormUpdate() { return this.formUpdate; } public boolean isFormDestroy() { return this.formDestroy; } private void clearForm() { this.formView = false; this.formCreate = false; this.formRead = false; this.formUpdate = false; this.formDestroy = false; } public void setFormView(ActionEvent event) { this.clearForm(); this.formView = true; setPojo( getObjectBySession() ); } public void setFormCreate(ActionEvent event) { this.clearForm(); this.formCreate = true; createNewPojo(); } public void setFormRead(ActionEvent event) { this.clearForm();

this.formRead = true; } public void setFormUpdate(ActionEvent event) { this.clearForm(); this.formUpdate = true; setPojo( getObjectBySession() ); } public void setFormDestroy(ActionEvent event) { this.clearForm(); this.formDestroy = true; setPojo( getObjectBySession() ); } protected void showM essage(Severity severity, String resume, String detail) { FacesContext.getCurrentInstance().addM essage ( null , new FacesM essage( severity , resume , detail ) ); } public void createNewPojo() {} public InterfacePojo getObjectBySession() { return null; } public void setPojo(InterfacePojo pojo) {} }

Este cdigo contm os procedimentos que indicam quais partes da pgina JSP ser exibida para os usurios. Por exemplo, a pgina de leitura dos dados (consulta) mostrar uma tabela (DataTable) contendo os dados e esta s ser exibida quando isFormRead retornar true (o que ocorre, neste caso). Agora vamos construir o objeto de controle do objeto POJO. Ela tambm possui alguns mtodos que precisam ser sobrescritos (createNewPojo(), getObjectBySession() e setPojo()). Vamos observ-los adiante.
1. Aps expandir o item Pacotes de cdigos-fonte da aba Projetos, clique com o boto direito

sobre o pacote view 2. Selecione a opo Novo e o submenu Classe java... 3. Em Nome da classe digite PojoManager 4. Clique em Finalizar Substitua o cdigo pelo fragmento abaixo:
// PojoM anager.java package view; import import import import import import import import controller.Bo; java.util.List; javax.faces.application.FacesM essage; javax.faces.context.FacesContext; javax.faces.event.ActionEvent; javax.servlet.ServletRequest; model.InterfacePojo; util.M yCrudException;

public abstract class PojoM anager extends ViewM anager { private Bo bo; private InterfacePojo pojo;

public PojoM anager(String titleForm, Bo bo, InterfacePojo pojo) { super(titleForm); this.bo = bo; this.pojo = pojo; } @Override public void setPojo(InterfacePojo pojo) { this.pojo = pojo; } public InterfacePojo getPojo() { return this.pojo; } public void setBo(Bo bo) { this.bo = bo; } public Bo getBo() { return this.bo; } public void create(ActionEvent event) { try { this.bo.create(this.pojo); super.setFormCreate(event); super.showM essage(FacesM essage.SEVERITY_INFO, null, "Objeto inserido com sucesso!"); } catch (M yCrudException e) { super.showM essage(FacesM essage.SEVERITY_WARN, null, e.getM essage()); } } public void destroy(ActionEvent event) { try { this.bo.destroy(this.pojo); super.setFormRead(event); super.showM essage(FacesM essage.SEVERITY_INFO, null, "Objeto excludo com sucesso!"); } catch (M yCrudException e) { super.showM essage(FacesM essage.SEVERITY_WARN, null, e.getM essage()); } } public void update(ActionEvent event) { try { this.bo.update(this.pojo); super.setFormRead(event); super.showM essage(FacesM essage.SEVERITY_INFO, null, "Objeto alterado com sucesso!"); } catch (M yCrudException e) { super.showM essage(FacesM essage.SEVERITY_WARN, null, e.getM essage()); } } public List<?> getList() { List list = null;

try { list = this.bo.read(); } catch (M yCrudException e) { super.showM essage(FacesM essage.SEVERITY_WARN, null, e.getM essage()); } finally { return list; } } @Override public InterfacePojo getObjectBySession() { InterfacePojo value = null; try { value = FacesContext.getCurrentInstance().getExternalContext().getRequest()).getAttribute("pojo"); } catch (IllegalStateException e) { this.showM essage(FacesM essage.SEVERITY_WARN, null, "No foi possvel obter o objeto!" ); } finally { return value; } } public Object searchObjectByCode() { Object value = null; try { value = this.bo.searchObjectByCode( this.pojo.getClass(), new Integer(this.pojo.getCode())); if (value == null) { super.showM essage(FacesM essage.SEVERITY_WARN, null, "Objeto no encontrado!"); } } catch (M yCrudException e) { super.showM essage(FacesM essage.SEVERITY_WARN, null, e.getM essage()); } finally { return value; } } } (InterfacePojo) ((ServletRequest)

Esta , provavelmente, a classe mais complexa do projeto. Porm, depois de implementada, o ganho de produo para outros CRUDs fantstico. Antes de tudo, vamos observar os principais comportamentos: atravs dos getters e setters de Pojo e Bo, poderemos gerenciar as respectivas classes. Outro comportamento importante realizado pelos mtodos comuns do CRUD (create, destroy, update e read), pois eles realizam o procedimento (atravs do Bo) e, caso ocorra, capturam as excees geradas nas camadas inferiores. Atravs do showMessage (implementado no ViewManager.java) as mensagens sero enviadas para a tela (navegador). Outro mtodo importante definido em getObjectBySession(), que retorna o objeto selecionado na JSP. Quando isso ocorre? Na listagem de telefones, havero campos de opes (links para visualizar, alterar e excluir) no qual o usurio poder clicar. Neste momento, o objeto da linha selecionada (onde o link foi clicado), ser enviado para o servidor. O cdigo de getObjectBySession() obtm esse objeto (que, inclusive, possui o nome de pojo). Por padro, no vamos implementar em PojoManager uma chamada ao mtodo executeQuery() de Bo, pois caso haja necessidade de executar uma Query que no esteja especificada no Model, somente o Bo teria essa permisso (ou melhor, a princpio, somente ele deveria ter essa necessidade). Como voc pode observar, as duas ltimas classes so

abstratas (no podem ser instanciadas). Isso deve ser assim pelo fato delas serem genricas. Vamos implementar agora, uma classe especfica para Telefone que herdar todo o comportamento de PojoManager (e por consequncia, ViewManager).
1. Aps expandir o item Pacotes de cdigos-fonte da aba Projetos, clique com o boto direito 2. Selecione a opo Novo e o submenu Classe java... 3. Em Nome da classe digite TelefoneManager 4. Clique em Finalizar

sobre o pacote view

Substitua o contexto abaixo pelo cdigo da classe criada:


// TelefoneManager.java package view; import controller.TelefoneBo; import model.Telefone; public class TelefoneManager extends PojoManager { public TelefoneManager() { super( "Telefone" , new TelefoneBo() , new Telefone() ); } @Override public void createNewPojo() { Telefone telefone = new Telefone(); super.setPojo( telefone ); } }

Como voc pode observar, esta uma simples classe que apenas sobrescreve o constructor para definir as variveis de instncia para o ViewManager e o createNewPojo() - utilizado para criar um novo pojo Telefone. Esta classe ser nosso Bean de Sesso, porm, no ser acessada diretamente. Criaremos uma classe chamada SessionBean que controlar todos os Beans da aplicao. Neste caso, como s temos um Bean, o TelefoneManager, que por sua vez, possui acesso direto ao Telefone, este ser gerenciado pela SessionBean.
1. Aps expandir o item Pacotes de cdigos-fonte da aba Projetos, clique com o boto direito

sobre o pacote view 2. Selecione a opo Novo e o submenu Classe java... 3. Em Nome da classe digite SessionBean 4. Clique em Finalizar O cdigo da classe mostrado abaixo:
// SessionBean.java package view; public class SessionBean { private TelefoneManager telefoneBean; public SessionBean() { this.telefoneBean = new TelefoneManager();

} public TelefoneManager getTelefoneBean() { return this.telefoneBean; } }

Para torn-la acessvel pelos JSP's, precisamos adicion-la ao faces-config.xml. Para trabalhar com esse arquivo, execute:
1. Aps expandir o item Arquivos de configurao da aba Projetos, d dois cliques sobre o

arquivo faces-config.xml

No incio, ser mostrada a IDE de organizao dos JSP e navegao, porm, vamos trabalhar diretamente com o cdigo. Clique (na parte superior do editor) na aba XML. O contedo do arquivo dever ficar igual ao cdigo mostrado abaixo:
<?xml version='1.0' encoding='UTF-8'?> <faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"> <managed-bean> <managed-bean-name>SessionBean</managed-bean-name> <managed-bean-class>view.SessionBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config>

Observe que foi acrescentado uma diretiva <managed-bean que indicar o arquivo java que ser acessvel pelo JSP. Esse parmetro indica o seguinte: Item <managed-bean-name : nome acessvel pelas tags do JSP. Ou seja, se quisermos obter um atributo contido em SessionBean, o mesmo dever (por padro) ter o mtodo getAtributo(). Se quisermos definir um valor para esse atributo, precisaremos do setAtributo(). Por exemplo, no cdigo JSP, vamos acessar o atributo ddd do pojo telefone com a sintaxe: SessionBean.telefoneBean.pojo.ddd Ou seja, podemos referenciar SessionBean pois o mesmo est no faces-config.xml. SessionBean possui um atributo telefoneBean, que acessvel pelo getTelefoneBean(). Que por sua vez possui um mtodo getPojo() - herdado do PojoManager que retorna o Pojo no runtime que se trata de um Telefone (pois TelefoneManager instancia o pojo Telefone em seu constructor). Por ltimo, Telefone possui o mtodo getDdd() que retorna o valor do atributo e setDdd() que define o valor do atributo. Esse acesso, por exemplo, poderia estar associado a um componente input do tipo text, indicando que o valor escrito no componente, ser guardado (ou buscado) do Pojo Telefone. Veremos o cdigo JSP adiante. Item <managed-bean-class : indica com o pacote a classe associada ao Bean estabelecido. Item <managed-bean-scope : indica o escopo deste Bean. Pode-se definir session, request ou application, cada um com sua utilidade. Se utilizarmos request, o bean tem seu ciclo de vida para uma nica requisio, ou seja, ao postarmos uma pgina, o container instancia o Bean e realiza o procedimento. Em seguida o Bean descartado. O session, mantm o Bean no container enquanto a sesso do usurio estiver ativa. Quando a sesso for finalizada, o container finaliza a vida dele (no do usurio - do bean, claro). O escopo application dar ao Bean, tempo de vida durante toda a aplicao. Este um caso muito particular, que precisa ser

utilizado com cuidado, pois todos utilizaram de um mesmo recurso no sistema (o que se faz necessrio, em alguns casos). Como nosso telefoneBean guardar vrios estados da JSP, durante toda a sesso, vamos utilizar o escopo session. Voc deve estar se perguntando: porque no definir TelefoneManager diretamente no facesconfig.xml ao invs de criar SessionBean. Bom, com uma nica classe a ser gerenciada na sesso, realmente no precisamos de SessionBean. Porm, imagine que o sistema tenha dezenas de Beans, sendo todos com escopo de sesso. Para cada JSP que o usurio trabalhar, um Bean ser instanciado no container. Ou seja, se o usurio acessar a tela de Telefones, o container instancia TelefoneManager. Se o usurio acessar a tela de Clientes (se existisse, por exemplo), o container instancia o Bean ClienteManager, s que, neste momento, no mais necessrio que TelefoneManager continue na memria. Que iria liber-lo? Nosso SessionBean. Quando o usurio acessar uma nova pgina JSP, o SessionBean teria o cuidado de liberar da memria (com o cdigo telefoneBean = null;, por exemplo) os Beans que ele no precisa mais. Ateno, o EJB 3 fornece Beans de sesso em seu framework, porm no veremos isso neste estudo (quem sabe futuramente?). Por fim, vamos criar a tela JSP. Criao das telas JSP Nesta etapa, finalmente criaremos a interface com usurio. Primeiramente, vamos criar dois templates atravs do recurso de tags (isso poderia ser feito, com algumas vantagens, com facelets). Vamos criar a pasta para guardar nossas tags. Por padro, o diretrio tags fica localizado dentro de WEB-INF. Execute o procedimento abaixo para cri-lo:
1. Aps expandir o item Pginas web, da aba Projetos, clique com o boto direito do mouse no 2. 3. 4. 5. 6. 7.

diretrio WEB-INF Selecione a opo Novo, item Outro... Na caixa Categorias, selecione Outro Na caixa Tipos de arquivos, selecione Diretrio Clique em Prximo Em Nome da pasta, entre com tags Clique em Finalizar

Todas as nossas tags sero guardadas aqui. Vamos criar a tag header.
1. 2. 3. 4. 5. 6. 7.

Na aba Projetos, abra o item Pginas web, em seguida, abra o diretrio WEB-INF Clique com o boto direito no diretrio tags, selecione a opo Novo, item Outro... Na caixa Categorias, selecione Web Na caixa Tipos de Arquivos, selecione Arquivo de marcao (Tag) Clique em Prximo Em Nome do arquivo de marcao, defina o valor header Clique em Finalizar

Substitua o contedo do arquivo pelo cdigo abaixo:


<%@tag description="put the tag description here" pageEncoding="UTF-8"%> <table> <tr> <td width="20%" bgcolor="#898989"> &nbsp; </td> <td align="center" bgcolor="#aeaeae"> <font class="title"> MyCRUD </font> </td> <td width="20%" bgcolor="#898989"> &nbsp; </td>

</tr> </table>

Agora vamos criar a tag footer.


1. 2. 3. 4. 5. 6. 7.

Na aba Projetos, abra o item Pginas web, em seguida, abra o diretrio WEB-INF Clique com o boto direito no diretrio tags, selecione a opo Novo, item Outro... Na caixa Categorias, selecione Web Na caixa Tipos de Arquivos, selecione Arquivo de marcao (Tag) Clique em Prximo Em Nome do arquivo de marcao, defina o valor footer Clique em Finalizar

Substitua o contedo do arquivo pelo cdigo abaixo:


<%@tag description="put the tag description here" pageEncoding="UTF-8"%> <table> <tr> <td bgcolor="#898989" height="3"></td> </tr> </table>

Agora, vamos criar nosso estilo CSS.


1. 2. 3. 4. 5. 6. 7.

Na aba Projetos, clique com o boto direito no item Pginas web Selecione a opo Novo, item Outro... Na caixa Categorias, selecione Outro Na caixa Tipos de arquivos, selecione Diretrio Clique em Prximo Em Nome da pasta, entre com css Clique em Finalizar

Nossa folha de estilo ficar aqui. Vamos cri-la:


1. 2. 3. 4. 5. 6. 7.

Na aba Projetos, abra o item Pginas web Clique com o boto direito no diretrio css, selecione a opo Novo, item Outro... Na caixa Categorias, selecione Web Na caixa Tipos de Arquivos, selecione Folha de estilo em cascata Clique em Prximo Em Nome do arquivo CSS, defina o valor style Clique em Finalizar

Substitua o contedo do arquivo pelo cdigo abaixo:


/* style.css */ img.link { border: 0px; } table { border-collapse: collapse; border: 0px;

padding: 0px; background: white; width: 500px; } table.empty { border-collapse: collapse; border: 0px; padding: 0px; width: 100%; } table.data { border-collapse: collapse; padding: 0px; background-color: white; width: 100%; } .form { font: 12px Arial, sans-serif; } .footer { text-align: right; padding: 8px; } .header { text-align: left; font-weight: bold; color: grey; font: 14px Arial, sans-serif; } font.title { font-weight: bold; color: white; font: 14px Arial, sans-serif; } .tableHeader { color: black; font: 12px Arial, sans-serif; } .tableData { color: blue; font: 12px Arial, sans-serif; } .severityInformation { text-align: center; font: 11px Arial, sans-serif; font-weight: bold; color: #2222aa; } .severityWarning { text-align: center; font: 11px Arial, sans-serif;

font-weight: bold; color: #aaaa22; } .severityError { text-align: center; font: 11px Arial, sans-serif; font-weight: bold; color: #aa2222; }

Por fim, vamos definir as imagens que utilizaremos no sistema.


1. 2. 3. 4. 5. 6. 7.

Na aba Projetos, clique com o boto direito no item Pginas web Selecione a opo Novo, item Outro... Na caixa Categorias, selecione Outro Na caixa Tipos de arquivos, selecione Diretrio Clique em Prximo Em Nome da pasta, entre com img Clique em Finalizar

Neste caso, vamos salvar as imagens diretamente no diretrio onde est guardado o projeto. Caso voc no saiba onde est, clique com o boto direito no projeto mycrud (na aba Projetos), selecione o menu Propriedades. No campo Pasta do projeto estar definido o caminho. Vamos supor que seu projeto esteja no path abaixo:
/home/guilherme/desenvolvimento/java/netbeans/mycrud

As imagens devero ser salvas em:


/home/guilherme/desenvolvimento/java/netbeans/mycrud/web/img

Ou seja, exatamente no diretrio que voc criou. As imagens esto dispostas abaixo:

delete.gif

floppy.gif

lupa.gif

Aps salva-las no diretrio img, voc poder observ-las pelo Netbeans. Vamos agora para a criao do nosso arquivo JSP. Primeiramente, vamos excluir o arquivo welcomeJSF.jsp. Para isso, execute:
1. Abra o item Pginas web na aba Projetos 2. Clique com o boto direito em welcomeJSF.jsp e selecione Excluir 3. Na confirmao, clique em Sim

Vamos criar nosso JSP:


1. Na aba Projetos, clique com o boto direito no item Pginas web 2. Selecione a opo Novo, item Outro... 3. Na caixa Categorias, selecione Web

4. 5. 6. 7.

Na caixa Tipos de arquivos, selecione JSP Clique em Prximo Em Nome do arquivo JSP, entre com crudTelefone Clique em Finalizar

Substitua o cdigo gerado pelo contedo abaixo (que grande, alias):


<%@page contentType="text/html" pageEncoding="UTF-8"%> <%@ taglib prefix="my" tagdir="/WEB-INF/tags" %> <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %> <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" type="text/css" href="css/style.css"> <title>MyCRUD</title> </head> <body> <my:header /> <table> <tr> <td> <f:view> <h:form id="editForm"> <h:dataTable styleClass="data" footerClass="footer" headerClass="header" value="#{SessionBean.telefoneBean.list}" var="pojo" rendered="#{SessionBean.telefoneBean.formRead}"> <f:facet name="header"> <h:outputText value="#{SessionBean.telefoneBean.titleForm}" /> </f:facet> <h:column> <f:facet name="header"> <h:outputText value="Nome" styleClass="tableHeader"/> </f:facet> <h:outputText value="#{pojo.nome}" styleClass="tableData"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Telefone" styleClass="tableHeader"/> </f:facet> <h:outputText value="#{pojo.numeroFormatado}" styleClass="tableData"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Opes" styleClass="tableHeader"/> </f:facet> <h:commandLink actionListener="#{SessionBean.telefoneBean.setFormView}"> <h:graphicImage styleClass="link" value="img/lupa.gif" /> </h:commandLink> &nbsp; <h:commandLink actionListener="#{SessionBean.telefoneBean.setFormUpdate}"> <h:graphicImage styleClass="link" value="img/floppy.gif" /> </h:commandLink> &nbsp; <h:commandLink actionListener="#{SessionBean.telefoneBean.setFormDestroy}"> <h:graphicImage styleClass="link" value="img/delete.gif" /> </h:commandLink>

</h:column> <f:facet name="footer"> <h:commandButton actionListener="#{SessionBean.telefoneBean.setFormCreate}" value="Inserir" /> </f:facet> </h:dataTable> <h:panelGrid columns="2" rendered="#{!SessionBean.telefoneBean.formRead}" styleClass="empty" footerClass="footer" headerClass="header"> <f:facet name="header"> <h:outputText value="#{SessionBean.telefoneBean.titleForm}" /> </f:facet> <h:column> <h:outputText value="DDD" styleClass="form" /> </h:column> <h:column> <h:inputText disabled="#{SessionBean.telefoneBean.formDestroy or SessionBean.telefoneBean.formView}" value="#{SessionBean.telefoneBean.pojo.ddd}" maxlength="2" /> </h:column> <h:column> <h:outputText value="N mero" styleClass="form" /> </h:column> <h:column> <h:inputText disabled="#{SessionBean.telefoneBean.formDestroy or SessionBean.telefoneBean.formView}" value="#{SessionBean.telefoneBean.pojo.numero}" maxlength="8" /> </h:column> <h:column> <h:outputText value="Nome" styleClass="form" /> </h:column> <h:column> <h:inputText disabled="#{SessionBean.telefoneBean.formDestroy or SessionBean.telefoneBean.formView}" value="#{SessionBean.telefoneBean.pojo.nome}" maxlength="40" /> </h:column> <f:facet name="footer"> <h:panelGrid styleClass="empty"> <h:column> <h:commandButton actionListener="#{SessionBean.telefoneBean.setFormRead}" value="Voltar" /> &nbsp; <h:commandButton actionListener="#{SessionBean.telefoneBean.create}" value="Inserir" rendered="#{SessionBean.telefoneBean.formCreate}" /> <h:commandButton actionListener="#{SessionBean.telefoneBean.update}" value="Alterar" rendered="#{SessionBean.telefoneBean.formUpdate}" /> <h:commandButton actionListener="#{SessionBean.telefoneBean.destroy}" value="Excluir" rendered="#{SessionBean.telefoneBean.formDestroy}" />

</h:column> </h:panelGrid> </f:facet> </h:panelGrid> <my:footer /> <h:messages showSummary="false" showDetail="true" infoClass="severityInformation" warnClass="severityWarning" errorClass="severityError" /> </h:form> </f:view> </td> </tr> </table> </body> </html>

Para configurar nossa JSP como pgina inicial, execute a sequncia:


1. Aps expandir o item Arquivos de configurao da aba Projetos, d dois cliques sobre o

arquivo web.xml

Entre na aba XML (parte superior do editor) e substitua o contedo pelo cdigo abaixo:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>com.sun.faces.verifyObjects</param-name> <param-value>false</param-value> </context-param> <context-param> <param-name>com.sun.faces.validateXml</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>client</param-value> </context-param> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <session-config> <session-timeout> 30 </session-timeout> </session-config> <welcome-file-list> <welcome-file>faces/crudTelefone.jsp</welcome-file>

</welcome-file-list> </web-app>

O que transforma nosso JSP em pgina principal a diretiva <welcome-file <welcome-file-list .

localizada em

Vamos compreender o cdigo da JSP. Acho que ser mais didtico, entender o que ocorre quando executamos este aplicativo. Neste ponto, o mesmo j est pronto para ser executado. Voc poder executar atravs do menu Executar, submenu Executar projeto principal. Quando fizer isso, o Netbeans levantar o container Tomcat, e abrir um navegador. Algo similar ao mostrado abaixo aparecer em sua tela:

Vejamos os detalhes: 1. Quando o usurio acessa essa JSP, o container instancia SessionBean (com escopo de sesso). 2. Atravs das taglib no incio do arquivo, definimos os namespace's ou seja, quais tag poderemos utilizar no JSP (que na verdade, um JSF Java ServerFaces). 3. Observe que atravs de <%@ taglib prefix="my" tagdir="/WEB-INF/tags" % , podemos acessar nossas tags header e footer 4. Na tag <my:header / , fazemos referncia ao namespace my (definido na taglib anterior), o contedo de header 5. Em <f:view definimos o escopo onde trabalharemos com os recursos JSF 6. Em <h:form id="editForm" definido o formulrio 7. Na criao de <h:dataTable..., definimos os estilos CSS (styleClass, headerClass e footerClass), a listagem SessionBean.telefoneBean.list de componentes que ser exibida (que obtm seu valor em getList() de telefoneBean), o nome do objeto (var="pojo") em cada linha da tabela, e se a mesma renderizada. Como telefoneBean foi criado agora, como voc pode observar no cdigo do constructor de ViewManager (av de TelefoneMananger), definimos this.formRead = true;. Isso significa que, o cdigo de

8.

9.

10.

11.

12.

13. 14. 15.

SessionBean.telefoneBean.formRead (que acessa o mtodo isFormRead() de ViewManager) utilizado em rendered, retorna true e possibilita a exibio deste componente dataTable O campo <h:outputText value="#{SessionBean.telefoneBean.titleForm}" / obtm o valor do mtodo getTitleForm() que, por consequncia de formRead ser verdadeiro, retorna a String Telefone Consultar Os <h:outputText..., encontrados nas outras colunas, acessam diretamente o elemento pojo da iterao, ou seja, um objeto Telefone (lembrando que getList() de telefoneBean, definido no value de dataTable, retorna uma listagem de Telefone's. Em cada linha, um dos Telefone's ser exibido. Como se trata do pojo Telefone, podemos acessar seus mtodos getNome() e getNumeroFormatado(), respectivamente com pojo.nome e pojo.numeroFormatado Atravs dos <h:commandLink... (cada um associado com sua <h:graphicImage...), podemos disparar as aes (com actionListener) para setFormView(), setFormUpdate() e setFormDestroy(). Cada uma delas buscar da sesso, o objeto em questo (pelo cdigo de getObjectBySession()), e tornar o respectivo booleano form ativo (desabilitando os demais com clearForm()). Isso nos levaria para as respectivas aes do CRUD. Atravs do <h:commandButton..., podemos executar a ao setFormCreate, que criar um novo pojo com createNewPojo() (que foi sobrescrito em TelefoneManager e, em runtime, ser executado) e definir formCreate como true Abaixo, na definio do <h:panelGrid..., o JSP no far usa reenderizao, pois o valor retornado em isFormRead() true, e o cdigo !SessionBean.telefoneBean.formRead, definido em rendered, pega o inverso (pelo smbolo !) de true Mais abaixo, em <my:footer / , nossa tag footer ser exibida O cdigo <h:messages..., mostrar as mensagens enviadas pelo cdigo showMessage() de ViewManager (quando forem enviadas, o que neste momento, no ocorreu) O restante do cdigo fecha as tags JSP e HTML

Como no existem objetos no banco, nada foi retornado. Se clicarmos em Inserir, a tela abaixo (similar, pois a tela mostrada j contm dados digitados e aes realizadas) ser exibida: Vejamos o que ocorreu:
1. Quando o boto Inserir da primeira tela (a de consulta) foi clicado, o mtodo

2. 3. 4. 5.

6. 7. 8.

setFormCreate() foi chamado, um novo Telefone foi criado e formCreate foi definido como true. Neste caso, a dataTable da consulta no ser mais exibida (pois formRead foi definida como false) e o panelGrid passar a ser mostrado Os cdigos dos <h:inputText..., sero associados aos valores do pojo Telefone Observe tambm que, atravs dos disabled's dos <h:inputText..., o JSP desabilitar os input's para os casos onde isFormView() ou isFormDestroy() retornarem true Com os <h:commandButton..., poderemos executar as aes do CRUD definidas em PojoManager Observe que cada um deles possui (com exceo do Voltar) um rendered que far com que os mesmos s sejam exibidos em suas respectivas telas. Ou seja, como estamos na tela de cadastro, getFormCreate() retornar true e far com que seu boto seja exibido. Como getFormUpdate() e getFormDestroy() retornam false, os respectivos botes no sero mostrados para o usurio Simulando um cadastro, entre com os valores 2, 22334455 e Joo, para os campos DDD, Nmero e Nome, respectivamente Quando clicarmos no boto Inserir, o mtodo create() de PojoManager ser chamado PojoManager automaticamente j recebeu uma instncia de Telefone atravs de setPojo(), e por isso, quando create() executa this.bo.create(this.pojo);, this.pojo retorna esta instncia

10. 11. 12.

13.

14. 15. 16.

telefoneBean uma instncia de TelefoneManager, que por usa vez, define o Bo 9. de PojoManager como sendo um TelefoneBo. Isso significa que, no runtime, this.bo de PojoManager um TelefoneBo Ao verificarmos o mtodo create() de Bo, vemos que o primeiro procedimento a ser executado validate( pojo ); Como Bo um TelefoneBo, o validate() do runtime tambm o seu, ou seja, vejamos o que ocorre no validate() de TelefoneBo Como j comentado, esse mtodo faz a validao do pojo Telefone. Em primeiro lugar, ele valida o valor de telefone.getDdd() (atravs do objeto de utilidades util.Number), que por sua vez, retorna false em ddd.validate() e por consequncia gera uma MyCrudException com a mensagem "Valor do DDD invlido!" Essa exceo disparada pelo throws do mtodo validate() de TelefoneBo, capturada pelo try do mtodo create() de Bo, disparada pelo novo MyCrudException de create() de Bo, capturada pelo try de PojoManager, que por sua vez envia uma mensagem para a JSP Como nada foi alterado em formCreate (de ViewManager) a mesma tela ser exibida, porm com a mensagem encaminha sendo mostrada na parte inferior (igual a imagem anterior) Se preenchermos os dados corretamente, aps o validate() de TelefoneBo, o mtodo create() de Dao executado, que por sua vez, armazena o objeto no banco O runtime retorna para o mtodo create() de PojoManager, executa setFormCreate() - para criar um novo Telefone e consequentemente limpar os campos do JSP e posteriormente, joga uma mensagem para a JSP

Observe o que ocorre quando o cadastro realizado com sucesso: Esse fluxo exatamente o mesmo que ocorre em Update (exceto pelo fato de que em vez de create(), coordenado por update()). No procedimento de excluso, algo similar acontece, porm, o mtodo validate() no chamado. Outras telas representativas do processo so mostradas

abaixo.

Ao voltarmos para a consulta, o registro ser exibido com suas respectivas opes. Se clicarmos em excluir (cone lixeira), a tela abaixo ser exibida:

Se clicarmos na opo de alterar (cone do disquete, na tela de consulta), e realizarmos algumas alteraes, o mtodo update() de PojoManager realiza o procedimento setFormRead(), que levar o usurio para a tela de consulta. Porm, como update() tambm exibe uma mensagem, a mesma ser exibida na tela de consulta (conforme a tela abaixo). Se houvesse algum problema no processo, setFormRead() no seria executado e o usurio permaneceria na tela de atualizao. Nosso CRUD telefone est pronto. Conforme falado, vamos voltar ao cdigo de TelefoneBo para aplicar algumas regras de negcio mais complexas. Ateno: SEMPRE que voc alterar o cdigo (seja de JSP e, principalmente, Java) feche o navegador e execute (faa o deploy publicao) a aplicao novamente. Aplicando as Regras de Negcio Como voc pode observar, os procedimento de cadastro e atualizao obrigam o usurio a passar pelo mtodo validate() de TelefoneBo. exatamente nesta classe que ns vamos aplicar as seguintes regras de negcio: O sistema no deve permitir cadastrar um DDD da rea 22 Luck arquiinimigo de Dartvaider. O sistema no deve deixar que ambos existam no banco de dados para evitar uma pane no sistema O sistema deve ter no mnimo 1 (um) registro no banco de dados Agora que j sabemos nossas regras de negcio (importantssimas, alis), vamos ao que interessa. Edite o cdigo de TelefoneBo para que o mesmo fique igual ao contexto mostrado abaixo.
// TelefoneBo.java package controller; import java.util.List; import model.InterfacePojo;

import model.Telefone; import util.Number; import util.MyCrudException; public class TelefoneBo extends Bo { public TelefoneBo() { super( "selectTelefone" ); } @Override public void validate(InterfacePojo pojo) throws MyCrudException { Telefone telefone = (Telefone) pojo; // Validao do DDD Number ddd = new Number( 2 , telefone.getDdd() ); if ( !ddd.validate() ) throw new MyCrudException( "Valor do DDD invlido!" ); // Validao do DDD // Validao do N mero Number numero = new Number( 8 , telefone.getNumero() ); if ( !numero.validate() ) throw new MyCrudException( "Valor do N mero invlido!" ); // Validao do N mero // Validao do Nome if ( telefone.getNome() == null ) throw new MyCrudException( "Valor do Nome invlido!" ); if ( ( telefone.getNome().length() < 1 ) || ( telefone.getNome().length() > 40 ) ) throw new MyCrudException( "Valor do Nome invlido!" ); // Validao do Nome

// Regras de Negcios this.invalidDdd( telefone ); this.luckVersusDartvaider( telefone ); // Regras de Negcios } private void invalidDdd(Telefone telefone) throws MyCrudException { if ( telefone.getDdd().equals( "22" ) ) throw new MyCrudException( "O DDD 22 no pode ser utilizado!" ); } private void luckVersusDartvaider(Telefone telefone) throws MyCrudException { String ejbQL = "select obj from Telefone obj where "; ejbQL += "UPPER( obj.nome ) like ?1"; String parameter[] = new String[ 1 ]; try { if ( telefone.getNome().toUpperCase().equals( "LUCK" ) ) parameter[ 0 ] = "DARTVAIDER"; else parameter[ 0 ] = "LUCK" ; List<Telefone> collection = (List<Telefone>) super.executeQuery( ejbQL , parameter ); if ( !collection.isEmpty() ) throw new MyCrudException( "May The Force Be With You!" ); } catch (Exception e) { throw new MyCrudException( e.getMessage() ); } } @Override public void destroy(InterfacePojo pojo) throws MyCrudException { try { String ejbQL = "select obj from Telefone obj"; List<Telefone> collection = (List<Telefone>) super.executeQuery( ejbQL , null ); if ( collection.size() == 1 ) throw new MyCrudException( "Existe um nico registro!" ); super.destroy( pojo ); } catch (Exception e) { throw new MyCrudException( e.getMessage() ); } } }

Vamos ao seu entendimento. Para a primeira regra de negcio (DDD 22 invlido), uma simples verificao no pojo Telefone cadastrado (ou atualizado), onde comparamos o valor de getDdd() com 22, far com que uma exception seja disparada. Neste caso, observe como ficaria a tela:

A prxima regra, que impede que estejam registrados os telefones de Luck e Dartvaider ao mesmo tempo, foi criada da seguinte maneira. Caso Luck j estivesse cadastrado (ou seja, cadastre Luck agora), ao tentarmos cadastrar Dartvaider, o fluxo abaixo ocorre:
1. Na tela de cadastro, entre com o telefone de Dartvaider. Ao inserir, o mtodo create(), em 2.

3. 4. 5. 6.

7. 8.

9.

algum momento, encontra com validate(), que por sua vez chama luckVersusDartvaider() Em luckVersusDartvaider(), criamos nossa EJB Query Language que vai verificar se existe algum registro no banco com obj.nome igual (ou que contm like) o parmetro, ainda no definido, ?1 Se getNome() possui o valor LUCK, parameter[0] ser DARTVAIDER Caso contrrio, paramter[0] ser LUCK Em nosso exemplo, o valor de parameter[0] igual DARTVAIDER Atravs do mtodo executeQuery() de Bo, passamos ejbQL e o vetor parameter para executeQuery() de Dao, que por sua vez, monta uma Query que substitui a diretiva ?1 pelo valor contido em parameter (isso realizado em um looping, pois podemos ter vrios parmetros dependendo da Query) Por fim, essa consulta retorna uma List<? com os resultados O runtime volta para o mtodo luckVersusDartvaider() e verifica a quantidade de registros contidos em collection. Como Luck j estava cadastrado (em nosso exemplo, j estava), collection.isEmpty() retornar false, que com a oposio do resultado (!), far com que uma MyCrudException seja disparada com a mensagem "May The Force Be With You!" Observe que tanto o valor de getNome() (em Telefone) quanto o valor de obj.nome (na ejbQL) so transformados em maisculo para uma melhor comparao

Aps executar este teste, a tela abaixo ser exibida: Como voc pode observar, essa regra de negcio precisou realizar uma consulta mais especfica no

banco. Vamos, por fim, para a ltima regra. Como o sistema necessita de no mnimo um registro no banco, precisamos realizar essa regra no momento da excluso de registros. Como faremos? Como voc pode observar no cdigo, o mtodo destroy() de Bo foi sobrescrito em TelefoneBo e, atravs deste recurso acrescentamos a verificao da quantidade de registros atravs de consulta ao banco. A lgica da regra simples e por isso no vou descrev-la aqui. Observe o cdigo que voc compreender perfeitamente o que acontece. Como exemplo, tente excluir todos os registros e observe o vai acontecer quando voc for tentar excluir o ltimo registro: Bom, isso ai! Para fazer um sisteminha podre desses eu preciso implementar isso tudo Concluso ? A programao OO de Java, por si s requer uma quantidade maior de cdigo para os sistemas simples como esse. Com o padro MVC isso ocorre com mais impacto. Porm, neste exemplo, ns implementamos um Model com uma nica classe. Imagine um sistema com 100 classes de modelo. Qual seria seu trabalho, a partir do que foi feito aqui, para implementar as outras 99 classes? Essa a pergunta que voc precisa responder! Por exemplo, para criar um CRUD Cliente, criaramos a classe Cliente.java no pacote model, a classe CienteBo.java no pacote controller e a classe ClienteManager.java no pacote view. Como voc pode observar, o cdigo para implementar essas classes mnimo. Por fim, voc cria um gerenciamento para ClienteManager em SessionBean.java (criando um clienteBean, instanciando-o no constructor, e criando um mtodo getClienteBean()) e colocaria uma referncia para o mesmo no arquivo persistence.xml. Por ltimo, voc criaria a pgina crudCliente.jsp (que alis, muito similar crudTelefone.jsp). Voc capaz de fazer isso em no mximo 30 minutos. Experimente! Voc ver o ganho de produo conquistado ao desenvolver projetos Web com Java, EJB 3 no padro MVC. Bom pessoal! Espero ter contribudo com algo! Caso vejam algum erro no sistema ou algum erro de portugus (ops!!!), peo que colaborem enviando-me um e-mail para que o mesmo possa ser corrigido!

Voc pode fazer o download completo da aplicao clicando aqui! Abraos, Guilherme Pontes.