quinta-feira, 20 de setembro de 2012

JAVA + Spring + Netbeans 7.2 - Mysql + Swing Lesson 05

Dando seqüência nos posts de JAVA + Spring

Requisitos :
- Netbeans 7.2
- spring-3.2.0.M2

- Ter lido :

Posts Anteriores : 
JSNBTut - Base  que é uma preparação do ambiente para o desenvolvimento

Opcionais : 
JSNBTut - Lesson 01 - introdução ao Spring
JSNBTut - Lesson 02 - introdução ao gerenciamento de dependências no  Spring
Obrigatório:
JSNBTut - Lesson 03 - acessando banco de dados Mysql com beans e injeção de dependências
JSNBTut - Lesson 04 - outro jeito rápido de utilizar o Spring e Mysql sem utilizar Arquivos XML.
Para baixar o projeto como está na versão 2


Este é o 5º da série , o objetivo deste post é :
- melhorar o exemplo da lição 04 , implementando a configuração da conexão em um arquivo XML
- implementar funcionalidades GUI (gráficas,telas) .
- ver 2 jeitos diferentes de trabalhar com JTable

1) Na pasta onde vc baixou o arquivo SpringLesson04-v2.zip , e decompactou, vamos :

I) Duplicar essa pasta e alterar o nome para final v3 ficando SpringLesson04-v3;

II) Abrir e renomear o projeto no NB como na lição anterior e o projeto deve estar assim :
Figura 01 - Abrindo o projeto
Depois de Renomear o projeto
Figura 02 - Arquivos do projeto


2) Vamos fazer alguns acertos
I) Refatorar o package onde está a classe Main
Clique com o botão direito no package springlesson04 e escolha Refactor >> Rename , altere para
springlesson04.main
Figura 03 - Refatorando 

II) Clique com o botão direito no projeto , escolha properties
Na opção Main Class, apague o q estiver ali , que é a MainClass, e clique em OK

III) Clique com o botão direito na classe MainClass, escolha  Refactor>> Rename e dê o nome de Main

IV) II) Clique com o botão direito no projeto , escolha properties
Na opção Main Class, selecione a  Main.java, e clique em OK

Figura 04 - Definindo o metodo main do programa

3) Lembra do nosso bean-definitions.xml do exemplo 3? usaremos ele novamente aqui , com algumas modificações, mas primeiro veremos o acesso  de 2 jeitos diferentes sem utilizá-lo :

Clique com o botão direito no projeto e escolha new >> XML Document; dê o nome de beans-definitions conforme a figura  abaixo
Figura 05 - Criando o arquivo XML para o Spring

O código desse arquivo fica assim:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="dataSource" name="dataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource">
        <constructor-arg index = "0" value = "com.mysql.jdbc.Driver"></constructor-arg>
        <constructor-arg index = "1" value = "jdbc:mysql://ns1/springlessons"></constructor-arg>
        <constructor-arg index = "2" value = "springlessons"></constructor-arg> 
        <constructor-arg index = "3" value = "DHADdSXcDF29WGXy"></constructor-arg>
        <constructor-arg index = "4" value = "true"></constructor-arg>
    </bean>
    <bean name="jdbcTemplate" id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <bean name="contatoDao" id="ContatoDao" class="springlesson04.dao.ContatoDAO">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
</beans>

4) Vamos criar uma Tela que é  uma classe que extende javax.swing.JFrame,

I) Clique com o botão direito no projeto New>> JFrame Form
Figura 06 - Novo JFrame

Figura 07 - Novo JFrame: class name =frameListaContatos package=springlesson04.view.contato

Observe que o NB apareceu em uma perspectiva de Design com duas abas que ainda não tinham aparecido em nossas lições: a Janela Palette e a de Propriedades
Você pode arrastar os itens do Palette para o Frame, e ao selecioná-los no Frame a janela Properties mostra todas as propriedades do objeto ou Componente

Figura 08 - Apresentando a paleta de objetos 

a estrutura do projeto deve estar assim:
Figura 09 - Situação do projeto


II) Agora arraste um Table e um Button p/ a Tela de maneira a ficar assim :
Figura 10 - Acessando as propriedades de um objeto GUI

