21 de fevereiro de 2011

JavaEE 6: CRUD em JSF 2.0

Inicialmente no banco de dados crie uma database chamada 4tads, e nela crie uma tabela cliente com o seguinte código:
CREATE TABLE `4tads`.`cliente` ( 
  `codigo` INTEGER(11)  NOT NULL AUTO_INCREMENT, 
  `nome` VARCHAR(255)  NOT NULL, 
  `telefone` VARCHAR(30) , 
  PRIMARY KEY (`codigo`) 
) 
ENGINE = InnoDB; 

Agora crie um projeto JEE 6 (Veja aqui), com o nome de crudJSF, teremos como estrutura final o seguinte projeto:


Antes de iniciar a codificação, vamos colocar no projeto o driver JDBC para acesso ao banco de dados, para isso clique com o botão direito em cima de BibliotecasAdicionar Biblioteca e selecione MySQL JDBC Driver:


Agora no Pacotes de código-fonte crie os seguintes pacotes: model, controller e dao.
Dentro do model crie uma classe java chamada Cliente.java, com os atributos codigo, nome e telefone, além dos getters e setters:
public class Cliente {

    private int codigo;
    private String nome;
    private String telefone;

    public int getCodigo() {
        return codigo;
    }

    public void setCodigo(int codigo) {
        this.codigo = codigo;
    }

    public String getNome() {
        return nome;
    }

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

    public String getTelefone() {
        return telefone;
    }

    public void setTelefone(String telefone) {
        this.telefone = telefone;
    }
}

Dentro do dao vamos criar uma classe java chamada Conexao.java, esta será responsável por fazer a conexão com o banco de dados:
import java.sql.DriverManager;
import java.sql.SQLException;
import com.mysql.jdbc.Connection;

public class Conexao {

    private String driver = "com.mysql.jdbc.Driver";
    private String URL = "jdbc:mysql://localhost/4tads";
    private String USER = "root";
    private String SENHA = "admin";
    private Connection conn;