Existem várias maneiras de trazer os dados nessa Grade, o que ilustrarei é apenas um exemplo.


A) Vamos Utilizar o NB p/ customizar essa Table:
Selecione a Tabela na Form e na aba Properties clique em Model ,
Figura 11 - customizando o TableModel



vamos deixá-la assim :

Figura 12 -  TableModel customizado 


B) Examine o código gerado : Clique no Botao Source em cima do form
Figura 13 - Altere para o modo Source

C) localize no código esse trecho: e clique no sinal de mais
Figura 14 - Clique no sinal de mais p/ expandir esse trecho de código gerado e protegido pelo NB 

D) Veja como é definido o modelo que preenche a tabela : através de um objeto do tipo javax.swing.table.DefaultTableModel
Figura 15 - Veja o objeto DefaultTableModel criado


3) Se quisermos apenas carregar os registros do banco na grade o jeito mais simples é o seguinte
Solução 1:  (sem usar o XML)
A - Criamos um objeto do tipo DefaultTableModel de nome modelo e aplicamos a jTable1
B - Criamos uma função carregaTabela que chama o Controller
C - Criamos um objeto do tipo Object que conterá os dados do Contato e adicionamos ao modelo
D - ReDefinimos o modelo da Tabela
E - Mandamos isso rodar ao carregar o Frame
OBS: Centenas de exemplos na internet utilizam o objeto Vector p/ popular Jtable. NÃO USE ISSO. ESTÁ DEPRECIADO, USE OBJECT.
Vamos ver como fica :

Logo abaixo da linha escrito  // End of variables declaration
Figura 16 - Modo Source
A) Adicione o Modelo
public final DefaultTableModel modelo =new javax.swing.table.DefaultTableModel(
            new Object [][] {},
            new String [] {
                "ID", "NOME", "TELEFONE"
            }) 
            {
            boolean[] canEdit = new boolean [] {
                false, false, false
            };
            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        };

B,C,D) Criar a função carregaTabela()
    private void carregaTabela(){
        ContatoController cc = new ContatoController(true);
        List<Contato> listaContatos = cc.getContatos();
        for (Contato C:listaContatos){
            Object[] O = new Object[3];
            O[0]=C.getId();
            O[1]=C.getNome();
            O[2]=C.getTelefone();
            modelo.addRow(O);
        }
        jTable1.setModel(modelo);
    }


D) Já está sendo feitona função, mas vamos limpar o modelo que está feito automático no NB
Volte ao modo Design e selecione a Tabela na Form e na aba Properties clique em Model ,
Figura 17 - customizando o TableModel - Vamos adicionar o objeto modelo que criamos do tipo javax.swing.table.DefaultTableModel



vamos deixá-la assim :

Figura 18 - usando o método setModel passando nosso modelo  da figura 17 

Agora nas propriedades ficou assim :
Figura 19 - Aba propriedades , veja a linha model

E) carregar a função :
inclua a chamada para a função carregaTabela dentro do construtor da classe

Figura 20 - Chamando o método criado carregaTabela no construtor da classe

Visão Geral do Arquivo :
Figura 21 - Visão geral da classe frameListaContato até esse ponto. 

4) Clique com o botão direito nesse Arquivo pela aba Projects e escolha Run File

Figura 22 - Como queremos testar apenas esse frame do programa, Execute esse arquivo dentro do NB


Acerte o título do Frame , selecionando o Frame no Modo Design e na aba Propriedades modifique o atributo title para "Teste Spring"

Figura 23 - Acerte o title do form


o resultado deve ser esse :
Uma Janela com os dados da tabela contato
Figura 24 - Titulo do form
Como iremos carregar esses dados de diferentes jeitos, vamos comparar os resultados de análises de performance utilizando a ferramenta Profile do NB

Figura 25 - Introdução ao recurso Profile

Se for a 1ª vez que vc usa esse recurso , o NB pedirá para você configurar o calibrador, siga o Next->Next->Next e habilite o Profile.

Figura 26 - 1ª vez que executa o Profile File ? 

Após configurar o calibrador , escolha uma opção , e clique em Run
Figura 27 - Escolha o tipo de analise , Monitor, CPU ou Memory

Coletando os resultados :
Figura 28 - Durante o Profile , clique em Take Snapshot p/ salvar o momento de execução



Examine os resultados , faça com os 2 tests com CPU e com Memory  : e após finalizar o programa colete e salve  os resultados , eles serão importantes p/ testarmos com outras implementações

Figura 29 - Se quiser comparar depois , salve os resultados

Algumas Telas de Analise
Figura 30 - Analise de CPU - Classes em uso

Figura 31 - Veja nossa classe Main

Figura 32 - Na opção view ao lado esquerdo ,  veja as duas : VM Telemetry e a  Threads
obs : os snapshots sao arquivos com extensão .nps em uma pasta seuprojeto/private/profiler/
Figura 33 - Arquivos dos Snapshots
Esse foi o resultado da Solução 1

5) Solução 2:  (sem usar o XML)

A - Criamos uma Classe que implementa a classe TableModel e que recebe como parâmetro no construtor uma Lista de Contatos, reimplementado seu métodos
B - usamos o método setModel da jTable passando como modelo nosso TableModel

A) Vamos criar a classe ContatoTableModel no package springlesson04.model
I) Nova Classe
Figura 34 - Nova Classe Java

Figura 35 class name=ContatoTableModel  package=..model

II) Após o nome da classe adicione implements TableModel e deixe o NB acertar o import. 
Figura 36 -  o NB mostras os imports possíveis 

III) E em seguinda escolha a opção Implement all Abstract Methods
Figura 37 - implementando os metodos necessários
E a classe deve ter ficado assim:
package springlesson04.model;

import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;


public class ContatoTableModel implements TableModel{

    @Override
    public int getRowCount() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public int getColumnCount() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public String getColumnName(int i) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Class<?> getColumnClass(int i) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean isCellEditable(int i, int i1) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public Object getValueAt(int i, int i1) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void setValueAt(Object o, int i, int i1) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void addTableModelListener(TableModelListener tl) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void removeTableModelListener(TableModelListener tl) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
}

IV) Vamos editar essa classe.Ela deve ficar assim:

package springlesson04.model;

import java.util.List;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;


public class ContatoTableModel implements TableModel {
    List<Contato> lista;

    public ContatoTableModel(List<Contato> lista) {
    this.lista = lista;
    }
    

    @Override
    public int getRowCount() {
        return lista.size();
    }

    @Override
    public int getColumnCount() {
        return 3;
    }

    @Override
    public String getColumnName(int columnIndex) {
        String retorno =null;
        switch(columnIndex){
            case 0: retorno = "Id"; break;
            case 1: retorno = "Nome"; break;
            case 2: retorno = "Telefone"; break;
        }
        return retorno;
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        Class retorno =null;
        switch(columnIndex){
            case 0: retorno = Integer.class; break;
            case 1: retorno = String.class; break;
            case 2: retorno = String.class; break;
        }
        return retorno;

    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false; // p/ todos 
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Contato C = lista.get(rowIndex);
        Object retorno = null;
                switch(columnIndex){
            case 0: retorno = C.getId(); break;
            case 1: retorno = C.getNome(); break;
            case 2: retorno = C.getTelefone(); break;
        }
        return retorno;
    }

    @Override
    public void setValueAt(Object o, int i, int i1) {
//        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void addTableModelListener(TableModelListener tl) {
//        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void removeTableModelListener(TableModelListener tl) {
//        throw new UnsupportedOperationException("Not supported yet.");
    }
    
}


V) E em nosso método main do frameListaContatos vamos simplificá-lo :
No modo Design , selecione a tabela e clique na aba propriedades em model e vamos limpá-la:
Figura 38 - Limpando a Tabela 

VI) E no código (modo Source)
Não precisamos mais do DefaultTableModel modelo e vamos alterar essa função carregaTabela que já está no construtor do frame:
essa função fica assim , comente ou remova o trecho do modelo e da função conforme a imagem abaixo:
    private void carregaTabela(){
        ContatoController cc = new ContatoController(true);
        List<Contato> listaContatos = cc.getContatos();
        ContatoTableModel tableModel = new ContatoTableModel(listaContatos);
        jTable1.setModel(tableModel);
    }

o resultado deve ser esse :
Uma Janela com os dados da tabela contato