    public Conexao() {
        try {
            Class.forName(driver);
            conn = (Connection) DriverManager.getConnection(URL, USER, SENHA);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Connection getConn() {
        return conn;
    }

    public void fecharConexao() {
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Perceba que o atributo URL termina com 4tads, este está se referindo a nossa database criada no inicio do post que contém nossa tabela cliente. Os atributos USER e SENHA, se referem ao usuário e a senha do banco de dados.
Depois de ter criado nosso arquivo de conexão com o banco, vamos criar nossa classe ClienteDAO.java:
import com.mysql.jdbc.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import model.Cliente;

/**
 *
 * @author andii
 */
public class ClienteDAO {

    private Conexao conexao;
    private Statement stmt;
    private boolean sucesso = false;

    public ClienteDAO() {
        conexao = new Conexao();
        try {
            stmt = (Statement) conexao.getConn().createStatement();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public boolean inserir(Cliente cliente) {
        try {
            stmt.execute("INSERT INTO cliente (nome, telefone) VALUES ('" + cliente.getNome() + "','" + cliente.getTelefone() + "')");
            sucesso = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            conexao.fecharConexao();
        }

        return sucesso;
    }

    public boolean alterar(Cliente cliente) {
        try {
            stmt.execute("UPDATE cliente SET nome = '" + cliente.getNome() + "', telefone = '" + cliente.getTelefone() + "' WHERE codigo = '" + cliente.getCodigo() + "'");
            sucesso = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            conexao.fecharConexao();
        }

        return sucesso;
    }

    public boolean remover(Cliente cliente) {
        try {
            stmt.execute("DELETE FROM cliente WHERE codigo = '" + cliente.getCodigo() + "'");
            sucesso = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            conexao.fecharConexao();
        }

        return sucesso;
    }

    public List<Cliente> listar() {
        List<Cliente> clientes = new ArrayList<Cliente>();
        try {
            ResultSet rs = stmt.executeQuery("SELECT * FROM cliente ORDER BY nome");
            while (rs.next()) {
                Cliente cliente = new Cliente();
                cliente.setCodigo(rs.getInt("codigo"));
                cliente.setNome(rs.getString("nome"));
                cliente.setTelefone(rs.getString("telefone"));

                clientes.add(cliente);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            conexao.fecharConexao();
        }

        return clientes;
    }
}

Agora dentro do controller vamos criar nosso bean, para isso crie uma nova classe java com o nome de ClienteBean.java:
import dao.ClienteDAO;
import java.io.Serializable;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.inject.Named;
import model.Cliente;

/**
 *
 * @author andii
 */
@Named
@SessionScoped
public class ClienteBean implements Serializable{

    private ClienteDAO clienteDAO;
    private Cliente cliente = new Cliente();
    private DataModel<Cliente> clientes;

    public void novo(){
        cliente = new Cliente();
    }

    public String inserir(){
        String resultado = "falha";
        clienteDAO = new ClienteDAO();
        boolean retorno = clienteDAO.inserir(cliente);

        if(retorno){
            resultado = "clientes";
        }

        return resultado;
    }

    public void selecionar(){
        cliente = clientes.getRowData();
    }

    public String alterar(){
        String resultado = "falha";
        clienteDAO = new ClienteDAO();
        boolean retorno = clienteDAO.alterar(cliente);

        if(retorno){
            resultado = "clientes";
        }

        return resultado;
    }

    public String remover(){
        String resultado = "falha";
        clienteDAO = new ClienteDAO();
        boolean retorno = clienteDAO.remover(cliente);

        if(retorno){
            resultado = "clientes";
        }

        return resultado;
    }

    public Cliente getCliente() {
        return cliente;
    }

    public void setCliente(Cliente cliente) {
        this.cliente = cliente;
    }

    public DataModel<Cliente> getClientes() {
        clienteDAO = new ClienteDAO();
        List<Cliente> clienteList = clienteDAO.listar();
        clientes = new ListDataModel<Cliente>(clienteList);
        return clientes;
    }

    public void setClientes(DataModel<Cliente> clientes) {
        this.clientes = clientes;
    }

}

Para finalizar vamos criar nossas páginas JSF, com o botão direito em Páginas WebNovoOutro... selecione a categoria JavaServer Faces e o tipo de arquivo Página JSF e aí é só colocar o nome e finalizar. Faça esse procedimento para criar as seguintes páginas:
Obs.: apenas substitua o h:body de cada página criada pelos respectivos códigos abaixo.
novo.xhtml:
<h:body> 
        <h:form> 
            <h:panelGrid columns="2"> 
                <h:outputText value="Nome" /> 
                <h:inputText value="#{clienteBean.cliente.nome}" /> 
                <h:outputText value="Telefone" /> 
                <h:inputText value="#{clienteBean.cliente.telefone}" /> 
                <h:commandButton action="#{clienteBean.inserir}" value="Inserir" /> 
                <h:commandButton action="clientes" immediate="true" value="Cancelar" />
            </h:panelGrid> 
        </h:form> 
    </h:body>
Visualização:



alterar.xhtml:
<h:body> 
        <h:form> 
            <h:panelGrid columns="2"> 
                <h:outputText value="Nome" /> 
                <h:inputText value="#{clienteBean.cliente.nome}" /> 
                <h:outputText value="Telefone" /> 
                <h:inputText value="#{clienteBean.cliente.telefone}" /> 
                <h:commandButton action="#{clienteBean.alterar}" value="Alterar" /> 
                <h:commandButton action="clientes" immediate="true" value="Cancelar" />     
            </h:panelGrid> 
        </h:form> 
    </h:body>
Visualização:


remover.xhtml:
<h:body> 
        <h:form> 
            <h:outputText value="Deseja remover o cliente: #{clienteBean.cliente.nome} ?" /> 
            <h:panelGrid columns="2"> 
                <h:commandButton action="#{clienteBean.remover}" value="Remover" /> 
                <h:commandButton action="clientes" immediate="true" value="Cancelar" /> 
            </h:panelGrid> 
        </h:form> 
    </h:body>
Visualização:


clientes.xhtml:
<h:body> 
        <h:form> 
            <h:commandButton action="novo" actionlistener="#{clienteBean.novo}" value="Novo" /> 
            <h:dataTable value="#{clienteBean.clientes}" var="c"> 
                <h:column> 
                    <f:facet name="header"><h:outputText value="Nome" /></f:facet>
                    <h:outputText value="#{c.nome}" /> 
                </h:column> 
                <h:column> 
                    <f:facet name="header"><h:outputText value="Telefone" /></f:facet> 
                    <h:outputText value="#{c.telefone}" /> 
                </h:column> 
                <h:column> 
                    <f:facet name="header"><h:outputText value="Ações" /></f:facet> 
                    <h:commandButton action="alterar" actionListener="#{clienteBean.selecionar}" value="Alterar" /> 
                    <h:commandButton action="remover" actionListener="#{clienteBean.selecionar}" value="Remover" /> 
                </h:column> 
            </h:dataTable> 
        </h:form> 
    </h:body>
Visualização:



index.xhtml:
<h:body> 
        <h:form> 
            <h:commandButton action="clientes" value="Clientes" /> 
        </h:form> 
    </h:body>
Visualização:


erro.xhtml:
<h:body> 
        <h:form> 
            <h:outputText value="Ocorreu um erro, tente novamente:" /> 
            <h:commandButton action="index" value="Tentar novamente" /> 
        </h:form> 
    </h:body>
Visualização:



É isso aí... ;)

17 de fevereiro de 2011

JPA 2.0: Criando tabelas - Parte 1

Para trabalhar com o JPA, vamos usar a implementação padrão para a versão 2.0, o EclipseLink com o banco de dados MySQL. Antes de começar vamos preparar nosso banco de dados para receber nossas tabelas que serão geradas pelo JPA, então no banco de dados crie uma database com o nome de 5tads.
Depois de criar um projeto Java EE6 (Veja aqui), vamos começar a utilizar o JPA.
Inicialmente criei um projeto com o nome de TesteJPA, segue a estrutura final do projeto:


1. Habilitando o JPA
Para habilitar o JPA no projeto, basta clicar no projeto com o botão direito e ir em Novo - Outro... Escolha o tipo de arquivo da categoria Persistence do tipo Unidade de Persistência e vá para o próximo passo...



No próximo passo, é a hora de definir o provedor e o banco de dados:
O nome da unidade de persistência é gerada por padrão com o nome do projeto + PU (Persistence Unit)
O provedor de persistência é o EclipseLink(JPA 2.0)
E no combo de Fonte de dados, selecione a opção, Nova fonte de dados...


Ao selecionar a opção de criar uma nova fonte de dados, abrirá a seguinte janela, basta seguir a configuração das imagens:


Ao selecionar uma Nova conexão com o banco de dados... irá abrir a próxima janela, basta colocar os dados referentes aos seu banco de dados, lembre-se de selecionar o driver para o MySQL:


Ao clicar em OK ele fechará a janela acima, e na janela anterior a esta, aparecerá setado no combo a conexão que foi acabada de criar (imagem abaixo).


Basta dar um OK na janela acima, e voltamos a janela principal, onde estará setada a nossa nova fonte de dados, e clique em Finalizar.



2. Criando uma classe de entidade
Para organizar meu projeto, criei um pacote model dentro do pacote de códigos fonte. Para criar uma entidade, pode-se criar uma classe normal e fazer as anotações necessárias, porém o NetBeans, já dá a opção de criar uma entidade pré-anotada, para isso, clique com o botão direito no pacote model - Novo - Outro... Escolha a categoria Persistence e o tipo de arquivo Classe da entidade, como na imagem abaixo:


Ao clicar em Próximo defina um nome para a classe, nesse caso será Cliente, e deixe os valores padrões e finalize.


Temos uma entidade pré-anotada criada, ela já vem com o atributo id anotado porém, altere o GenerationType.AUTO para GenerationType.IDENTITY... Quando este valor está como AUTO, o JPA irá identificar qual será o banco para qual as tabelas serão geradas e a partir disso decide se auto-incremento será SEQUENCE ou IDENTITY, no caso do MySQL é o IDENTITY, mas deixando AUTO, o JPA acaba criando uma tabela SEQUENCE e tals, o que não é o padrão do MySQL, por isso é necessário alterar.
Para minha entidade Cliente adicionei um atributo nome, deixando minha classe na seguinte forma:
@Entity
public class Cliente implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(length=100)
    private String nome;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNome() {
        return nome;
    }

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

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Cliente)) {
            return false;
        }
        Cliente other = (Cliente) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "model.Cliente[id=" + id + "]";
    }

}
IMPORTANTE: É necessário adicionar todas as entidades criadas no persistence.xml, senão elas não serão gerenciadas pelo JPA.
Meu persistence.xml fica do seguinte formato:


em xml:
<persistence version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/persistence" xsi:schemalocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="TesteJPAPU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>5tads</jta-data-source>
        <class>model.Cliente</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>
            <property name="eclipselink.ddl-generation" value="create-tables" />
        </properties>
    </persistence-unit>
</persistence>

Feito isso nosso JPA já estará funcionando, mas ainda não criará nossa tabela Cliente de acordo com a nossa entidade, o que falta? É necessário fazer alguma operação no banco de dados via JPA, aí sim ele criará nossas tabelas!

3. Criando nosso DAO de acesso ao banco de dados
Inicialmente precisamos criar um pacote chamado dao, depois disso vamos criar uma nova classe java com o nome de ClienteDAO.java:
Nessa classe teremos um EntityManagerFactory e um EntityManager que é responsável por conectar ao JPA, veja que o EntityManagerFactory é criado pelo nossa unidade de persistência: TesteJPAPU. E nosso EntityManager é criado no construtor da classe pelo EntityManagerFactory: para entender direito esse parágrafo é necessária a leitura desse artigo do DevMedia: Veja aqui .
E a partir disso, criamos um método para listar os dados da tabela cliente (não irei entrar em detalhes sobre o método agora), no final nosso DAO ficará assim:
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import model.Cliente;

/**
 *
 * @author andii
 */
public class ClienteDAO {

    private EntityManagerFactory factory = Persistence.createEntityManagerFactory("TesteJPAPU");
    private EntityManager em;

    public ClienteDAO() {
        em = factory.createEntityManager();
    }


    public List< Cliente > listar() {
        List< Cliente > clientes = null;
        try {
            em.getTransaction().begin();
            Query query = em.createQuery("Select c from Cliente c");
            clientes = query.getResultList();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            em.close();
        }
        return clientes;
    }
}


4. Bean que acessará o ClienteDAO.java
Quase finalizando nosso projeto, vamos criar um pacote chamado controle para guardarmos os beans, e nele vamos criar uma classe java com o nome de ClienteBean.java, que terá os seguintes dados:
import dao.ClienteDAO;
import java.util.List;
import javax.inject.Named;
import javax.faces.bean.RequestScoped;
import model.Cliente;

/**
 *
 * @author andii
 */
@Named(value="clienteBean")
@RequestScoped
public class ClienteBean {

    private ClienteDAO clienteDAO = new ClienteDAO();
    private List< Cliente > clientes;

    public List< Cliente > getClientes() {
        clientes = clienteDAO.listar();
        return clientes;
    }

    public void setClientes(List< Cliente > clientes) {
        this.clientes = clientes;
    }

Nesse bean apenas iremos retornar uma lista de clientes para o JSF...

5. Página index.xhtml, acessando o bean
Falando em JSF, lembra que quando criamos o projeto o NetBeans já cria um arquivo index.xhtml? Pois bem, agora vamos alterar ele mesmo para mostrar os clientes trazidos pelo bean, que foi trazido pelo dao, que enfim foi trazido do banco de dados pelo JPA. Ficando assim nosso index.xhtml, o código abaixo é apenas a parte do h:body da página, o restante continua normal:
<h:body>
        <h:datatable value="#{clienteBean.clientes}" var="cliente">
            <h:column>
                <f:facet name="header"><h:outputtext value="ID" /></f:facet>
                <h:outputtext value="#{cliente.id}" />
            </h:column>
            <h:column>
                <f:facet name="header"><h:outputtext value="NOME" /></f:facet>
                <h:outputtext value="#{cliente.nome}" />
            </h:column>
        </h:datatable>
    </h:body>

Obs: inseri alguns clientes diretamente no banco para melhorar a visualização do resultado do nosso projeto, finalizando, o resultado no navegador é o seguinte:


Por hoje ficamos por aqui! ;)

4 de fevereiro de 2011

JPA 2.0: Java Persistence API

Java Persistence API ou JPA, é uma especificação padrão do Java para persistência de dados que deve ser implementada por frameworks que queiram seguir o padrão. A JPA lida com a forma como os dados relacionais são mapeado para objetos Java ("entidades persistentes"), a maneira que esses objetos são armazenados em um banco de dados relacional, para que eles possam ser acessados em um momento posterior, e a continuação da existência de um estado da entidade, mesmo após o aplicativo que usa o seu término. Além de simplificar o modelo de persistência da entidade, a Java Persistence API padroniza o mapeamento objeto-relacional.
Algumas implementações dessa especificação para a versão 2.0: EclipseLink e Hibernate.
Atualmente a versão da JPA é a 2.0, mais essa é mais voltada ao Java EE 6, é o que utilizaremos a partir de agora!

Tenha por exemplo a seguinte tabela Fornecedor (com codigo, nome e telefone) em SQL:
CREATE TABLE Fornecedor (
  codigo int(11) NOT NULL auto_increment,
  nome varchar(60) NOT NULL,
  telefone varchar(15) NULL,
  PRIMARY KEY  (codigo)
);

Agora analise a classe abaixo, veja que o mesmo tem os mesmos atributos: codigo, nome e telefone:
@Entity
public class Fornecedor implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(unique=true, nullable=false)
    private Long codigo;
 
    @Column(length=60, nullable=false)
    private String nome;
 
    @Column(length=15)
    private String telefone;

    //getters e setters
}

Essa classe é a representação do código SQL acima com JPA. Esses @Id, @Column, entre outros são chamados de anotações, eles são responsáveis por fazer o mapeamento dessa classe em código SQL. Em versões anteriores esses mapeamentos eram feitos por XML e não por anotações (conheço apenas a versão das anotações :D).

Para ficar mais claro vamos entender o que são essas anotações:
@Entity : essa anotação indica que esta é uma entidade gerenciada pelo JPA.
@Id: define quem é a primary key da tabela.
@GeneratedValue(strategy=GenerationType.IDENTITY): corresponde ao auto_increment do MySQL.
@Column(...): informa que este atributo é uma coluna da tabela Fornecedor.
private Long codigo;
Não vou entrar em detalhes nessa postagem quanto as propriedades do @Column, pois nas próximas postagens estaremos vendo mais a fundo esse mundo da JPA. Para hoje só quis mostrar como funciona o mapeamento da JPA mesmo.

Deixo como leitura obrigatória complementar a apostila feita pelo Ivan Salvadori: Veja aqui

Fontes:
http://www.oracle.com/technetwork/articles/javaee/jpa-137156.html