Figura 39 - Teste do programa 

Sep 20, 2012 3:12:17 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
Sep 20, 2012 3:12:18 PM org.springframework.jdbc.datasource.SingleConnectionDataSource initConnection
INFO: Established shared JDBC Connection: com.mysql.jdbc.JDBC4Connection@b955970

E assim vimos 2 jeitos diferentes de carregar tabelas usando um DefaultTableModel e criando nosso TableModel que implementa essa classe.

Download do projeto NB
SpringLesson04-v3.zip


Ops, e p/ usar a  a conexão do arquivo XML ?
Precisamos usar o ApplicationContext e o ClassPathXmlApplicationContext do Spring,  lembra ?
P/ facilitar a comparação entre as técnicas, vamos duplicar o projeto  para SpringLesson04-v4 e alterar o v4. Para isso :
Solução 3:  (usando o XML)
I) Crie um novo projeto Java e de o nome de SpringLesson04-v4
Figura 40 - Alterando o Projeto para + uma versão 

II) Selecione Todos os packages do v3 e copiar 
Figura 41 - Alterando o Projeto para + uma versão - copiando
III) Clique em Source Packages no projeto v4 e colar
Figura 42 - Alterando o Projeto para + uma versão - Colando

 IV)Adicione as libs necessárias :
Figura 43 - Adicionando as Libs 

V) Selecione o arquivo frameListaContato.java, botão direito e Run File, tem q executar igual o projeto v3

Figura 44 - Teste o Programa na nova versão

OBS : prefiro duplicar a pasta pelo gerenciador de Arquivos do SO. Ae não preciso incluir as libs d e novo , por que já estão definidos nos arquivo do projeto :
Figura 45 - Visão Files (ctrl + 2 | command + 2) do projeto de nossa próxima lição


6) Vamos alterar apenas a função carregaTabela p/ o seguinte :
Não precisamos mais do controller que criamos, pois estamos utilizando o Spring

    private void carregaTabela(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-definitions.xml");
        ContatoDAO dao = (ContatoDAO) ctx.getBean("contatoDao");
        ContatoTableModel tableModel = new ContatoTableModel(dao.listar());
        jTable1.setModel(tableModel);
    }

Salve e ... Run File

o resultado deve ser a mesma tela porém no console no NB vc verá que está carregando mais coisa :
Figura 46 - resultado final

Sep 20, 2012 2:56:46 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3c2d7440: startup date [Thu Sep 20 14:56:46 BRT 2012]; root of context hierarchy
Sep 20, 2012 2:56:46 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans-definitions.xml]
Sep 20, 2012 2:56:47 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@7badb7b8: defining beans [dataSource,jdbcTemplate,ContatoDao]; root of factory hierarchy
Sep 20, 2012 2:56:47 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
Sep 20, 2012 2:56:47 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
Sep 20, 2012 2:56:48 PM org.springframework.jdbc.datasource.SingleConnectionDataSource initConnection
INFO: Established shared JDBC Connection: com.mysql.jdbc.JDBC4Connection@75c45731

Download do projeto NB
SpringLesson04-v4.zip

Experimente executar o Profile e compare os resultados.


E assim concluímos nossa lição 05.

Resumo : o que foi feito ?
Sol.1
- Criamos um controller simples ;
- Criamos um arquivo XML que foi usado na solução 3
- Conhecemos o objeto JFrame, jTable e button (não usei o botao, pois por enquanto basta fechar o formulario)
- Conhecemos a classe DefaultTableModel, criamos um modelo e demos carga usando Object

Sol.2
- Criamos uma classe que implementa a classe javax.swing.table.TableModel e utilizamos o @Override p/ reescrever alguns métodos

Sol.3

- Utilizamos o Spring e injeção de dependências

- Pudemos comparar os diferentes jeitos de acessar os mesmos dados
- Vimos o recurso de Profile do NB que nos permite analizar o comportamento de nossa aplicação.

Na próxima lição Lesson 06 implementaremos um CRUD e organizaremos esse projeto exemplo, deixando apenas as libs necessárias.

Dúvidas, Contribuições, Sugestões? Poste..
Grato,
Até a próxima.

Nenhum comentário: